diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 1548abbe3..0da0acb4f 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 ${CRYPTOPP_LS} serpent lll evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmface devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f413532b7..cd6cad11a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -149,7 +152,9 @@ 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 WebThreeStubServer(m_qwebConnector, *web3(), keysAsVector(m_myKeys))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -158,7 +163,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(); @@ -868,18 +873,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 +951,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 +991,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 +1149,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 << "
"; @@ -1251,31 +1256,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 << ""; + 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); @@ -1564,10 +1569,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); + } + 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 +1626,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); @@ -1786,14 +1810,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(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 0ea072a93..e62afb497 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -255,7 +255,7 @@ private: QString m_logHistory; bool m_logChanged = true; - QWebThreeConnector m_qwebConnector; + QWebThreeConnector* m_qwebConnector; std::unique_ptr m_server; QWebThree* m_qweb = nullptr; }; diff --git a/cmake/EthDependenciesDeprecated.cmake b/cmake/EthDependenciesDeprecated.cmake index d1c51f6c4..17b937c5c 100644 --- a/cmake/EthDependenciesDeprecated.cmake +++ b/cmake/EthDependenciesDeprecated.cmake @@ -128,6 +128,7 @@ else() find_path( JSONRPC_ID jsonrpc/rpc.h /usr/include /usr/local/include + ../libjson-rpc-cpp/src ) if ( JSONRPC_ID ) message(STATUS "Found jsonrpc headers") @@ -137,6 +138,7 @@ else() /usr/local/lib /opt/local/lib /usr/lib/*/ + ../libjson-rpc-cpp/build/out ) if ( JSONRPC_LS ) message(STATUS "Found jsonrpc library: ${JSONRPC_LS}") 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/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/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b4623ba24..d82098655 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -14,53 +14,33 @@ 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 "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)); + uniform_int_distribution d(0, 255); for (int i = 0; i < 100; ++i) { @@ -78,24 +58,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 +94,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 6070b651b..dc5d6a610 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 5086e3203..af6d0e65e 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -18,54 +18,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" -#include -#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 +86,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 a8df19be8..2a28f99ed 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,29 +52,29 @@ 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) @@ -84,9 +84,9 @@ bool Executive::setup(bytesConstRef _rlp) } 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; + clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); BOOST_THROW_EXCEPTION(BlockGasLimitReached()); } @@ -94,21 +94,21 @@ bool Executive::setup(bytesConstRef _rlp) 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/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 6fc313c15..2e52187c6 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -522,7 +522,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; @@ -793,7 +793,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; @@ -1127,10 +1128,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 @@ -1155,10 +1156,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()); @@ -1215,32 +1216,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 @@ -1284,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) { @@ -1320,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; } @@ -1383,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; @@ -1412,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 ef3c3a36f..ae12080ae 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -43,7 +43,7 @@ namespace dev { -namespace test { class FakeExtVM; class FakeState; } +namespace test { class ImportTest; } namespace eth { @@ -68,8 +68,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/ExtVMFace.h b/libevm/ExtVMFace.h index 1b1ae7455..62132a462 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -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; } }; diff --git a/libevm/VM.h b/libevm/VM.h index 252628b75..6fe358bc0 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -45,7 +45,7 @@ public: virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - 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 curPC() const { return m_curPC; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 02290357d..76dc8a219 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -32,7 +32,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. diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index b3ed4fb74..fadb5ab14 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -32,6 +32,8 @@ namespace dev namespace eth { +struct InvalidOpcode: virtual Exception {}; + /// Virtual machine bytecode instruction. enum class Instruction: uint8_t { @@ -176,6 +178,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 { diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index f60dbe783..0c89587e9 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -29,7 +29,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) case ReturnCode::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas()); case ReturnCode::StackTooSmall: - BOOST_THROW_EXCEPTION(StackTooSmall(1, 0)); + BOOST_THROW_EXCEPTION(StackTooSmall()); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); default: diff --git a/liblll/Assembly.h b/liblll/Assembly.h index 8ab3062dc..e39f1899b 100644 --- a/liblll/Assembly.h +++ b/liblll/Assembly.h @@ -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/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..026aef975 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,7 +279,7 @@ void IfStatement::checkTypeRequirements() void WhileStatement::checkTypeRequirements() { - expectType(*m_condition, BoolType()); + m_condition->expectType(BoolType()); m_body->checkTypeRequirements(); } @@ -293,13 +293,16 @@ 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 +314,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 @@ -326,20 +329,36 @@ 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(); + if (!getType()->isImplicitlyConvertibleTo(_expectedType)) + BOOST_THROW_EXCEPTION(createTypeError("Type not implicitly convertible to expected type.")); + //@todo provide more information to the exception } 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.")); @@ -359,7 +378,6 @@ void BinaryOperation::checkTypeRequirements() 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.")); @@ -375,25 +393,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 +417,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,19 +431,21 @@ 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); + if (asserts(m_referencedDeclaration)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved.")); + //@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? @@ -441,9 +458,9 @@ void Identifier::checkTypeRequirements() 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 +486,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() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 4dc44e29b..f42ff47d0 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -152,7 +152,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 +175,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 +243,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 +314,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 +346,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 +377,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; @@ -398,6 +410,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 +439,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 +470,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 +530,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,7 +555,10 @@ 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; @@ -530,6 +586,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 +675,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..f425bba48 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,8 +16,8 @@ file(GLOB HEADERS "*.h") include_directories(..) -target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} evmface) +# @todo we only depend on Assembly, not on all of lll +target_link_libraries(${EXECUTABLE} evmface devcore lll) 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..654eceadb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -17,387 +17,291 @@ /** * @author Christian * @date 2014 - * Solidity AST to EVM bytecode compiler. + * Solidity compiler. */ -#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) { - assert(m_labelPositions.find(_label) == m_labelPositions.end()); - m_labelPositions[_label] = _position; + Compiler compiler; + compiler.compileContract(_contract); + return compiler.m_context.getAssembledBytecode(); } -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 + //@todo register state variables + + for (ASTPointer const& function: _contract.getDefinedFunctions()) + m_context.addFunction(*function); + + 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()); + // 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 @todo it could be that the optimizer destroys this + m_context << jumpTableStart; + for (pair> const& f: publicFunctions) + m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST; + + m_context << returnTag << eth::Instruction::STOP; - // resolve label references - for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos) + 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 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 + unsigned numBytes = parameters[i]->getType()->getCalldataEncodedSize(); + if (numBytes == 0) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(parameters[i]->getLocation()) + << errinfo_comment("Type 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 (asserts(!m_continueTags.empty())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"continue\".")); + 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 (asserts(!m_breakTags.empty())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"break\".")); + 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::cleanHigherOrderBitsIfNeeded(*expression->getType(), *firstVariable.getType()); + int stackPosition = m_context.getStackPositionOfVariable(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::cleanHigherOrderBitsIfNeeded(*expression->getType(), + *_variableDefinition.getDeclaration().getType()); + int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration()); + 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..4e4d90d45 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() { return m_context.getAssembledBytecode(); } + 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); 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..99cf090e0 --- /dev/null +++ b/libsolidity/CompilerContext.cpp @@ -0,0 +1,61 @@ +/* + 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::initializeLocalVariables(unsigned _numVariables) +{ + if (_numVariables > 0) + { + *this << u256(0); + for (unsigned i = 1; i < _numVariables; ++i) + *this << eth::Instruction::DUP1; + m_asm.adjustDeposit(-_numVariables); + } +} + +int CompilerContext::getStackPositionOfVariable(Declaration const& _declaration) +{ + 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 end(m_localVariables) - res - 1 + m_asm.deposit(); +} + +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(); +} + +} +} diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h new file mode 100644 index 000000000..46c4c72ab --- /dev/null +++ b/libsolidity/CompilerContext.h @@ -0,0 +1,89 @@ +/* + 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() {} + + void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } + void initializeLocalVariables(unsigned _numVariables); + void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } + /// Returns the distance of the given local variable from the top of the stack. + int getStackPositionOfVariable(Declaration const& _declaration); + + void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); } + eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; + + void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + + /// 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() const { return m_asm.assemble(); } +private: + eth::Assembly m_asm; + + /// 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..bbd693ae5 --- /dev/null +++ b/libsolidity/CompilerStack.cpp @@ -0,0 +1,49 @@ +/* + 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) +{ + if (!_scanner) + _scanner = make_shared(); + _scanner->reset(CharStream(_sourceCode)); + + ASTPointer contract = Parser().parse(_scanner); + NameAndTypeResolver().resolveNamesAndTypes(*contract); + return Compiler::compile(*contract); +} + +} +} diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h new file mode 100644 index 000000000..9f3f81c04 --- /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()); +}; + +} +} 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..d23579b11 --- /dev/null +++ b/libsolidity/ExpressionCompiler.cpp @@ -0,0 +1,410 @@ +/* + 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); +} + +bool ExpressionCompiler::visit(Assignment& _assignment) +{ + m_currentLValue = nullptr; + + Expression& rightHandSide = _assignment.getRightHandSide(); + rightHandSide.accept(*this); + Type const& resultType = *_assignment.getType(); + cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); + _assignment.getLeftHandSide().accept(*this); + + Token::Value op = _assignment.getAssignmentOperator(); + if (op != Token::ASSIGN) + { + // compound assignment + m_context << eth::Instruction::SWAP1; + appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); + } + else + m_context << eth::Instruction::POP; //@todo do not retrieve the value in the first place + + 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 + if (_unaryOperation.isPrefixOperation()) + storeInLValue(_unaryOperation); + else + moveToLValue(_unaryOperation); + 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& resultType = *_binaryOperation.getType(); + Token::Value const op = _binaryOperation.getOperator(); + + if (op == Token::AND || op == Token::OR) + { + // special case: short-circuiting + appendAndOrOperatorCode(_binaryOperation); + } + else if (Token::isCompareOp(op)) + { + leftExpression.accept(*this); + rightExpression.accept(*this); + + // the types to compare have to be the same, but the resulting type is always bool + if (asserts(*leftExpression.getType() == *rightExpression.getType())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + appendCompareOperatorCode(op, *leftExpression.getType()); + } + else + { + leftExpression.accept(*this); + cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType); + rightExpression.accept(*this); + cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); + appendOrdinaryBinaryOperatorCode(op, resultType); + } + + // 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); + cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); + } + else + { + // Calling convention: Caller pushes return address and arguments + // Callee removes them and pushes return values + m_currentLValue = nullptr; + _functionCall.getExpression().accept(*this); + FunctionDefinition const& function = dynamic_cast(*m_currentLValue); + + 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); + cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(), + *function.getParameters()[i]->getType()); + } + + m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); + 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) +{ + m_currentLValue = _identifier.getReferencedDeclaration(); + switch (_identifier.getType()->getCategory()) + { + case Type::Category::BOOL: + case Type::Category::INTEGER: + case Type::Category::REAL: + { + //@todo we also have to check where to retrieve them from once we add storage variables + unsigned stackPos = stackPositionOfLValue(); + if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation()) + << errinfo_comment("Stack too deep.")); + m_context << eth::dupInstruction(stackPos + 1); + break; + } + default: + break; + } +} + +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::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. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); + } +} + +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(); + + // 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: + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) + << eth::Instruction::ISZERO; + break; + case Token::LTE: + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) + << eth::Instruction::ISZERO; + break; + case Token::GT: + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + break; + case Token::LT: + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + 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::SWAP1 << eth::Instruction::SUB; + break; + case Token::MUL: + m_context << eth::Instruction::MUL; + break; + case Token::DIV: + m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + break; + case Token::MOD: + m_context << eth::Instruction::SWAP1 << (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::storeInLValue(Expression const& _expression) +{ + moveToLValue(_expression); + unsigned stackPos = stackPositionOfLValue(); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + m_context << eth::dupInstruction(stackPos + 1); +} + +void ExpressionCompiler::moveToLValue(Expression const& _expression) +{ + unsigned stackPos = stackPositionOfLValue(); + 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; +} + +unsigned ExpressionCompiler::stackPositionOfLValue() const +{ + if (asserts(m_currentLValue)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request.")); + return m_context.getStackPositionOfVariable(*m_currentLValue); +} + +} +} diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h new file mode 100644 index 000000000..a930723cc --- /dev/null +++ b/libsolidity/ExpressionCompiler.h @@ -0,0 +1,79 @@ +/* + 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 + +namespace dev { +namespace solidity { + +class CompilerContext; // 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 cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); + +private: + ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), 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); + /// @} + + /// Stores the value on top of the stack in the current lvalue and copies that value to the + /// top of the stack again + void storeInLValue(Expression const& _expression); + /// The same as storeInLValue but do not again retrieve the value to the top of the stack. + void moveToLValue(Expression const& _expression); + /// Returns the position of @a m_currentLValue in the stack, where 0 is the top of the stack. + unsigned stackPositionOfLValue() const; + + Declaration* 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..c36820317 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()) { @@ -423,15 +417,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; } @@ -473,7 +463,9 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(bool _periodSeen) { - assert(IsDecimalDigit(m_char)); // the first digit of the number or the fraction + // the first digit of the number or the fraction + if (asserts(IsDecimalDigit(m_char))) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit.")); enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; LiteralScope literal(this); if (_periodSeen) @@ -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(); @@ -611,7 +604,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 +633,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 +656,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..537c2434e 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(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index c54f387c7..0fb9b670f 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 */ \ @@ -224,7 +224,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 +250,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 +267,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 +276,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..a4d70e3a0 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -20,7 +20,6 @@ * Solidity data types */ -#include #include #include #include @@ -33,6 +32,9 @@ namespace solidity std::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; @@ -52,7 +54,8 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) else if (_typeToken == Token::BOOL) return std::make_shared(); else - assert(false); // @todo add other tyes + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + + std::string(Token::toString(_typeToken)) + " to type.")); return std::shared_ptr(); } @@ -63,7 +66,7 @@ std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _ std::shared_ptr Type::fromMapping(Mapping const&) { - assert(false); //@todo not yet implemented + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); return std::shared_ptr(); } @@ -94,7 +97,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): { if (isAddress()) _bits = 160; - assert(_bits > 0 && _bits <= 256 && _bits % 8 == 0); + if (asserts(_bits > 0 && _bits <= 256 && _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 @@ -159,14 +163,12 @@ std::string IntegerType::toString() const 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); + //@todo check that the number is not too large + //@todo does this work for signed numbers? + return u256(value); } bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -182,14 +184,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 diff --git a/libsolidity/Types.h b/libsolidity/Types.h index c9f6da574..4493b8037 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -70,8 +71,16 @@ 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; } + 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.")); + } }; /** @@ -97,8 +106,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 +138,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; }; /** diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e7eb62e04..89d45f4e0 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -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,48 @@ 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; @@ -252,13 +312,6 @@ 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 ret(Json::arrayValue); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index b18faf95a..33163b75e 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -56,13 +56,14 @@ 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); @@ -109,6 +110,7 @@ public: 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..66b9ff77d 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -13,7 +13,6 @@ 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); @@ -59,11 +58,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServeraccount(); - } - inline virtual void accountsI(const Json::Value& request, Json::Value& response) { response = this->accounts(); @@ -275,7 +269,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer #include #include +#include #include #include "Common.h" diff --git a/neth/main.cpp b/neth/main.cpp index 4e3a0f40a..06e22f963 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -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/solc/main.cpp b/solc/main.cpp index 8367e3d44..04fee2905 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -34,65 +34,33 @@ #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 + << " -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; for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; + string arg = argv[i]; if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") @@ -100,13 +68,13 @@ int main(int argc, char** argv) 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 +82,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(); } 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/test/CMakeLists.txt b/test/CMakeLists.txt index e6c10cd1b..951db2c99 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,7 +8,7 @@ link_directories(../libevm) 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) target_link_libraries(testeth ethcore) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 03e679343..ca46c2ca2 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,296 @@ 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 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..622b83ac4 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; + bytes code; + +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(); + +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/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/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..69d331339 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(0x20 + shift), // ret address + byte(Instruction::PUSH1), 0x1, + byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x3, + 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..b28b8499a --- /dev/null +++ b/test/solidityEndToEndTest.cpp @@ -0,0 +1,229 @@ + +/* + 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 compileAndRun(std::string const& _sourceCode) + { + bytes code = dev::solidity::CompilerStack::compile(_sourceCode); + sendMessage(code, true); + return m_output; + } + + bytes callFunction(byte _index, bytes const& _data) + { + sendMessage(bytes(1, _index) + _data, false); + return m_output; + } + + bytes callFunction(byte _index, u256 const& _argument1) + { + callFunction(_index, toBigEndian(_argument1)); + return m_output; + } + +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) + : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data); + 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_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().toBytes(); + } + + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 1000000; + bytes m_output; +}; + +BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a) returns(uint d) { return a * 7; }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + u256 a = 0x200030004; + bytes result = framework.callFunction(0, a); + BOOST_CHECK(result == toBigEndian(a * 7)); +} + +BOOST_AUTO_TEST_CASE(empty_contract) +{ + char const* sourceCode = "contract test {\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); +} + +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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); +} + +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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1))); +} + +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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) + == toBigEndian(u256(0x121121))); +} + +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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.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"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8))); +} + +//@todo test smaller types + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces + diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp new file mode 100644 index 000000000..561cc3bda --- /dev/null +++ b/test/solidityExpressionCompiler.cpp @@ -0,0 +1,352 @@ + +/* + 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::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::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 = (10 + 8 >= 4 || 2 != 9) != true; }" + "}\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::ISZERO), // 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::POP), + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0x9, + 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 = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" + "}\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()); +} + +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), 0x1, + 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()); +} + +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::DUP1), + byte(eth::Instruction::DUP3), + byte(eth::Instruction::SWAP1), + byte(eth::Instruction::ADD), + // Stack here: a b a+b + byte(eth::Instruction::SWAP2), + byte(eth::Instruction::POP), + byte(eth::Instruction::DUP2), + // Stack here: a+b b a+b + byte(eth::Instruction::PUSH1), 0x2, + 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), 0x0a, + byte(eth::Instruction::DUP3), + byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::ADD), + // Stack here: a b (a+1) + byte(eth::Instruction::DUP3), + byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::JUMP), + byte(eth::Instruction::JUMPDEST), + // Stack here: a b g(a+1, b) + byte(eth::Instruction::PUSH1), 0x02, + byte(eth::Instruction::MUL), + // Stack here: a b g(a+1, b)*2 + byte(eth::Instruction::DUP3), + byte(eth::Instruction::SWAP1), + 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_SUITE_END() + +} +} +} // end namespaces + 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/state.cpp b/test/state.cpp index b0f279bac..9c0a7188b 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -15,81 +15,121 @@ 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) +{ + cout << "start state test\n"; + 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); + + if (_fillin) + { + importer.code = importer.m_statePre.code(importer.m_environment.myAddress); + importer.m_environment.code = &importer.code; + } + + 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; - - // Mine to get some ether and set in stone. - s.commitToMine(bc); - while (!s.mine(100).completed) {} - s.completeMine(); - bc.attemptImport(s.blockData(), stateDB); +} +} }// Namespace Close - cout << bc; +BOOST_AUTO_TEST_SUITE(StateTests) - s.sync(bc); +BOOST_AUTO_TEST_CASE(stExample) +{ + dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests); +} - cout << s; +BOOST_AUTO_TEST_CASE(stSystemOperationsTest) +{ + dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); +} - return 0; +BOOST_AUTO_TEST_CASE(tmp) +{ + int currentVerbosity = g_logVerbosity; + g_logVerbosity = 12; + dev::test::executeTests("tmp", "/StateTests", dev::test::doStateTests); + g_logVerbosity = currentVerbosity; } +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/tmpFiller.json b/test/tmpFiller.json new file mode 100644 index 000000000..bd27b8907 --- /dev/null +++ b/test/tmpFiller.json @@ -0,0 +1,44 @@ +{ + "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" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + } + +} 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 8a16dea8b..fe37d67c3 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -21,10 +21,7 @@ */ #include -#include #include "vm.h" -//#define FILL_TESTS - using namespace std; using namespace json_spirit; using namespace dev; @@ -36,136 +33,20 @@ FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& 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 +79,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 +158,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); } } @@ -357,26 +196,14 @@ void FakeExtVM::importExec(mObject& _o) 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 + + thisTxCode = importCode(_o); + if (_o["code"].type() != str_type && _o["code"].type() != array_type) code.reset(); 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 +213,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 +231,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 +252,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,75 +268,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. - auto vmObj = VMFace::create(getVMKind(), *_gas); - auto& vm = *vmObj; - 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()) { @@ -541,7 +289,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; dev::test::FakeExtVM fev; - fev.setVMKind(vmKind); fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -556,7 +303,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.code = &fev.thisTxCode; } - auto vm = VMFace::create(fev.getVMKind(), fev.gas); + auto vm = VMFace::create(vmKind, fev.gas); bytes output; auto outOfGas = false; @@ -629,20 +376,11 @@ 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"]), gas); - + checkOutput(output, o); + + BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); + if (outOfGas) BOOST_CHECK_MESSAGE(gas == 0, "Remaining gas not 0 in out-of-gas state"); @@ -662,172 +400,62 @@ 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"); -} - -BOOST_AUTO_TEST_CASE(vmPerformanceTest) -{ - dev::test::executeTests("vmPerformanceTest"); -} - -BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) -{ - dev::test::executeTests("vmSystemOperationsTest"); + dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(userDefinedFile) { - if (boost::unit_test::framework::master_test_suite().argc >= 2) { string filename = boost::unit_test::framework::master_test_suite().argv[1]; @@ -840,7 +468,7 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) string s = asString(contents(filename)); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); json_spirit::read_string(s, v); - dev::test::doTests(v, false); + dev::test::doVMTests(v, false); } catch (Exception const& _e) { @@ -853,3 +481,5 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) g_logVerbosity = currentVerbosity; } } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/vm.h b/test/vm.h index b3397b2c6..1ed33e5fa 100644 --- a/test/vm.h +++ b/test/vm.h @@ -36,18 +36,12 @@ along with cpp-ethereum. If not, see . #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(); @@ -80,11 +72,8 @@ public: void importExec(json_spirit::mObject& _o); json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); - void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); } - eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); } eth::OnOpFunc simpleTrace(); - FakeState state() const { return m_s; } std::map, bytes>> addresses; eth::Transactions callcreates; @@ -93,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..29d523a36 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" : "0x62122ff4600016600057", + "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" : "0x62122f6a600016600057", + "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" : "0x6212faf4600116600057", + "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" : "0x62126af4600116600057", + "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" : "0x62126af4605016600057", + "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" : "0x66f000000000000161ffff16600057", + "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" : "0x60ff68f0000000000000000116600057", + "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" + } + } }