From 538aae8078fb8bd2cd3c0be5d7dbf64081adec3d Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 25 Oct 2014 18:23:19 +0200 Subject: [PATCH 01/77] Cleaner everything. CryptoPP doesn't recover public keys. secp256k1lib base doesn't verify compact signatures. CryptoPP sign and verify. Stub for secp256k1lib verification from compact signature. --- libdevcrypto/Common.cpp | 25 ++++++++-- libdevcrypto/Common.h | 7 ++- libdevcrypto/CryptoPP.cpp | 83 ++++++++++++++++++++++--------- libdevcrypto/CryptoPP.h | 34 +++++++------ libdevcrypto/EC.cpp | 42 +++++++++++++--- libdevcrypto/EC.h | 9 ++++ libdevcrypto/SHA3MAC.cpp | 5 +- test/crypto.cpp | 101 ++++++++++++++++---------------------- 8 files changed, 192 insertions(+), 114 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6d57bf2b2..f4caa5027 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -152,17 +152,18 @@ inline h256 kFromMessage(h256 _msg, h256 _priv) return _msg ^ _priv; } -Signature dev::sign(Secret _k, h256 _message) +Signature dev::sign(Secret _k, h256 _hash) { int v = 0; secp256k1_start(); SignatureStruct ret; - h256 nonce = kFromMessage(_message, _k); + h256 nonce = kFromMessage(_hash, _k); - if (!secp256k1_ecdsa_sign_compact(_message.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) + if (!secp256k1_ecdsa_sign_compact(_hash.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) return Signature(); + #if ETH_ADDRESS_DEBUG cout << "---- SIGN -------------------------------" << endl; cout << "MSG: " << _message << endl; @@ -174,3 +175,21 @@ Signature dev::sign(Secret _k, h256 _message) ret.v = v; return *(Signature const*)&ret; } + +bool dev::verify(Public _p, Signature _s, h256 _hash) +{ + secp256k1_start(); + + // sig_t +// secp256k1_ecdsa_sig_t s; + int sz = sizeof(_s)-1; +// secp256k1_ecdsa_sig_serialize(_s.data()+1, &sz, &s); + + // pubk_t + byte pubkey[65] = {0x04}; + memcpy(&pubkey[1], _p.data(), 64); + +// int result = secp256k1_ecdsa_verify(_hash.data(), sizeof(_hash), &s, sizeof(s), pubkey, 65); + return 0; +} + diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..bd9a4fbd4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -59,7 +59,7 @@ 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); @@ -67,7 +67,10 @@ bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); Public recover(Signature _sig, h256 _message); /// 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. diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index cabcfd45a..fa45e6242 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,12 +25,62 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -ECP::Point pp::PointFromPublic(Public const& _p) +/// Conversion from bytes to cryptopp point +inline ECP::Point publicToPoint(Public const& _p); + +/// Conversion from bytes to cryptopp exponent +inline Integer secretToExponent(Secret const& _s); + +/// Conversion from cryptopp exponent Integer to bytes +inline void exponentToPublic(Integer const& _e, Public& _p); + +void pp::initializeSigner(Secret const& _s, ECDSA::Signer& _signer) +{ + _signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _signer.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +void pp::initializeVerifier(Public const& _p, ECDSA::Verifier& _verifier) +{ + _verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _verifier.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& _encryptor) +{ + _encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _encryptor.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& _decryptor) +{ + _decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +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."); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); + memcpy(_p.data(), &prefixedKey[1], Public::size); +} + +void pp::exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +{ + _k.GetPrivateExponent().Encode(_s.data(), Secret::size); +} + +/// Integer and Point Conversion: + +inline ECP::Point publicToPoint(Public const& _p) { ECP::Point p; CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1()); - + pub.AccessGroupParameters().Initialize(pp::secp256k1Curve); + bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); prefixedKey[0] = 0x04; assert(Public::size == prefixedKey.size() - 1); @@ -40,35 +90,20 @@ ECP::Point pp::PointFromPublic(Public const& _p) return std::move(p); } -Integer pp::ExponentFromSecret(Secret const& _s) +inline Integer secretToExponent(Secret const& _s) { static_assert(Secret::size == 32, "Secret key must be 32 bytes."); return std::move(Integer(_s.data(), Secret::size)); } -void pp::PublicFromExponent(Integer const& _e, Public& _p) +inline void exponentToPublic(Integer const& _e, Public& _p) { CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(secp256k1()); + k.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.SetPrivateExponent(_e); - + CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(secp256k1()); + p.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.MakePublicKey(p); - pp::PublicFromDL_PublicKey_EC(p, _p); -} - -void pp::PublicFromDL_PublicKey_EC(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."); - 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) -{ - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); + pp::exportPublicKey(p, _p); } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index d7e4181ee..87334b847 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,8 +23,6 @@ #pragma once -// need to leave this one disabled -//#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push @@ -58,27 +56,31 @@ namespace crypto namespace pp { -/// 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); +/// CryptoPP random number pool +static CryptoPP::AutoSeededRandomPool PRNG; + +/// CryptoPP EC Cruve +static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); -/// Conversion from bytes to cryptopp exponent -CryptoPP::Integer ExponentFromSecret(Secret const& _s); +/// Initialize signer +void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); + +/// Initialize verifier +void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); -/// Conversion from cryptopp exponent Integer to bytes -void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); +/// Conversion from Public key to cryptopp encryptor +void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); +/// Conversion from Secret key to cryptopp decryptor +void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); + /// Conversion from cryptopp public key to bytes -void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& out_p); /// Conversion from cryptopp private key to bytes -void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); - +void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& out_s); + } } } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b38703ac3..d3c9d9c9f 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -42,32 +42,58 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +void crypto::encrypt(Public const& _key, bytes& io_cipher) { ECIES::Encryptor e; - e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + pp::initializeEncryptor(_key, 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()); + e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); bzero(io_cipher.data(), 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)); + pp::initializeDecryptor(_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()); + DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); assert(r.messageLength); io_text.resize(r.messageLength); io_text = std::move(p); } +Signature crypto::sign(Secret const& _k, bytesConstRef _message) +{ + ECDSA::Signer signer; + pp::initializeSigner(_k, signer); + + string sigstr; + StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + + /// eth signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. + return std::move(retsig); +} + +//Public crypto::recover(Signature _sig, bytesConstRef _message) +//{ +// +//} + +bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) +{ + ECDSA::Verifier verifier; + pp::initializeVerifier(_p, verifier); + // cryptopp signatures are 64 bytes + static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); + return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); +} + + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index cf6714faf..c7ce01ed0 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -35,7 +35,16 @@ void encrypt(Public const& _k, bytes& io_cipher); /// Decrypts text (in place). void decrypt(Secret const& _k, bytes& io_text); + +/// Returns siganture of message hash. +Signature sign(Secret const& _k, bytesConstRef _message); +/// Recovers Public key from signed message. +//Public recover(Signature _sig, bytesConstRef _message); + +/// Verify signature +bool verify(Public _p, Signature _sig, bytesConstRef _message); + } } diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 5c74edd7e..1fa370ca1 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -28,10 +28,11 @@ 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; - ctx.Update((byte*)_secret.data(), _secret.size()); + if (_secret.size() > 0) + ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); diff --git a/test/crypto.cpp b/test/crypto.cpp index 0d3b6202f..187ca6c79 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "TestHelperCrypto.h" using namespace std; @@ -57,96 +58,81 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) 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()))); Secret previous = s; for (auto i = 0; i < 30; 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); + pp::exportPrivateKey(d.GetKey(), s); assert(s != previous); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); } } -BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) +BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { KeyPair k = KeyPair::create(); Secret s = k.sec(); - - // Convert secret to exponent used by pp - Integer e = pp::ExponentFromSecret(s); - // 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()); + string emptystr(""), msgstr("test"); + bytesConstRef empty(emptystr), msg(msgstr); - // 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); + // sha3 output of strings are the same + h256 hashpp; + sha3mac(empty, msg, hashpp.ref()); + assert(sha3(msg) == hashpp); + + // cryptopp sign and verify + Signature sigpp = crypto::sign(s, msg); + cout << std::hex << sigpp << endl; + + ECDSA::Verifier verifier; + pp::initializeVerifier(k.pub(), verifier); + assert(verifier.VerifyMessage(msg.data(), msgstr.size(), sigpp.data(), sizeof(Signature))); + + // seckp256k1lib sign and verify + h256 hashed(sha3(h256().asBytes())); + Signature sig = dev::sign(s, hashed); + Public recoveredp = dev::recover(sig, hashed); + bool result = dev::verify(k.pub(), sig, hashed); +// assert(result); + - // 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); } 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); 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_AUTO_TEST_CASE(ecies_eckeypair) @@ -172,9 +158,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 +166,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,31 +174,31 @@ 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); From 6e889cd88757c7b80b4a5a46db6c4302f7bfac95 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 04:17:03 +0100 Subject: [PATCH 02/77] ecdsa tests --- libdevcrypto/Common.cpp | 17 ++----- libdevcrypto/EC.cpp | 8 +-- libdevcrypto/EC.h | 3 -- test/crypto.cpp | 109 ++++++++++++++++++++++++++++------------ 4 files changed, 81 insertions(+), 56 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index fd9d6a563..584f4cfe7 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -78,6 +78,7 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { + secp256k1_start(); int ok = secp256k1_ecdsa_seckey_verify(m_secret.data()); if (!ok) return; @@ -180,18 +181,8 @@ Signature dev::sign(Secret _k, h256 _hash) bool dev::verify(Public _p, Signature _s, h256 _hash) { - secp256k1_start(); - - // sig_t -// secp256k1_ecdsa_sig_t s; - int sz = sizeof(_s)-1; -// secp256k1_ecdsa_sig_serialize(_s.data()+1, &sz, &s); - - // pubk_t - byte pubkey[65] = {0x04}; - memcpy(&pubkey[1], _p.data(), 64); - -// int result = secp256k1_ecdsa_verify(_hash.data(), sizeof(_hash), &s, sizeof(s), pubkey, 65); - return 0; + // Placeholder. The signature should be verified if recovering public key isn't proof. + Public v = dev::recover(_s, _hash); + return (v == _p); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 5d05b2aec..b8321102b 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -81,20 +81,14 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) string sigstr; StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); - - /// eth signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. return std::move(retsig); } -//Public crypto::recover(Signature _sig, bytesConstRef _message) -//{ -// -//} - bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) { ECDSA::Verifier verifier; pp::initializeVerifier(_p, verifier); + // cryptopp signatures are 64 bytes static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index c7ce01ed0..8b66a7bfe 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -38,9 +38,6 @@ void decrypt(Secret const& _k, bytes& io_text); /// Returns siganture of message hash. Signature sign(Secret const& _k, bytesConstRef _message); - -/// Recovers Public key from signed message. -//Public recover(Signature _sig, bytesConstRef _message); /// Verify signature bool verify(Public _p, Signature _sig, bytesConstRef _message); diff --git a/test/crypto.cpp b/test/crypto.cpp index 187ca6c79..ebb844688 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -47,13 +47,13 @@ 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) @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Public 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++) @@ -77,45 +77,88 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Secret s; pp::exportPrivateKey(d.GetKey(), s); - assert(s != previous); + BOOST_REQUIRE(s != previous); Public 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()))); } } BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { - KeyPair k = KeyPair::create(); - Secret s = k.sec(); - - string emptystr(""), msgstr("test"); - bytesConstRef empty(emptystr), msg(msgstr); - - // sha3 output of strings are the same - h256 hashpp; - sha3mac(empty, msg, hashpp.ref()); - assert(sha3(msg) == hashpp); - - // cryptopp sign and verify - Signature sigpp = crypto::sign(s, msg); - cout << std::hex << sigpp << endl; - + // 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("0x02")); + h256 hm(sha3(m)); // f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2 + Integer hInt("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); // 32b msg hash + 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::initializeSigner(key.sec(), signer); + Integer r, s; + signer.RawSign(kInt, hInt, r, s); + cout << "cryptopp-raw r, s: " << endl << r << endl << s << endl; + + // verify cryptopp raw-signature w/cryptopp ECDSA::Verifier verifier; - pp::initializeVerifier(k.pub(), verifier); - assert(verifier.VerifyMessage(msg.data(), msgstr.size(), sigpp.data(), sizeof(Signature))); - - // seckp256k1lib sign and verify - h256 hashed(sha3(h256().asBytes())); - Signature sig = dev::sign(s, hashed); - Public recoveredp = dev::recover(sig, hashed); - bool result = dev::verify(k.pub(), sig, hashed); -// assert(result); - - - + pp::initializeVerifier(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(dev::recover(sigppraw, hm) == key.pub()); + + // sign with sec256lib, verify with cryptopp + Signature seclibsig(dev::sign(key.sec(), hm)); + r.Decode(seclibsig.data(), 32); + s.Decode(seclibsig.data()+32, 32); + cout << "sec256lib r, s: " << endl << r << endl << s << endl; + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); + 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()); + r.Decode(sigppb.data(), 32); + s.Decode(sigppb.data()+32, 32); + cout << "cryptopp-signmsg r, s: " << endl << r << endl << s << endl; + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); + + // this has a 25% of failing + Signature sigpp; + r.Encode(sigpp.data(), 32); + s.Encode(sigpp.data()+32, 32); + BOOST_WARN(dev::recover(sigpp, hm) == key.pub()); + + // sign with stringsource + 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)); + + + // need to serialize signature for secp256k1lib to verify compact sig, then + // test if secp256k1lib can verify cryptopp sigs + + +// byte dersig[70]; +// DSAConvertSignatureFormat(dersig, 70, DSA_DER, sig.data(), 64, DSA_P1363); +// +// byte encpub[65] = {0x04}; +// memcpy(&encpub[1], key.pub().data(), 64); +// int r = secp256k1_ecdsa_verify(msg.data(), msg.size(), dersig, 70, encpub, 65); +// assert(r); } From 5517fa2f4222d097ab2f0f0758c42cab84febffd Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 05:15:44 +0100 Subject: [PATCH 03/77] support for verifying ec signatures w/secp256k1 or cryptopp. --- libdevcrypto/Common.cpp | 4 +- libdevcrypto/CryptoPP.h | 1 + libdevcrypto/EC.cpp | 14 +++- libdevcrypto/EC.h | 2 +- test/crypto.cpp | 178 +++++++++++++++++++++------------------- 5 files changed, 109 insertions(+), 90 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 584f4cfe7..c7503a820 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -181,8 +181,6 @@ Signature dev::sign(Secret _k, h256 _hash) bool dev::verify(Public _p, Signature _s, h256 _hash) { - // Placeholder. The signature should be verified if recovering public key isn't proof. - Public v = dev::recover(_s, _hash); - return (v == _p); + return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 87334b847..3064f0dc4 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -45,6 +45,7 @@ #include #include #include +#include #pragma warning(pop) #pragma GCC diagnostic pop #include "Common.h" diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b8321102b..77096b691 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -84,11 +84,21 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) return std::move(retsig); } -bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) +bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) { + if (_raw) + { + assert(_message.size() == 32); + byte encpub[65] = {0x04}; + memcpy(&encpub[1], _p.data(), 64); + byte dersig[72]; + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, _sig.data(), 64, DSA_P1363); + assert(cssz <= 72); + return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65)); + } + ECDSA::Verifier verifier; pp::initializeVerifier(_p, verifier); - // cryptopp signatures are 64 bytes static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index 8b66a7bfe..d98472a54 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -40,7 +40,7 @@ void decrypt(Secret const& _k, bytes& io_text); Signature sign(Secret const& _k, bytesConstRef _message); /// Verify signature -bool verify(Public _p, Signature _sig, bytesConstRef _message); +bool verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw = false); } } diff --git a/test/crypto.cpp b/test/crypto.cpp index ebb844688..c1f678fcb 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -97,69 +97,79 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 KeyPair key(secret); - bytes m(fromHex("0x02")); - h256 hm(sha3(m)); // f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2 - Integer hInt("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); // 32b msg hash - 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::initializeSigner(key.sec(), signer); - Integer r, s; - signer.RawSign(kInt, hInt, r, s); - cout << "cryptopp-raw r, s: " << endl << r << endl << s << endl; - - // verify cryptopp raw-signature w/cryptopp - ECDSA::Verifier verifier; - pp::initializeVerifier(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(dev::recover(sigppraw, hm) == key.pub()); - - // sign with sec256lib, verify with cryptopp - Signature seclibsig(dev::sign(key.sec(), hm)); - r.Decode(seclibsig.data(), 32); - s.Decode(seclibsig.data()+32, 32); - cout << "sec256lib r, s: " << endl << r << endl << s << endl; - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); - 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()); - r.Decode(sigppb.data(), 32); - s.Decode(sigppb.data()+32, 32); - cout << "cryptopp-signmsg r, s: " << endl << r << endl << s << endl; - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); - - // this has a 25% of failing - Signature sigpp; - r.Encode(sigpp.data(), 32); - s.Encode(sigpp.data()+32, 32); - BOOST_WARN(dev::recover(sigpp, hm) == key.pub()); - - // sign with stringsource - 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)); - - - // need to serialize signature for secp256k1lib to verify compact sig, then - // test if secp256k1lib can verify cryptopp sigs - - -// byte dersig[70]; -// DSAConvertSignatureFormat(dersig, 70, DSA_DER, sig.data(), 64, DSA_P1363); -// -// byte encpub[65] = {0x04}; -// memcpy(&encpub[1], key.pub().data(), 64); -// int r = secp256k1_ecdsa_verify(msg.data(), msg.size(), dersig, 70, encpub, 65); -// assert(r); - + bytes m(fromHex("0x01")); + int tests = 5; + 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::initializeSigner(key.sec(), signer); + Integer r, s; + signer.RawSign(kInt, hInt, r, s); + + // verify cryptopp raw-signature w/cryptopp + ECDSA::Verifier verifier; + pp::initializeVerifier(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)); + BOOST_CHECK(dev::recover(sigppraw, hm) == key.pub()); + + // sign with sec256lib, verify with cryptopp + 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_CHECK(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)); + BOOST_CHECK(dev::recover(sigpp, hm) == key.pub()); + + // 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)); + BOOST_CHECK(dev::recover(retsig, hm) == key.pub()); + + /// 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) @@ -172,10 +182,10 @@ BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) Public 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); + BOOST_REQUIRE(l.address() == addr); } BOOST_AUTO_TEST_CASE(ecies_eckeypair) @@ -187,10 +197,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) @@ -244,16 +254,16 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) 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; @@ -276,7 +286,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) @@ -289,7 +299,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) { @@ -300,7 +310,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]; @@ -309,7 +319,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) { @@ -321,7 +331,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); @@ -336,11 +346,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 @@ -350,10 +360,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) @@ -390,8 +400,8 @@ 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; @@ -406,7 +416,7 @@ int cryptoTest() cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(true); - assert(t.sender() == p.address()); + BOOST_REQUIRE(t.sender() == p.address()); } From 464fe70e454b8a00de8f434033aa99b6492ca419 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 05:21:02 +0100 Subject: [PATCH 04/77] doc text --- libdevcrypto/CryptoPP.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 3064f0dc4..fdeb67707 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -64,16 +64,16 @@ static CryptoPP::AutoSeededRandomPool PRNG; /// CryptoPP EC Cruve static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); -/// Initialize signer +/// Initialize signer with Secret void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); -/// Initialize verifier +/// Initialize verifier with Public void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); -/// Conversion from Public key to cryptopp encryptor +/// Initialize cryptopp encryptor with Public void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); -/// Conversion from Secret key to cryptopp decryptor +/// Initialize cryptopp decryptor with Secret void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); /// Conversion from cryptopp public key to bytes From 6b6ebcdcdac1b67fea8c41f5fc5ac3d2bf892544 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 17:21:01 +0100 Subject: [PATCH 05/77] Require secret for hmac. --- libdevcrypto/SHA3MAC.cpp | 4 ++-- test/crypto.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 1fa370ca1..9498ef87b 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -31,8 +31,8 @@ using namespace CryptoPP; void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { CryptoPP::SHA3_256 ctx; - if (_secret.size() > 0) - ctx.Update((byte*)_secret.data(), _secret.size()); + assert(_secret.size() > 0); + ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); diff --git a/test/crypto.cpp b/test/crypto.cpp index c1f678fcb..3d47d0b0c 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) bytes m(fromHex("0x01")); int tests = 5; - while (m[0]++ && tests--) + while (m[0]++, tests--) { h256 hm(sha3(m)); Integer hInt(hm.asBytes().data(), 32); From 5fc22a8cc79ab1e382e87de3490160ff186913c0 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 18:08:10 +0100 Subject: [PATCH 06/77] numbers to words --- libdevcrypto/EC.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 77096b691..d6c2ad622 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -86,14 +86,15 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) { + static size_t derMaxEncodingLength = 72; if (_raw) { assert(_message.size() == 32); byte encpub[65] = {0x04}; memcpy(&encpub[1], _p.data(), 64); - byte dersig[72]; - size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, _sig.data(), 64, DSA_P1363); - assert(cssz <= 72); + 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)); } From 3ce9cde377007e84c331706093e92fbb6a943b6f Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 28 Oct 2014 16:24:49 +0100 Subject: [PATCH 07/77] revert oops; warning for unused-function disabled during link-time --- libdevcrypto/CryptoPP.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index fdeb67707..e7a5ea94c 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,10 +23,11 @@ #pragma once +// need to leave this one disabled for link-time. blame cryptopp. +#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" From ec5bf1abe91975e381f39520bb2a3a92a7b6b9a2 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 29 Oct 2014 00:29:07 +0100 Subject: [PATCH 08/77] NEG->BNOT change --- libsolidity/Compiler.cpp | 12 ++++-------- test/solidityCompiler.cpp | 4 +--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index acb0a5cc7..4244a3e09 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -111,13 +111,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) append(eth::Instruction::NOT); break; case Token::BIT_NOT: // ~ - // ~a modeled as "a xor (0 - 1)" for now - append(eth::Instruction::PUSH1); - append(1); - append(eth::Instruction::PUSH1); - append(0); - append(eth::Instruction::SUB); - append(eth::Instruction::XOR); + append(eth::Instruction::BNOT); break; case Token::DELETE: // delete // a -> a xor a (= 0). @@ -149,7 +143,9 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) // unary add, so basically no-op break; case Token::SUB: // - - append(eth::Instruction::NEG); + append(eth::Instruction::PUSH1); + append(0); + append(eth::Instruction::SUB); break; default: assert(false); // invalid operation diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 6e12fecf8..02a2287d9 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -210,11 +210,9 @@ BOOST_AUTO_TEST_CASE(unary_operators) byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), - byte(eth::Instruction::NEG), - byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SUB), - byte(eth::Instruction::XOR), // bitwise not + byte(eth::Instruction::BNOT), byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::EQ), byte(eth::Instruction::NOT)}); From 2b6d66374dd58601612565bbfd7c67b7fe0a072b Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Oct 2014 16:52:22 +0200 Subject: [PATCH 09/77] Compiler for assignments. --- libsolidity/AST.cpp | 13 ++++- libsolidity/AST.h | 9 ++- libsolidity/Compiler.cpp | 113 ++++++++++++++++++++++++++++++-------- libsolidity/Compiler.h | 16 +++++- libsolidity/Exceptions.h | 1 + solc/main.cpp | 60 +++++++++++--------- test/solidityCompiler.cpp | 62 +++++++++++++++++++-- 7 files changed, 214 insertions(+), 60 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0b635339d..7b5b6a73c 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -326,6 +326,8 @@ void Assignment::checkTypeRequirements() //@todo lefthandside actually has to be assignable // add a feature to the type system to check that m_leftHandSide->checkTypeRequirements(); + if (!m_leftHandSide->isLvalue()) + BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); expectType(*m_rightHandSide, *m_leftHandSide->getType()); m_type = m_leftHandSide->getType(); if (m_assigmentOperator != Token::ASSIGN) @@ -338,8 +340,13 @@ void Assignment::checkTypeRequirements() 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.")); @@ -441,9 +448,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()? diff --git a/libsolidity/AST.h b/libsolidity/AST.h index db6637aea..856c222eb 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -402,13 +402,17 @@ private: class Expression: public Statement { public: - Expression(Location const& _location): Statement(_location) {} + Expression(Location const& _location): Statement(_location), m_isLvalue(false) {} std::shared_ptr const& getType() const { return m_type; } + bool isLvalue() const { return m_isLvalue; } 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; }; /// @} @@ -492,6 +496,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; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 4244a3e09..dbb38324d 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -81,22 +81,29 @@ AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context, return compiler.getAssemblyItems(); } -void ExpressionCompiler::endVisit(Assignment& _assignment) +bool ExpressionCompiler::visit(Assignment& _assignment) { + m_currentLValue = nullptr; + _assignment.getLeftHandSide().accept(*this); + Expression& rightHandSide = _assignment.getRightHandSide(); Token::Value op = _assignment.getAssignmentOperator(); if (op != Token::ASSIGN) { // compound assignment - // @todo retrieve lvalue value rightHandSide.accept(*this); Type const& resultType = *_assignment.getType(); cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); } else + { + append(eth::Instruction::POP); //@todo do not retrieve the value in the first place rightHandSide.accept(*this); - // @todo store value + } + + storeInLValue(_assignment); + return false; } void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) @@ -114,30 +121,31 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) append(eth::Instruction::BNOT); 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); + storeInLValue(_unaryOperation); 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()) + if (!_unaryOperation.isPrefixOperation()) + append(eth::Instruction::DUP1); + append(eth::Instruction::PUSH1); + append(1); + if (_unaryOperation.getOperator() == Token::INC) + append(eth::Instruction::ADD); + else { - append(eth::Instruction::PUSH1); - append(1); append(eth::Instruction::SWAP1); //@todo avoid this append(eth::Instruction::SUB); } + if (_unaryOperation.isPrefixOperation()) + storeInLValue(_unaryOperation); + else + moveToLValue(_unaryOperation); break; case Token::ADD: // + // unary add, so basically no-op @@ -190,28 +198,38 @@ 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. + //@todo we only have integers and bools for now which cannot be explicitly converted + assert(_functionCall.getArguments().size() == 1); + cleanHigherOrderBitsIfNeeded(*_functionCall.getArguments().front()->getType(), + *_functionCall.getType()); } else { - //@todo + //@todo: arguments are already on the stack + // push return label (below arguments?) + // jump to function label + // discard all but the first function return argument } } -void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) +void ExpressionCompiler::endVisit(MemberAccess&) { } -void ExpressionCompiler::endVisit(IndexAccess& _indexAccess) +void ExpressionCompiler::endVisit(IndexAccess&) { } void ExpressionCompiler::endVisit(Identifier& _identifier) { - + m_currentLValue = _identifier.getReferencedDeclaration(); + 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.")); + appendDup(stackPos + 1); } void ExpressionCompiler::endVisit(Literal& _literal) @@ -224,7 +242,7 @@ void ExpressionCompiler::endVisit(Literal& _literal) bytes value = _literal.getType()->literalToBigEndian(_literal); assert(value.size() <= 32); assert(!value.empty()); - append(static_cast(eth::Instruction::PUSH1) + static_cast(value.size() - 1)); + appendPush(value.size()); append(value); break; } @@ -391,6 +409,24 @@ uint32_t ExpressionCompiler::appendConditionalJump() return label; } +void ExpressionCompiler::appendPush(unsigned _number) +{ + assert(1 <= _number && _number <= 32); + append(eth::Instruction(unsigned(eth::Instruction::PUSH1) + _number - 1)); +} + +void ExpressionCompiler::appendDup(unsigned _number) +{ + assert(1 <= _number && _number <= 16); + append(eth::Instruction(unsigned(eth::Instruction::DUP1) + _number - 1)); +} + +void ExpressionCompiler::appendSwap(unsigned _number) +{ + assert(1 <= _number && _number <= 16); + append(eth::Instruction(unsigned(eth::Instruction::SWAP1) + _number - 1)); +} + void ExpressionCompiler::append(bytes const& _data) { m_assemblyItems.reserve(m_assemblyItems.size() + _data.size()); @@ -398,6 +434,37 @@ void ExpressionCompiler::append(bytes const& _data) append(b); } +void ExpressionCompiler::storeInLValue(Expression const& _expression) +{ + assert(m_currentLValue); + moveToLValue(_expression); + unsigned stackPos = stackPositionOfLValue(); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + if (stackPos >= 1) + appendDup(stackPos); +} + +void ExpressionCompiler::moveToLValue(Expression const& _expression) +{ + assert(m_currentLValue); + unsigned stackPos = stackPositionOfLValue(); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackPos > 0) + { + appendSwap(stackPos); + append(eth::Instruction::POP); + } +} + +unsigned ExpressionCompiler::stackPositionOfLValue() const +{ + return 8; // @todo ask the context and track stack changes due to m_assemblyItems +} + } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index ac5e10ec9..1c5523e08 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -87,7 +87,7 @@ private: class ExpressionCompiler: public ASTVisitor { public: - ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} + ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} /// Compile the given expression and (re-)populate the assembly item list. void compile(Expression& _expression); @@ -98,7 +98,7 @@ public: static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression); private: - virtual void endVisit(Assignment& _assignment) override; + virtual bool visit(Assignment& _assignment) override; virtual void endVisit(UnaryOperation& _unaryOperation) override; virtual bool visit(BinaryOperation& _binaryOperation) override; virtual void endVisit(FunctionCall& _functionCall) override; @@ -123,6 +123,9 @@ private: /// Appends a JUMPI instruction to a new label and returns the label uint32_t appendConditionalJump(); + void appendPush(unsigned _number); + void appendDup(unsigned _number); + void appendSwap(unsigned _number); /// Append elements to the current instruction list. void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); } @@ -131,6 +134,15 @@ private: void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); } void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); } + /// 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; AssemblyItems m_assemblyItems; CompilerContext& m_context; }; diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 5a48c47dd..1d981e7c0 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -34,6 +34,7 @@ namespace solidity struct ParserError: virtual Exception {}; struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; +struct CompilerError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/solc/main.cpp b/solc/main.cpp index f5c4c8a0f..24f07d952 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -34,25 +34,24 @@ #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); } @@ -87,10 +86,10 @@ private: 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") @@ -98,13 +97,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); } } @@ -112,7 +111,7 @@ 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; try { @@ -120,39 +119,48 @@ int main(int argc, char** argv) } 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; + 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; } - std::cout << "Syntax tree for the contract:" << std::endl; + cout << "Syntax tree for the contract:" << endl; dev::solidity::ASTPrinter printer(ast, sourceCode); - printer.print(std::cout); + printer.print(cout); FirstExpressionExtractor extractor(*ast); CompilerContext context; ExpressionCompiler compiler(context); - compiler.compile(*extractor.getExpression()); + try + { + compiler.compile(*extractor.getExpression()); + } + catch (CompilerError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); + return -1; + } + bytes instructions = compiler.getAssembledBytecode(); - // debug - std::cout << "Bytecode for the first expression: " << std::endl; - std::cout << eth::disassemble(instructions) << std::endl; + + cout << "Bytecode for the first expression: " << endl; + cout << eth::disassemble(instructions) << endl; return 0; } diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 02a2287d9..591330dd6 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -200,22 +200,74 @@ BOOST_AUTO_TEST_CASE(arithmetics) BOOST_AUTO_TEST_CASE(unary_operators) { char const* sourceCode = "contract test {\n" - " function f() { var x = !(~+-(--(++1++)--) == 2); }" + " 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::BNOT), + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT)}); + 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); + + bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking + byte(eth::Instruction::DUP1), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::ADD), + byte(eth::Instruction::SWAP8), // will change + byte(eth::Instruction::POP), // first ++ + byte(eth::Instruction::DUP9), byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::ADD), + byte(eth::Instruction::SWAP8), // will change + byte(eth::Instruction::POP), // second ++ + byte(eth::Instruction::DUP8), // will change + byte(eth::Instruction::XOR), + byte(eth::Instruction::DUP9), // will change + byte(eth::Instruction::DUP1), byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), - byte(eth::Instruction::PUSH1), 0x0, + byte(eth::Instruction::SWAP8), // will change + byte(eth::Instruction::POP), // first -- + byte(eth::Instruction::XOR), + byte(eth::Instruction::DUP9), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), - byte(eth::Instruction::BNOT), + byte(eth::Instruction::SWAP8), // will change + byte(eth::Instruction::POP), // second ++ + byte(eth::Instruction::DUP8), // will change + byte(eth::Instruction::XOR)}); + 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); + + bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking + byte(eth::Instruction::DUP9), + byte(eth::Instruction::ADD), + byte(eth::Instruction::SWAP8), // will change + byte(eth::Instruction::POP), // first ++ + byte(eth::Instruction::DUP8), byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT)}); + byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } From 4c3894e4558809caa76cce824f70377d163ef5d4 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 29 Oct 2014 18:46:57 +0100 Subject: [PATCH 10/77] recover public key from ecdsa,v sig using cryptopp --- test/crypto.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/test/crypto.cpp b/test/crypto.cpp index acb7b7589..773c64d3b 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -86,6 +86,114 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) } } +BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) +{ + // cryptopp implementation of secp256k1lib sign_compact w/recid parameter for recovering public key from signature + + // cryptopp does this: + // void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + // { + // const Integer &q = params.GetSubgroupOrder(); + // r %= q; + // Integer kInv = k.InverseMod(q); + // s = (kInv * (x*r + e)) % q; + // assert(!!r && !!s); + // } + + // secp256k1lib does this, which we want cryptopp to do: + // secp256k1_gej_t rp; + // secp256k1_ecmult_gen(&rp, nonce); + // secp256k1_ge_t r; + // secp256k1_ge_set_gej(&r, &rp); + // unsigned char b[32]; + // secp256k1_fe_normalize(&r.x); + // secp256k1_fe_normalize(&r.y); + // secp256k1_fe_get_b32(b, &r.x); + // secp256k1_num_set_bin(&sig->r, b, 32); + // if (recid) + // *recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + // secp256k1_num_mod(&sig->r, &c->order); + // secp256k1_num_t n; + // secp256k1_num_init(&n); + // secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order); + // secp256k1_num_add(&n, &n, message); + // secp256k1_num_mod(&n, &c->order); + // secp256k1_num_mod_inverse(&sig->s, nonce, &c->order); + // secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order); + // secp256k1_num_free(&n); + // if (secp256k1_num_is_zero(&sig->s)) + // return 0; + // if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) { + // secp256k1_num_sub(&sig->s, &c->order, &sig->s); + // if (recid) + // *recid ^= 1; + // } + + + // secret + Secret secret(sha3("privacy")); + + // e := sha3(msg) + bytes e(fromHex("0x01")); + e.resize(32); + int tests = 150; // Oct 29: successful @ 1500 + while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + { + KeyPair key(secret); + + h256 he(sha3(e)); + Integer heInt(he.asBytes().data(), 32); + h256 k(he ^ key.sec()); + Integer kInt(k.asBytes().data(), 32); + + // we get ec params from signer + ECDSA::Signer signer; + pp::initializeSigner(key.sec(), signer); + + const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); + + 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); + BOOST_REQUIRE(!(r>=q)); // interesting, this never happens + r %= q; + + Integer kInv = kInt.InverseMod(q); + Integer s = (kInv * (Integer(key.sec().asBytes().data(), 32)*r + heInt)) % q; + BOOST_REQUIRE(!!r && !!s); + + if (s > params.GetSubgroupOrder()) + { + // also interesting, this never happens + s = params.GetGroupOrder() - s; + if (recid) + recid ^= 1; + } + BOOST_REQUIRE(recid < 2); + + Signature sig; + r.Encode(sig.data(), 32); + s.Encode(sig.data()+32, 32); + sig[64] = recid; + + Public p = dev::recover(sig, he); + Public pkey = key.pub(); + BOOST_REQUIRE(p == pkey); + + // verify w/cryptopp + BOOST_REQUIRE(crypto::verify(key.pub(), sig, bytesConstRef(&e))); + + // verify with secp256k1lib + byte encpub[65] = {0x04}; + memcpy(&encpub[1], key.pub().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 From fb00cbc62906c1a0ba7d0b2fa981d92c969c5d09 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 29 Oct 2014 19:24:23 +0100 Subject: [PATCH 11/77] remove asserts for recid being 2, which is rare, but may occur --- test/crypto.cpp | 74 +++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/test/crypto.cpp b/test/crypto.cpp index 773c64d3b..e11659ed0 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -88,89 +88,48 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) { - // cryptopp implementation of secp256k1lib sign_compact w/recid parameter for recovering public key from signature - - // cryptopp does this: - // void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const - // { - // const Integer &q = params.GetSubgroupOrder(); - // r %= q; - // Integer kInv = k.InverseMod(q); - // s = (kInv * (x*r + e)) % q; - // assert(!!r && !!s); - // } - - // secp256k1lib does this, which we want cryptopp to do: - // secp256k1_gej_t rp; - // secp256k1_ecmult_gen(&rp, nonce); - // secp256k1_ge_t r; - // secp256k1_ge_set_gej(&r, &rp); - // unsigned char b[32]; - // secp256k1_fe_normalize(&r.x); - // secp256k1_fe_normalize(&r.y); - // secp256k1_fe_get_b32(b, &r.x); - // secp256k1_num_set_bin(&sig->r, b, 32); - // if (recid) - // *recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); - // secp256k1_num_mod(&sig->r, &c->order); - // secp256k1_num_t n; - // secp256k1_num_init(&n); - // secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order); - // secp256k1_num_add(&n, &n, message); - // secp256k1_num_mod(&n, &c->order); - // secp256k1_num_mod_inverse(&sig->s, nonce, &c->order); - // secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order); - // secp256k1_num_free(&n); - // if (secp256k1_num_is_zero(&sig->s)) - // return 0; - // if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) { - // secp256k1_num_sub(&sig->s, &c->order, &sig->s); - // if (recid) - // *recid ^= 1; - // } - - - // secret + // 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 + ECDSA::Signer signer; + // e := sha3(msg) bytes e(fromHex("0x01")); e.resize(32); - int tests = 150; // Oct 29: successful @ 1500 + int tests = 15; // Oct 29: successful @ 1500 while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) { KeyPair key(secret); + Public pkey = key.pub(); + pp::initializeSigner(secret, signer); h256 he(sha3(e)); Integer heInt(he.asBytes().data(), 32); - h256 k(he ^ key.sec()); + h256 k(he ^ secret); Integer kInt(k.asBytes().data(), 32); - // we get ec params from signer - ECDSA::Signer signer; - pp::initializeSigner(key.sec(), signer); - const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); 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); - BOOST_REQUIRE(!(r>=q)); // interesting, this never happens - r %= q; - + BOOST_REQUIRE(!(r >= q)); + Integer kInv = kInt.InverseMod(q); - Integer s = (kInv * (Integer(key.sec().asBytes().data(), 32)*r + heInt)) % q; + Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); if (s > params.GetSubgroupOrder()) { - // also interesting, this never happens + // note: this rarely happens s = params.GetGroupOrder() - s; if (recid) recid ^= 1; } - BOOST_REQUIRE(recid < 2); Signature sig; r.Encode(sig.data(), 32); @@ -178,15 +137,14 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) sig[64] = recid; Public p = dev::recover(sig, he); - Public pkey = key.pub(); BOOST_REQUIRE(p == pkey); // verify w/cryptopp - BOOST_REQUIRE(crypto::verify(key.pub(), sig, bytesConstRef(&e))); + BOOST_REQUIRE(crypto::verify(pkey, sig, bytesConstRef(&e))); // verify with secp256k1lib byte encpub[65] = {0x04}; - memcpy(&encpub[1], key.pub().data(), 64); + 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); From 9ae4efd311795e66cc13c055bd1c1ec4c73ca693 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 01:16:11 +0100 Subject: [PATCH 12/77] Bugfix: Allow empty return statements without type checking. --- libsolidity/AST.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 7b5b6a73c..099222fa1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -294,6 +294,8 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { assert(m_returnParameters); + if (!m_expression) + return; if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); From ea6d58a0d14bea806671ba78b2369c81e25d59c4 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 01:20:32 +0100 Subject: [PATCH 13/77] Contract compiler and also add ExpressionStatement to AST. ExpressionStatement functions as glue between Statements and Expressions. This way it is possible to detect when the border between statements and expressions is crossed while walking the AST. Note that ExpressionStatement is not the only border, almost every statement can contains expressions. --- libevmface/Instruction.h | 9 + liblll/Assembly.cpp | 2 +- liblll/Assembly.h | 4 + libsolidity/AST.cpp | 43 ++- libsolidity/AST.h | 65 +++- libsolidity/ASTForward.h | 1 + libsolidity/ASTPrinter.cpp | 12 + libsolidity/ASTPrinter.h | 2 + libsolidity/ASTVisitor.h | 2 + libsolidity/CMakeLists.txt | 4 +- libsolidity/Compiler.cpp | 509 +++++++--------------------- libsolidity/Compiler.h | 141 ++------ libsolidity/CompilerUtilities.cpp | 60 ++++ libsolidity/CompilerUtilities.h | 83 +++++ libsolidity/ExpressionCompiler.cpp | 408 ++++++++++++++++++++++ libsolidity/ExpressionCompiler.h | 79 +++++ libsolidity/NameAndTypeResolver.cpp | 32 +- libsolidity/NameAndTypeResolver.h | 17 +- libsolidity/Parser.cpp | 21 +- libsolidity/Parser.h | 1 + libsolidity/Types.cpp | 18 +- libsolidity/Types.h | 6 +- solc/main.cpp | 41 +-- test/solidityCompiler.cpp | 323 +++++++----------- test/solidityExpressionCompiler.cpp | 348 +++++++++++++++++++ test/solidityParser.cpp | 2 +- 26 files changed, 1434 insertions(+), 799 deletions(-) create mode 100644 libsolidity/CompilerUtilities.cpp create mode 100644 libsolidity/CompilerUtilities.h create mode 100644 libsolidity/ExpressionCompiler.cpp create mode 100644 libsolidity/ExpressionCompiler.h create mode 100644 test/solidityExpressionCompiler.cpp diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index ea355fab1..9115367d7 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -175,6 +175,15 @@ enum class Instruction: uint8_t SUICIDE = 0xff ///< halt execution and register account for later deletion }; +/// Returs the PUSH<_number> instruction +inline Instruction pushInstruction(unsigned _number) { assert(1 <= _number && _number <= 32); return Instruction(unsigned(Instruction::PUSH1) + _number - 1); } + +/// Returs the DUP<_number> instruction +inline Instruction dupInstruction(unsigned _number) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::DUP1) + _number - 1); } + +/// Returs the SWAP<_number> instruction +inline Instruction swapInstruction(unsigned _number) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::SWAP1) + _number - 1); } + /// Information structure for a particular instruction. struct InstructionInfo { diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp index 5b10138d1..7ad84682f 100644 --- a/liblll/Assembly.cpp +++ b/liblll/Assembly.cpp @@ -54,6 +54,7 @@ unsigned Assembly::bytesRequired() const switch (i.m_type) { case Operation: + case Tag: // 1 byte for the JUMPDEST ret++; break; case PushString: @@ -69,7 +70,6 @@ unsigned Assembly::bytesRequired() const case PushData: case PushSub: ret += 1 + br; - case Tag:; default:; } if (dev::bytesRequired(ret) <= br) diff --git a/liblll/Assembly.h b/liblll/Assembly.h index 8ab3062dc..38baee0c5 100644 --- a/liblll/Assembly.h +++ b/liblll/Assembly.h @@ -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; assert(m_deposit >= 0); } + void setDeposit(int _deposit) { m_deposit = _deposit; assert(m_deposit >= 0); } + bytes assemble() const; Assembly& optimise(bool _enable); std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 099222fa1..5391e71b7 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, const Type& _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(); } @@ -301,7 +301,7 @@ void Return::checkTypeRequirements() "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() @@ -313,7 +313,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 @@ -330,7 +330,7 @@ void Assignment::checkTypeRequirements() m_leftHandSide->checkTypeRequirements(); if (!m_leftHandSide->isLvalue()) BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); - expectType(*m_rightHandSide, *m_leftHandSide->getType()); + m_rightHandSide->expectType(*m_leftHandSide->getType()); m_type = m_leftHandSide->getType(); if (m_assigmentOperator != Token::ASSIGN) { @@ -340,6 +340,19 @@ void Assignment::checkTypeRequirements() } } +void ExpressionStatement::checkTypeRequirements() +{ + m_expression->checkTypeRequirements(); +} + +void Expression::expectType(const Type& _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, ADD, SUB, NOT, BIT_NOT, DELETE @@ -411,10 +424,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(); } } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 856c222eb..7af8d521b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -144,7 +144,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; @@ -167,15 +167,20 @@ 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::vectorconst& 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; }; /// Declaration of a variable. This can be used in various places, e.g. in function parameter @@ -285,11 +290,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); }; /// Brace-enclosed block containing zero or more statements. @@ -318,6 +318,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getCondition() const { return *m_condition; } + Statement& getTrueStatement() const { return *m_trueBody; } + Statement* getFalseStatement() const { return m_falseBody.get(); } private: ASTPointer m_condition; ASTPointer m_trueBody; @@ -342,6 +345,8 @@ 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; @@ -372,6 +377,8 @@ public: virtual void checkTypeRequirements() override; void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } + ParameterList const& getFunctionReturnParameters() const { assert(m_returnParameters); return *m_returnParameters; } + Expression* getExpression() const { return m_expression.get(); } private: ASTPointer m_expression; //< value to return, optional @@ -392,21 +399,54 @@ 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). -class Expression: public Statement +/** + * A statement that contains only an expression (i.e. an assignment, function call, ...). + */ +class ExpressionStatement: public Statement +{ +public: + ExpressionStatement(Location const& _location, ASTPointer _expression): + Statement(_location), m_expression(_expression) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void checkTypeRequirements() override; + + Expression& getExpression() const { return *m_expression; } + +private: + ASTPointer m_expression; +}; + +/// @} + +/// Expressions +/// @{ + +/** + * 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): Statement(_location), m_isLvalue(false) {} + 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; @@ -415,11 +455,6 @@ protected: bool m_isLvalue; }; -/// @} - -/// Expressions -/// @{ - /// Assignment, can also be a compound assignment. /// Examples: (a = 7 + 8) or (a *= 2) class Assignment: public Expression 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 74e0837ff..722c80c9e 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -58,6 +58,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; @@ -89,6 +90,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 a667ad392..2a765e47b 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -58,6 +58,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; } @@ -89,6 +90,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 dbb38324d..fea885607 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -17,455 +17,192 @@ /** * @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) -{ - assert(m_labelPositions.find(_label) == m_labelPositions.end()); - m_labelPositions[_label] = _position; -} - -uint32_t CompilerContext::getLabelPosition(uint32_t _label) const -{ - auto iter = m_labelPositions.find(_label); - assert(iter != m_labelPositions.end()); - return iter->second; -} - -void ExpressionCompiler::compile(Expression& _expression) +bytes Compiler::compile(ContractDefinition& _contract) { - m_assemblyItems.clear(); - _expression.accept(*this); + Compiler compiler; + compiler.compileContract(_contract); + return compiler.m_context.getAssembledBytecode(); } -bytes ExpressionCompiler::getAssembledBytecode() const +void Compiler::compileContract(ContractDefinition& _contract) { - bytes assembled; - assembled.reserve(m_assemblyItems.size()); + m_context = CompilerContext(); // clear it just in case - // resolve label references - for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos) - { - AssemblyItem const& item = m_assemblyItems[pos]; - if (item.getType() == AssemblyItem::Type::LABEL) - m_context.setLabelPosition(item.getLabel(), pos + 1); - } + //@todo constructor + //@todo register state variables - 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()); - } - - return assembled; + for (ASTPointer const& function: _contract.getDefinedFunctions()) + m_context.addFunction(*function); + appendFunctionSelector(_contract.getDefinedFunctions()); + for (ASTPointer const& function: _contract.getDefinedFunctions()) + function->accept(*this); } -AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context, - Expression& _expression) +void Compiler::appendFunctionSelector(std::vector> const&) { - ExpressionCompiler compiler(_context); - compiler.compile(_expression); - return compiler.getAssemblyItems(); + // filter public functions, and sort by name. Then select function from first byte, + // unpack arguments from calldata, push to stack and jump. Pack return values to + // output and return. } -bool ExpressionCompiler::visit(Assignment& _assignment) +bool Compiler::visit(FunctionDefinition& _function) { - m_currentLValue = nullptr; - _assignment.getLeftHandSide().accept(*this); + //@todo to simplify this, the colling 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 - Expression& rightHandSide = _assignment.getRightHandSide(); - Token::Value op = _assignment.getAssignmentOperator(); - if (op != Token::ASSIGN) - { - // compound assignment - rightHandSide.accept(*this); - Type const& resultType = *_assignment.getType(); - cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); - appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); - } - else - { - append(eth::Instruction::POP); //@todo do not retrieve the value in the first place - rightHandSide.accept(*this); - } + m_context.startNewFunction(); + m_returnTag = m_context.newTag(); + m_breakTags.clear(); + m_continueTags.clear(); - 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: // ! - append(eth::Instruction::NOT); - break; - case Token::BIT_NOT: // ~ - append(eth::Instruction::BNOT); - break; - case Token::DELETE: // delete - { - // a -> a xor a (= 0). - // @todo semantics change for complex types - append(eth::Instruction::DUP1); - append(eth::Instruction::XOR); - storeInLValue(_unaryOperation); - break; - } - case Token::INC: // ++ (pre- or postfix) - case Token::DEC: // -- (pre- or postfix) - if (!_unaryOperation.isPrefixOperation()) - append(eth::Instruction::DUP1); - append(eth::Instruction::PUSH1); - append(1); - if (_unaryOperation.getOperator() == Token::INC) - append(eth::Instruction::ADD); - else - { - append(eth::Instruction::SWAP1); //@todo avoid this - append(eth::Instruction::SUB); - } - if (_unaryOperation.isPrefixOperation()) - storeInLValue(_unaryOperation); - else - moveToLValue(_unaryOperation); - break; - case Token::ADD: // + - // unary add, so basically no-op - break; - case Token::SUB: // - - append(eth::Instruction::PUSH1); - append(0); - append(eth::Instruction::SUB); - break; - default: - assert(false); // invalid operation - } -} + m_context << m_context.getFunctionEntryLabel(_function); -bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) -{ - Expression& leftExpression = _binaryOperation.getLeftExpression(); - Expression& rightExpression = _binaryOperation.getRightExpression(); - Type const& resultType = *_binaryOperation.getType(); - Token::Value const op = _binaryOperation.getOperator(); + // stack upon entry: [return address] [arg0] [arg1] ... [argn] + // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] - if (op == Token::AND || op == Token::OR) - { - // special case: short-circuiting - appendAndOrOperatorCode(_binaryOperation); - } - else if (Token::isCompareOp(op)) - { - leftExpression.accept(*this); - rightExpression.accept(*this); + unsigned const numArguments = _function.getParameters().size(); + unsigned const numReturnValues = _function.getReturnParameters().size(); + unsigned const numLocalVariables = _function.getLocalVariables().size(); - // 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); - } + 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); - // do not visit the child nodes, we already did that explicitly - return false; -} + _function.getBody().accept(*this); -void ExpressionCompiler::endVisit(FunctionCall& _functionCall) -{ - if (_functionCall.isTypeConversion()) - { - //@todo we only have integers and bools for now which cannot be explicitly converted - assert(_functionCall.getArguments().size() == 1); - cleanHigherOrderBitsIfNeeded(*_functionCall.getArguments().front()->getType(), - *_functionCall.getType()); - } - else - { - //@todo: arguments are already on the stack - // push return label (below arguments?) - // jump to function label - // discard all but the first function return argument - } -} + m_context << m_returnTag; -void ExpressionCompiler::endVisit(MemberAccess&) -{ + // 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. -} + 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); -void ExpressionCompiler::endVisit(IndexAccess&) -{ + 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()); + } -} + m_context << eth::Instruction::JUMP; -void ExpressionCompiler::endVisit(Identifier& _identifier) -{ - m_currentLValue = _identifier.getReferencedDeclaration(); - 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.")); - appendDup(stackPos + 1); + return false; } -void ExpressionCompiler::endVisit(Literal& _literal) +bool Compiler::visit(IfStatement& _ifStatement) { - 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()); - appendPush(value.size()); - append(value); - break; - } - default: - assert(false); // @todo - } + 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::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, const Type& _targetType) +bool Compiler::visit(WhileStatement& _whileStatement) { - // 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. - } -} + eth::AssemblyItem loopStart = m_context.newTag(); + eth::AssemblyItem loopEnd = m_context.newTag(); + m_continueTags.push_back(loopStart); + m_breakTags.push_back(loopEnd); -void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) -{ - 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); -} + m_context << loopStart; + ExpressionCompiler::compileExpression(m_context, _whileStatement.getCondition()); + m_context << eth::Instruction::NOT; + m_context.appendConditionalJumpTo(loopEnd); -void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) -{ - 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(); + _whileStatement.getBody().accept(*this); - // 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.appendJumpTo(loopStart); + m_context << loopEnd; -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 - assert(false); // unknown binary operator + m_continueTags.pop_back(); + m_breakTags.pop_back(); + return false; } -void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +bool Compiler::visit(Continue&) { - 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(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); - break; - case Token::MOD: - append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); - break; - default: - assert(false); - } + assert(!m_continueTags.empty()); + m_context.appendJumpTo(m_continueTags.back()); + return false; } -void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) +bool Compiler::visit(Break&) { - switch (_operator) - { - 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); - } + assert(!m_breakTags.empty()); + m_context.appendJumpTo(m_breakTags.back()); + return false; } -void ExpressionCompiler::appendShiftOperatorCode(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::SHL: - assert(false); //@todo - break; - case Token::SAR: - assert(false); //@todo - 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; } -uint32_t ExpressionCompiler::appendConditionalJump() -{ - uint32_t label = m_context.dispenseNewLabel(); - append(eth::Instruction::PUSH1); - appendLabelref(label); - append(eth::Instruction::JUMPI); - return label; -} - -void ExpressionCompiler::appendPush(unsigned _number) -{ - assert(1 <= _number && _number <= 32); - append(eth::Instruction(unsigned(eth::Instruction::PUSH1) + _number - 1)); -} - -void ExpressionCompiler::appendDup(unsigned _number) -{ - assert(1 <= _number && _number <= 16); - append(eth::Instruction(unsigned(eth::Instruction::DUP1) + _number - 1)); -} - -void ExpressionCompiler::appendSwap(unsigned _number) -{ - assert(1 <= _number && _number <= 16); - append(eth::Instruction(unsigned(eth::Instruction::SWAP1) + _number - 1)); -} - -void ExpressionCompiler::append(bytes const& _data) -{ - m_assemblyItems.reserve(m_assemblyItems.size() + _data.size()); - for (byte b: _data) - append(b); -} - -void ExpressionCompiler::storeInLValue(Expression const& _expression) -{ - assert(m_currentLValue); - moveToLValue(_expression); - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - if (stackPos >= 1) - appendDup(stackPos); -} - -void ExpressionCompiler::moveToLValue(Expression const& _expression) +bool Compiler::visit(VariableDefinition& _variableDefinition) { - assert(m_currentLValue); - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - else if (stackPos > 0) + if (Expression* expression = _variableDefinition.getExpression()) { - appendSwap(stackPos); - append(eth::Instruction::POP); + 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; } -unsigned ExpressionCompiler::stackPositionOfLValue() const +bool Compiler::visit(ExpressionStatement& _expressionStatement) { - return 8; // @todo ask the context and track stack changes due to m_assemblyItems + 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 1c5523e08..2ffaaa8d0 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -20,133 +20,40 @@ * Solidity AST to EVM bytecode compiler. */ -#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 +class Compiler: private ASTVisitor { 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; } + /// Compile the given contract and return the EVM bytecode. + static bytes compile(ContractDefinition& _contract); 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 + Compiler(): m_returnTag(m_context.newTag()) {} + + void compileContract(ContractDefinition& _contract); + void appendFunctionSelector(const std::vector >& _functions); + + 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; + + bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } + + 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 }; -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 -{ -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; - -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_currentLValue(nullptr), m_context(_compilerContext) {} - - /// 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); - -private: - virtual bool visit(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(); - void appendPush(unsigned _number); - void appendDup(unsigned _number); - void appendSwap(unsigned _number); - - /// 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)); } - - /// 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; - AssemblyItems m_assemblyItems; - CompilerContext& m_context; -}; - - } } diff --git a/libsolidity/CompilerUtilities.cpp b/libsolidity/CompilerUtilities.cpp new file mode 100644 index 000000000..b8f57618b --- /dev/null +++ b/libsolidity/CompilerUtilities.cpp @@ -0,0 +1,60 @@ +/* + 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 +#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(const Declaration& _declaration) +{ + auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); + assert(res != m_localVariables.end()); + return end(m_localVariables) - res - 1 + m_asm.deposit(); +} + +eth::AssemblyItem CompilerContext::getFunctionEntryLabel(const FunctionDefinition& _function) const +{ + auto res = m_functionEntryLabels.find(&_function); + assert(res != m_functionEntryLabels.end()); + return res->second.tag(); +} + +} +} diff --git a/libsolidity/CompilerUtilities.h b/libsolidity/CompilerUtilities.h new file mode 100644 index 000000000..90367903b --- /dev/null +++ b/libsolidity/CompilerUtilities.h @@ -0,0 +1,83 @@ +/* + 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 + +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(); } + + /// 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; } + + bytes getAssembledBytecode() { 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/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp new file mode 100644 index 000000000..76fcc2982 --- /dev/null +++ b/libsolidity/ExpressionCompiler.cpp @@ -0,0 +1,408 @@ +/* + 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::NOT; + break; + case Token::BIT_NOT: // ~ + m_context << eth::Instruction::BNOT; + 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: + assert(false); // invalid operation + } +} + +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 + 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); + } + + // 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 + assert(_functionCall.getArguments().size() == 1); + 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); + assert(function); + + eth::AssemblyItem returnLabel = m_context.pushNewTag(); + std::vector> const& arguments = _functionCall.getArguments(); + assert(arguments.size() == function->getParameters().size()); + 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: + assert(false); // @todo + } +} + +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. + } +} + +void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) +{ + Token::Value const op = _binaryOperation.getOperator(); + assert(op == Token::OR || op == Token::AND); + + _binaryOperation.getLeftExpression().accept(*this); + m_context << eth::Instruction::DUP1; + if (op == Token::AND) + m_context << eth::Instruction::NOT; + eth::AssemblyItem endLabel = m_context.appendConditionalJump(); + _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::NOT; + } + else + { + IntegerType const* type = dynamic_cast(&_type); + assert(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::NOT; + break; + case Token::LTE: + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) + << eth::Instruction::NOT; + 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: + assert(false); + } + } +} + +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 + assert(false); // unknown binary operator +} + +void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +{ + IntegerType const* type = dynamic_cast(&_type); + assert(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 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + break; + case Token::MOD: + m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + break; + default: + assert(false); + } +} + +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: + assert(false); + } +} + +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +{ + switch (_operator) + { + case Token::SHL: + assert(false); //@todo + break; + case Token::SAR: + assert(false); //@todo + break; + default: + assert(false); + } +} + +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 +{ + assert(m_currentLValue); + return m_context.getStackPositionOfVariable(*m_currentLValue); +} + +} +} diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h new file mode 100644 index 000000000..28a04f525 --- /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 +#include + +namespace dev { +namespace solidity { + +/// 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; + void adjustStackOffset(eth::Instruction _instruction); + + Declaration* m_currentLValue; + CompilerContext& m_context; +}; + + +} +} diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 9626ca848..4b77ed132 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -55,12 +55,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 +71,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,27 +109,33 @@ 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. + assert(m_currentFunction); + 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); diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 7abcbb0c5..cdc334a6e 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -41,6 +41,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: @@ -48,7 +56,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; }; @@ -58,7 +66,7 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); + DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); private: bool visit(ContractDefinition& _contract); @@ -67,15 +75,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; }; //! Resolves references to declarations (of variables and types) and also establishes the link diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 1ea413ee9..6ef6ebc31 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -266,9 +266,11 @@ ASTPointer Parser::parseStatement() // starting from here, all statements must be terminated by a semicolon case Token::CONTINUE: statement = ASTNodeFactory(*this).createNode(); + m_scanner->next(); break; case Token::BREAK: statement = ASTNodeFactory(*this).createNode(); + m_scanner->next(); break; case Token::RETURN: { @@ -283,9 +285,9 @@ 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 || @@ -293,8 +295,8 @@ ASTPointer Parser::parseStatement() (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; @@ -349,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); @@ -453,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/Types.cpp b/libsolidity/Types.cpp index 05b12df09..165787c56 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -159,14 +159,12 @@ std::string IntegerType::toString() const return prefix + dev::toString(m_bits); } -bytes IntegerType::literalToBigEndian(const Literal& _literal) const +u256 IntegerType::literalValue(const Literal& _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 +180,14 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo); } -bytes BoolType::literalToBigEndian(const Literal& _literal) const +u256 BoolType::literalValue(const Literal& _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; + assert(false); } bool ContractType::operator==(const Type& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 4d56b5abb..828f48095 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -69,7 +69,7 @@ public: virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } virtual std::string toString() const = 0; - virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; } + virtual u256 literalValue(Literal const&) const { assert(false); } }; /// Any kind of integer type including hash and address. @@ -94,7 +94,7 @@ public: virtual bool operator==(Type const& _other) const override; 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; } @@ -122,7 +122,7 @@ public: } virtual std::string toString() const override { return "bool"; } - virtual bytes literalToBigEndian(Literal const& _literal) const override; + virtual u256 literalValue(Literal const& _literal) const override; }; /// The type of a contract instance, there is one distinct type for each contract definition. diff --git a/solc/main.cpp b/solc/main.cpp index 24f07d952..945b53db5 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -55,35 +55,6 @@ void version() 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) { string infile; @@ -143,13 +114,10 @@ int main(int argc, char** argv) dev::solidity::ASTPrinter printer(ast, sourceCode); printer.print(cout); - FirstExpressionExtractor extractor(*ast); - - CompilerContext context; - ExpressionCompiler compiler(context); + bytes instructions; try { - compiler.compile(*extractor.getExpression()); + instructions = Compiler::compile(*ast); } catch (CompilerError const& exception) { @@ -157,10 +125,9 @@ int main(int argc, char** argv) return -1; } - bytes instructions = compiler.getAssembledBytecode(); - - cout << "Bytecode for the first expression: " << endl; + cout << "EVM assembly: " << endl; cout << eth::disassemble(instructions) << endl; + cout << "Binary: " << toHex(instructions) << endl; return 0; } diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 591330dd6..c9cf464d9 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -18,7 +18,7 @@ /** * @author Christian * @date 2014 - * Unit tests for the name and type resolution of the solidity parser. + * Unit tests for the solidity compiler. */ #include @@ -31,6 +31,9 @@ #include #include +using namespace std; +using namespace dev::eth; + namespace dev { namespace solidity @@ -41,233 +44,167 @@ 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(const std::string& _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(); + bytes instructions = Compiler::compile(*contract); // debug - //std::cout << eth::disassemble(instructions) << std::endl; + //cout << eth::disassemble(instructions) << endl; return instructions; } } // end anonymous namespace -BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) +BOOST_AUTO_TEST_SUITE(SolidityCompiler) -BOOST_AUTO_TEST_CASE(literal_true) +BOOST_AUTO_TEST_CASE(smoke_test) { char const* sourceCode = "contract test {\n" - " function f() { var x = true; }" + " function f() { var x = 2; }\n" "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); + bytes code = compileContract(sourceCode); + + 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)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } -BOOST_AUTO_TEST_CASE(literal_false) +BOOST_AUTO_TEST_CASE(different_argument_numbers) { char const* sourceCode = "contract test {\n" - " function f() { var x = false; }" + " 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), 0x0}); + bytes code = compileContract(sourceCode); + + 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), 0xa, // 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), 0x20, // ret address + byte(Instruction::PUSH1), 0x1, + byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x3, + byte(Instruction::PUSH1), 0x1, + // 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 + }); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } -BOOST_AUTO_TEST_CASE(int_literal) +BOOST_AUTO_TEST_CASE(ifStatement) { char const* sourceCode = "contract test {\n" - " function f() { var x = 0x12345678901234567890; }" + " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" "}\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::NOT)}); - 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::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()); -} - -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::MOD), - 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::BNOT), - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT)}); - 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); - - bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking - byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::ADD), - byte(eth::Instruction::SWAP8), // will change - byte(eth::Instruction::POP), // first ++ - byte(eth::Instruction::DUP9), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::ADD), - byte(eth::Instruction::SWAP8), // will change - byte(eth::Instruction::POP), // second ++ - byte(eth::Instruction::DUP8), // will change - byte(eth::Instruction::XOR), - byte(eth::Instruction::DUP9), // will change - byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::SUB), - byte(eth::Instruction::SWAP8), // will change - byte(eth::Instruction::POP), // first -- - byte(eth::Instruction::XOR), - byte(eth::Instruction::DUP9), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::SUB), - byte(eth::Instruction::SWAP8), // will change - byte(eth::Instruction::POP), // second ++ - byte(eth::Instruction::DUP8), // will change - byte(eth::Instruction::XOR)}); + bytes code = compileContract(sourceCode); + + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x0, + byte(Instruction::DUP1), + byte(Instruction::PUSH1), 0x1b, // "true" target + byte(Instruction::JUMPI), + // new check "else if" condition + byte(Instruction::DUP1), + byte(Instruction::NOT), + byte(Instruction::PUSH1), 0x13, + byte(Instruction::JUMPI), + // "else" body + byte(Instruction::PUSH1), 0x4f, + byte(Instruction::POP), + byte(Instruction::PUSH1), 0x17, // 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), 0x1f, + 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)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } -BOOST_AUTO_TEST_CASE(assignment) +BOOST_AUTO_TEST_CASE(loops) { char const* sourceCode = "contract test {\n" - " function f(uint a, uint b) { (a += b) * 2; }" + " function f() { while(true){1;break;2;continue;3;return;4;} }" "}\n"; - bytes code = compileFirstExpression(sourceCode); + bytes code = compileContract(sourceCode); + + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x1, + byte(Instruction::NOT), + byte(Instruction::PUSH1), 0x21, + byte(Instruction::JUMPI), + byte(Instruction::PUSH1), 0x1, + byte(Instruction::POP), + byte(Instruction::PUSH1), 0x21, + byte(Instruction::JUMP), // break + byte(Instruction::PUSH1), 0x2, + byte(Instruction::POP), + byte(Instruction::PUSH1), 0x2, + byte(Instruction::JUMP), // continue + byte(Instruction::PUSH1), 0x3, + byte(Instruction::POP), + byte(Instruction::PUSH1), 0x22, + byte(Instruction::JUMP), // return + byte(Instruction::PUSH1), 0x4, + byte(Instruction::POP), + byte(Instruction::PUSH1), 0x2, + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + byte(Instruction::JUMPDEST), + byte(Instruction::JUMP)}); - bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking - byte(eth::Instruction::DUP9), - byte(eth::Instruction::ADD), - byte(eth::Instruction::SWAP8), // will change - byte(eth::Instruction::POP), // first ++ - byte(eth::Instruction::DUP8), - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp new file mode 100644 index 000000000..2a58d670a --- /dev/null +++ b/test/solidityExpressionCompiler.cpp @@ -0,0 +1,348 @@ + +/* + 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 + +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::NOT)}); + 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::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()); +} + +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::MOD), + 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::BNOT), + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT)}); + 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), 0x0b, + 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), 0x15, + 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 025cd74d1..701a6e76c 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(while_loop) { char const* text = "contract test {\n" " function fun(uint256 a) {\n" - " uint256 x = (1 + 4).member(++67) || true;\n" + " while (true) { uint256 x = 1; break; continue; } x = 9;\n" " }\n" "}\n"; BOOST_CHECK_NO_THROW(parseText(text)); From 6f3afc8583b73e020135701d3df8cf5e24c18fb3 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 12:42:04 +0100 Subject: [PATCH 14/77] Renamed file. --- libsolidity/Compiler.h | 2 +- libsolidity/{CompilerUtilities.cpp => CompilerContext.cpp} | 0 libsolidity/{CompilerUtilities.h => CompilerContext.h} | 0 libsolidity/ExpressionCompiler.cpp | 1 + libsolidity/ExpressionCompiler.h | 4 ++-- test/solidityExpressionCompiler.cpp | 1 + 6 files changed, 5 insertions(+), 3 deletions(-) rename libsolidity/{CompilerUtilities.cpp => CompilerContext.cpp} (100%) rename libsolidity/{CompilerUtilities.h => CompilerContext.h} (100%) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 2ffaaa8d0..5f6d9b4e9 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -21,7 +21,7 @@ */ #include -#include +#include namespace dev { namespace solidity { diff --git a/libsolidity/CompilerUtilities.cpp b/libsolidity/CompilerContext.cpp similarity index 100% rename from libsolidity/CompilerUtilities.cpp rename to libsolidity/CompilerContext.cpp diff --git a/libsolidity/CompilerUtilities.h b/libsolidity/CompilerContext.h similarity index 100% rename from libsolidity/CompilerUtilities.h rename to libsolidity/CompilerContext.h diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 76fcc2982..53d2d95d9 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace std; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 28a04f525..a930723cc 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -21,11 +21,12 @@ */ #include -#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. @@ -68,7 +69,6 @@ private: 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; - void adjustStackOffset(eth::Instruction _instruction); Declaration* m_currentLValue; CompilerContext& m_context; diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 2a58d670a..252d2c15e 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include From 4d654d4e78408a9bb7837604e0efc22d73c7a15b Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 18:15:25 +0100 Subject: [PATCH 15/77] Function selector and variable (un)packing. --- libsolidity/Compiler.cpp | 100 ++++++++++++++++++++++++++++++++-- libsolidity/Compiler.h | 16 ++++-- libsolidity/CompilerContext.h | 4 +- libsolidity/Types.h | 8 +++ solc/main.cpp | 8 ++- test/solidityCompiler.cpp | 58 +++++++++++++------- 6 files changed, 160 insertions(+), 34 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index fea885607..7e40db15f 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -51,16 +51,106 @@ void Compiler::compileContract(ContractDefinition& _contract) function->accept(*this); } -void Compiler::appendFunctionSelector(std::vector> const&) +void Compiler::appendFunctionSelector(vector> const& _functions) { - // filter public functions, and sort by name. Then select function from first byte, - // unpack arguments from calldata, push to stack and jump. Pack return values to - // output and return. + // 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::RETURN; + + for (pair> const& f: publicFunctions) + { + m_context << f.second.second; + appendFunctionCallSection(*f.second.first); + } +} + +void Compiler::appendFunctionCallSection(FunctionDefinition const& _function) +{ + eth::AssemblyItem returnTag = m_context.pushNewTag(); + + appendCalldataUnpacker(_function); + + m_context.appendJumpTo(m_context.getFunctionEntryLabel(_function)); + m_context << returnTag; + + appendReturnValuePacker(_function); +} + +void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function) +{ + // We do not check the calldata size, everything is zero-padded. + unsigned dataOffset = 1; + + //@todo this can be done more efficiently, saving some CALLDATALOAD calls + for (ASTPointer const& var: _function.getParameters()) + { + 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; + } +} + +void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) +{ + //@todo this can be also done more efficiently + unsigned dataOffset = 0; + vector> const& parameters = _function.getReturnParameters(); + for (unsigned i = 0 ; i < parameters.size(); ++i) + { + 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(dataOffset) << eth::Instruction::MSTORE; + else + m_context << u256(dataOffset) << (u256(1) << ((32 - numBytes) * 8)) + << eth::Instruction::MUL << eth::Instruction::MSTORE; + dataOffset += numBytes; + } + // note that the stack is not cleaned up here + m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; } bool Compiler::visit(FunctionDefinition& _function) { - //@todo to simplify this, the colling convention could by changed such that + //@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 diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 5f6d9b4e9..ebd786658 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -20,6 +20,7 @@ * Solidity AST to EVM bytecode compiler. */ +#include #include #include @@ -29,14 +30,20 @@ namespace solidity { class Compiler: private ASTVisitor { public: + Compiler(): m_returnTag(m_context.newTag()) {} + + void compileContract(ContractDefinition& _contract); + bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } + void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } + /// Compile the given contract and return the EVM bytecode. static bytes compile(ContractDefinition& _contract); private: - Compiler(): m_returnTag(m_context.newTag()) {} - - void compileContract(ContractDefinition& _contract); - void appendFunctionSelector(const std::vector >& _functions); + void appendFunctionSelector(std::vector > const& _functions); + void appendFunctionCallSection(FunctionDefinition const& _function); + void appendCalldataUnpacker(FunctionDefinition const& _function); + void appendReturnValuePacker(FunctionDefinition const& _function); virtual bool visit(FunctionDefinition& _function) override; virtual bool visit(IfStatement& _ifStatement) override; @@ -47,7 +54,6 @@ private: virtual bool visit(VariableDefinition& _variableDefinition) override; virtual bool visit(ExpressionStatement& _expressionStatement) override; - bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } CompilerContext m_context; std::vector m_breakTags; ///< tag to jump to for a "break" statement diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 90367903b..cce5838ef 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -69,7 +70,8 @@ public: CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } - bytes getAssembledBytecode() { return m_asm.assemble(); } + void streamAssembly(std::ostream& _stream) const { _stream << m_asm; } + bytes getAssembledBytecode() const { return m_asm.assemble(); } private: eth::Assembly m_asm; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 828f48095..d7c3b241f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -68,6 +68,10 @@ 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 u256 literalValue(Literal const&) const { assert(false); } }; @@ -93,6 +97,8 @@ public: virtual bool operator==(Type const& _other) const override; + virtual unsigned getCalldataEncodedSize() const { return m_bits / 8; } + virtual std::string toString() const override; virtual u256 literalValue(Literal const& _literal) const override; @@ -121,6 +127,8 @@ public: return _operator == Token::NOT || _operator == Token::DELETE; } + virtual unsigned getCalldataEncodedSize() const { return 1; } + virtual std::string toString() const override { return "bool"; } virtual u256 literalValue(Literal const& _literal) const override; }; diff --git a/solc/main.cpp b/solc/main.cpp index 945b53db5..1cf466c72 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -115,9 +115,11 @@ int main(int argc, char** argv) printer.print(cout); bytes instructions; + Compiler compiler; try { - instructions = Compiler::compile(*ast); + compiler.compileContract(*ast); + instructions = compiler.getAssembledBytecode(); } catch (CompilerError const& exception) { @@ -125,7 +127,9 @@ int main(int argc, char** argv) return -1; } - cout << "EVM assembly: " << endl; + cout << "EVM assembly:" << endl; + compiler.streamAssembly(cout); + cout << "Opcodes:" << endl; cout << eth::disassemble(instructions) << endl; cout << "Binary: " << toHex(instructions) << endl; diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index c9cf464d9..4272354c3 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -22,14 +22,14 @@ */ #include - +#include +#include #include #include #include #include #include #include -#include using namespace std; using namespace dev::eth; @@ -52,10 +52,22 @@ bytes compileContract(const string& _sourceCode) NameAndTypeResolver resolver; BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); - bytes instructions = Compiler::compile(*contract); + Compiler compiler; + compiler.compileContract(*contract); // debug - //cout << eth::disassemble(instructions) << endl; - return instructions; + //compiler.streamAssembly(cout); + return compiler.getAssembledBytecode(); +} + +/// 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) +{ + BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); + auto checkStart = _compiledCode.begin() + _offset; + BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), + _expectation.begin(), _expectation.end()); } } // end anonymous namespace @@ -69,6 +81,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) "}\n"; bytes code = compileContract(sourceCode); + unsigned boilerplateSize = 39; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x2, @@ -77,7 +90,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) byte(Instruction::JUMPDEST), byte(Instruction::POP), byte(Instruction::JUMP)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + checkCodePresentAt(code, expectation, boilerplateSize); } BOOST_AUTO_TEST_CASE(different_argument_numbers) @@ -88,12 +101,13 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) "}\n"; bytes code = compileContract(sourceCode); + unsigned boilerplateSize = 76; 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), 0xa, // jump to return + byte(Instruction::PUSH1), 0xa + boilerplateSize, // jump to return byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::SWAP4), // store d and fetch return address @@ -105,11 +119,11 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), // initialized e and h - byte(Instruction::PUSH1), 0x20, // ret address + byte(Instruction::PUSH1), 0x20 + boilerplateSize, // ret address byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x3, - byte(Instruction::PUSH1), 0x1, + byte(Instruction::PUSH1), 0x1 + boilerplateSize, // stack here: ret e h 0x20 1 2 3 0x1 byte(Instruction::JUMP), byte(Instruction::JUMPDEST), @@ -129,7 +143,7 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) // f(1,2,3) e ret byte(Instruction::JUMP) // end of g }); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + checkCodePresentAt(code, expectation, boilerplateSize); } BOOST_AUTO_TEST_CASE(ifStatement) @@ -139,27 +153,28 @@ BOOST_AUTO_TEST_CASE(ifStatement) "}\n"; bytes code = compileContract(sourceCode); + unsigned boilerplateSize = 39; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x1b, // "true" target + byte(Instruction::PUSH1), 0x1b + boilerplateSize, // "true" target byte(Instruction::JUMPI), // new check "else if" condition byte(Instruction::DUP1), byte(Instruction::NOT), - byte(Instruction::PUSH1), 0x13, + byte(Instruction::PUSH1), 0x13 + boilerplateSize, byte(Instruction::JUMPI), // "else" body byte(Instruction::PUSH1), 0x4f, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x17, // exit path of second part + byte(Instruction::PUSH1), 0x17 + boilerplateSize, // 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), 0x1f, + byte(Instruction::PUSH1), 0x1f + boilerplateSize, byte(Instruction::JUMP), // "if" body byte(Instruction::JUMPDEST), @@ -169,7 +184,7 @@ BOOST_AUTO_TEST_CASE(ifStatement) byte(Instruction::JUMPDEST), byte(Instruction::POP), byte(Instruction::JUMP)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + checkCodePresentAt(code, expectation, boilerplateSize); } BOOST_AUTO_TEST_CASE(loops) @@ -179,33 +194,34 @@ BOOST_AUTO_TEST_CASE(loops) "}\n"; bytes code = compileContract(sourceCode); + unsigned boilerplateSize = 39; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, byte(Instruction::NOT), - byte(Instruction::PUSH1), 0x21, + byte(Instruction::PUSH1), 0x21 + boilerplateSize, byte(Instruction::JUMPI), byte(Instruction::PUSH1), 0x1, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x21, + byte(Instruction::PUSH1), 0x21 + boilerplateSize, byte(Instruction::JUMP), // break byte(Instruction::PUSH1), 0x2, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x2 + boilerplateSize, byte(Instruction::JUMP), // continue byte(Instruction::PUSH1), 0x3, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x22, + byte(Instruction::PUSH1), 0x22 + boilerplateSize, byte(Instruction::JUMP), // return byte(Instruction::PUSH1), 0x4, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x2 + boilerplateSize, byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::JUMP)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + checkCodePresentAt(code, expectation, boilerplateSize); } BOOST_AUTO_TEST_SUITE_END() From adcf06236704a103300b454cbd4af2c79396b12e Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 22:52:15 +0100 Subject: [PATCH 16/77] Actual contract creator and add solidity to AlethZero interface. --- alethzero/CMakeLists.txt | 2 +- alethzero/MainWin.cpp | 17 ++++++++++++ libsolidity/Compiler.cpp | 13 ++++++++++ libsolidity/Compiler.h | 2 ++ libsolidity/CompilerContext.h | 4 +++ libsolidity/CompilerStack.cpp | 49 +++++++++++++++++++++++++++++++++++ libsolidity/CompilerStack.h | 43 ++++++++++++++++++++++++++++++ libsolidity/Scanner.cpp | 5 ---- libsolidity/Scanner.h | 3 ++- test/solidityCompiler.cpp | 35 +++++++++++++------------ 10 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 libsolidity/CompilerStack.cpp create mode 100644 libsolidity/CompilerStack.h diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 4ad06f7a6..7f9cbb812 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) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmface devcore) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2853536b9..3c874d8a2 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -1560,6 +1563,20 @@ void Main::on_data_textChanged() { 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); + errors.push_back(error.str()); + } + } else { m_data = dev::eth::compileLLL(src, m_enableOptimizer, &errors); diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 7e40db15f..b1e3c3da3 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -46,9 +46,22 @@ void Compiler::compileContract(ContractDefinition& _contract) for (ASTPointer const& function: _contract.getDefinedFunctions()) m_context.addFunction(*function); + appendFunctionSelector(_contract.getDefinedFunctions()); for (ASTPointer const& function: _contract.getDefinedFunctions()) function->accept(*this); + + packIntoContractCreator(); +} + +void Compiler::packIntoContractCreator() +{ + 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); } void Compiler::appendFunctionSelector(vector> const& _functions) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index ebd786658..d10374a9b 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -40,6 +40,8 @@ public: static bytes compile(ContractDefinition& _contract); private: + /// Creates a new compiler context / assembly and packs the current code into the data part. + void packIntoContractCreator(); void appendFunctionSelector(std::vector > const& _functions); void appendFunctionCallSection(FunctionDefinition const& _function); void appendCalldataUnpacker(FunctionDefinition const& _function); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index cce5838ef..46c4c72ab 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -63,6 +63,9 @@ public: 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; } @@ -70,6 +73,7 @@ public: 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: 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/Scanner.cpp b/libsolidity/Scanner.cpp index 3148de52e..d8defb50a 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -103,11 +103,6 @@ int HexValue(char c) } } // end anonymous namespace -Scanner::Scanner(CharStream const& _source) -{ - reset(_source); -} - void Scanner::reset(CharStream const& _source) { m_source = _source; diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index fbaba9ed6..7754d71b4 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); diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 4272354c3..c0d4e32df 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 39; + unsigned boilerplateSize = 51; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x2, @@ -101,13 +101,14 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 76; + unsigned shift = 76; + 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), 0xa + boilerplateSize, // jump to return + byte(Instruction::PUSH1), 0xa + shift, // jump to return byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::SWAP4), // store d and fetch return address @@ -119,11 +120,11 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), // initialized e and h - byte(Instruction::PUSH1), 0x20 + boilerplateSize, // ret address + byte(Instruction::PUSH1), 0x20 + shift, // ret address byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x3, - byte(Instruction::PUSH1), 0x1 + boilerplateSize, + byte(Instruction::PUSH1), 0x1 + shift, // stack here: ret e h 0x20 1 2 3 0x1 byte(Instruction::JUMP), byte(Instruction::JUMPDEST), @@ -153,28 +154,29 @@ BOOST_AUTO_TEST_CASE(ifStatement) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 39; + unsigned shift = 39; + unsigned boilerplateSize = 51; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x1b + boilerplateSize, // "true" target + byte(Instruction::PUSH1), 0x1b + shift, // "true" target byte(Instruction::JUMPI), // new check "else if" condition byte(Instruction::DUP1), byte(Instruction::NOT), - byte(Instruction::PUSH1), 0x13 + boilerplateSize, + byte(Instruction::PUSH1), 0x13 + shift, byte(Instruction::JUMPI), // "else" body byte(Instruction::PUSH1), 0x4f, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x17 + boilerplateSize, // exit path of second part + byte(Instruction::PUSH1), 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), 0x1f + boilerplateSize, + byte(Instruction::PUSH1), 0x1f + shift, byte(Instruction::JUMP), // "if" body byte(Instruction::JUMPDEST), @@ -194,28 +196,29 @@ BOOST_AUTO_TEST_CASE(loops) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 39; + unsigned shift = 39; + unsigned boilerplateSize = 51; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, byte(Instruction::NOT), - byte(Instruction::PUSH1), 0x21 + boilerplateSize, + byte(Instruction::PUSH1), 0x21 + shift, byte(Instruction::JUMPI), byte(Instruction::PUSH1), 0x1, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x21 + boilerplateSize, + byte(Instruction::PUSH1), 0x21 + shift, byte(Instruction::JUMP), // break byte(Instruction::PUSH1), 0x2, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2 + boilerplateSize, + byte(Instruction::PUSH1), 0x2 + shift, byte(Instruction::JUMP), // continue byte(Instruction::PUSH1), 0x3, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x22 + boilerplateSize, + byte(Instruction::PUSH1), 0x22 + shift, byte(Instruction::JUMP), // return byte(Instruction::PUSH1), 0x4, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2 + boilerplateSize, + byte(Instruction::PUSH1), 0x2 + shift, byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), From 67747f8cc57dffb034a586c59183f4d694418317 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 2 Nov 2014 04:41:16 +0100 Subject: [PATCH 17/77] Placeholder kdf. More cleanup and tests. --- libdevcrypto/Common.cpp | 141 ++++++++++++++------------------------ libdevcrypto/Common.h | 17 +++-- libdevcrypto/CryptoPP.cpp | 80 +++------------------ libdevcrypto/CryptoPP.h | 34 ++++----- libdevcrypto/EC.cpp | 130 ++++++++++++++++++++++++++++++----- libdevcrypto/EC.h | 23 +++++-- libdevcrypto/FileSystem.h | 1 + test/crypto.cpp | 34 ++++----- 8 files changed, 238 insertions(+), 222 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index c7503a820..e763cc9b2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -14,51 +14,30 @@ 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 "EC.h" #include "SHA3.h" +#include "FileSystem.h" +#include "Common.h" using namespace std; using namespace dev; //#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); @@ -78,25 +57,10 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { - secp256k1_start(); - 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))); - + crypto::toPublic(m_secret, m_public); + if (crypto::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; @@ -129,54 +93,12 @@ 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; -} - -inline h256 kFromMessage(h256 _msg, h256 _priv) -{ - return _msg ^ _priv; + return crypto::recover(_sig, _message.ref()); } Signature dev::sign(Secret _k, h256 _hash) { - int v = 0; - - secp256k1_start(); - - SignatureStruct ret; - h256 nonce = kFromMessage(_hash, _k); - - if (!secp256k1_ecdsa_sign_compact(_hash.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 - - ret.v = v; - return *(Signature const*)&ret; + return crypto::sign(_k, _hash); } bool dev::verify(Public _p, Signature _s, h256 _hash) @@ -184,3 +106,40 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } +h256 Sec::getNonce(bool _commit) +{ + // todo: atomic efface bit, periodic save, kdf, rr, rng + static h256 seed; + static string seedFile(getDataDir() + "/seed"); + static mutex x; + lock_guard l(x); + { + if (!seed) + { + static Sec sec; + + bytes b = contents(seedFile); + if (b.size() == 32) + memcpy(seed.data(), b.data(), 32); + else + { + std::mt19937_64 s_eng(time(0)); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + seed[i] = (byte)d(s_eng); + } + writeFile(seedFile, bytes()); + } + assert(seed); + h256 prev(seed); + sha3(prev.ref(), seed.ref()); + if (_commit) + writeFile(seedFile, seed.asBytes()); + } + return seed; +} + +Sec::~Sec() +{ + Sec::getNonce(true); +} diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index bd9a4fbd4..e163fb1c4 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. @@ -63,8 +64,8 @@ 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 _hash); @@ -109,5 +110,13 @@ private: Public m_public; Address m_address; }; + +struct Sec +{ + static h256 getNonce(bool _commit = false); +private: + Sec() {} + ~Sec(); +}; -} +} \ No newline at end of file diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index fa45e6242..1b51d5bd5 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,85 +25,21 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -/// Conversion from bytes to cryptopp point -inline ECP::Point publicToPoint(Public const& _p); -/// Conversion from bytes to cryptopp exponent -inline Integer secretToExponent(Secret const& _s); - -/// Conversion from cryptopp exponent Integer to bytes -inline void exponentToPublic(Integer const& _e, Public& _p); - -void pp::initializeSigner(Secret const& _s, ECDSA::Signer& _signer) -{ - _signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _signer.AccessKey().SetPrivateExponent(secretToExponent(_s)); -} - -void pp::initializeVerifier(Public const& _p, ECDSA::Verifier& _verifier) -{ - _verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _verifier.AccessKey().SetPublicElement(publicToPoint(_p)); -} - -void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& _encryptor) -{ - _encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _encryptor.AccessKey().SetPublicElement(publicToPoint(_p)); -} - -void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& _decryptor) -{ - _decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s)); -} +/// Integer and Point Conversion: 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::exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +void pp::exponentToPublic(Integer const& _e, Public& _p) { - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); -} - -/// Integer and Point Conversion: - -inline ECP::Point publicToPoint(Public const& _p) -{ - ECP::Point p; - CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1Curve); - - 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); -} - -inline Integer secretToExponent(Secret const& _s) -{ - static_assert(Secret::size == 32, "Secret key must be 32 bytes."); - return std::move(Integer(_s.data(), Secret::size)); -} - -inline void exponentToPublic(Integer const& _e, Public& _p) -{ - CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(pp::secp256k1Curve); - k.SetPrivateExponent(_e); - - CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(pp::secp256k1Curve); - k.MakePublicKey(p); - pp::exportPublicKey(p, _p); -} + 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 e7a5ea94c..756bbb72a 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,6 @@ #include #include #include -#include #include #pragma warning(pop) #pragma GCC diagnostic pop @@ -55,34 +54,35 @@ 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(); - -/// Initialize signer with Secret -void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); -/// Initialize verifier with Public -void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); +static const CryptoPP::DL_GroupParameters_EC secp256k1Params(secp256k1Curve); -/// Initialize cryptopp encryptor with Public -void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); +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)); } -/// Initialize cryptopp decryptor with Secret -void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); +static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } + +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); -/// Conversion from cryptopp public key to bytes -void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& out_p); +static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } -/// Conversion from cryptopp private key to bytes -void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& out_s); +void exponentToPublic(Integer const& _e, Public& _p); +template +void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_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 d6c2ad622..e6b4c19c8 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * Shared EC classes and functions. + * ECDSA, ECIES */ #pragma warning(push) @@ -32,25 +32,44 @@ #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 crypto::encrypt(Public const& _key, bytes& io_cipher) +h256 crypto::kdf(Secret const& _priv, h256 const& _hash) +{ + h256 s; + sha3mac(Sec::getNonce().ref(), _priv.ref(), s.ref()); + assert(s); + return sha3((_hash ^ s).asBytes()); +} + +void crypto::encrypt(Public const& _k, bytes& io_cipher) { ECIES::Encryptor e; - pp::initializeEncryptor(_key, e); + initializeDLScheme(_k, e); size_t plen = io_cipher.size(); bytes c; c.resize(e.CiphertextLength(plen)); // todo: use StringSource with io_cipher as input and output. - e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); + e.Encrypt(PRNG, io_cipher.data(), plen, c.data()); memset(io_cipher.data(), 0, io_cipher.size()); io_cipher = std::move(c); } @@ -58,12 +77,12 @@ void crypto::encrypt(Public const& _key, bytes& io_cipher) void crypto::decrypt(Secret const& _k, bytes& io_text) { CryptoPP::ECIES::Decryptor d; - pp::initializeDecryptor(_k, d); + initializeDLScheme(_k, d); size_t clen = io_text.size(); bytes p; p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with io_text as input and output. - DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); + DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data()); if (!r.isValidCoding) { io_text.clear(); @@ -75,19 +94,51 @@ void crypto::decrypt(Secret const& _k, bytes& io_text) Signature crypto::sign(Secret const& _k, bytesConstRef _message) { - ECDSA::Signer signer; - pp::initializeSigner(_k, signer); + 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 e(_hash.asBytes().data(), 32); + + Integer k(kdf(_key, _hash).data(), 32); + k %= secp256k1Params.GetSubgroupOrder()-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 > secp256k1Params.GetSubgroupOrder()) + { + 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; +} - string sigstr; - StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); - FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); - return std::move(retsig); +bool crypto::verify(Signature const& _signature, bytesConstRef _message) +{ + return crypto::verify(crypto::recover(_signature, _message), _signature, _message); } -bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) +bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) { static size_t derMaxEncodingLength = 72; - if (_raw) + if (_hashed) { assert(_message.size() == 32); byte encpub[65] = {0x04}; @@ -99,10 +150,53 @@ bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw } ECDSA::Verifier verifier; - pp::initializeVerifier(_p, verifier); - // cryptopp signatures are 64 bytes - static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); + initializeDLScheme(_p, verifier); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); } +Public crypto::recover(Signature _signature, bytesConstRef _message) +{ + secp256k1_start(); + + byte pubkey[65]; + int pubkeylen = 65; + 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; + + byte pubkey[65]; + int pubkeylen = 65; + 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 d98472a54..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,18 +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 hash. +/// 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 signature -bool verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw = false); +/// 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/test/crypto.cpp b/test/crypto.cpp index e11659ed0..ab384a038 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) 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::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); @@ -82,7 +82,13 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Public p; pp::exportPublicKey(e.GetKey(), p); - BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + h160 secp256k1Addr = dev::toAddress(s); + h160 cryptoppAddr = right160(dev::sha3(p.ref())); + if (secp256k1Addr != cryptoppAddr) + { + BOOST_REQUIRE(secp256k1Addr == cryptoppAddr); + break; + } } } @@ -94,30 +100,29 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) 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 = 15; // Oct 29: successful @ 1500 + int tests = 2; // Oct 29: successful @ 1500 while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) { KeyPair key(secret); Public pkey = key.pub(); - pp::initializeSigner(secret, signer); + pp::initializeDLScheme(secret, signer); h256 he(sha3(e)); Integer heInt(he.asBytes().data(), 32); - h256 k(he ^ secret); + h256 k(crypto::kdf(secret, he)); Integer kInt(k.asBytes().data(), 32); - - const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); + 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); - BOOST_REQUIRE(!(r >= q)); Integer kInv = kInt.InverseMod(q); Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; @@ -164,7 +169,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) KeyPair key(secret); bytes m(fromHex("0x01")); - int tests = 5; + int tests = 2; while (m[0]++, tests--) { h256 hm(sha3(m)); @@ -174,27 +179,26 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) ECDSA::Signer signer; - pp::initializeSigner(key.sec(), 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::initializeVerifier(key.pub(), 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)); - BOOST_CHECK(dev::recover(sigppraw, hm) == key.pub()); - // sign with sec256lib, verify with cryptopp + // 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_CHECK(dev::recover(seclibsig, hm) == key.pub()); + BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); // sign with cryptopp (w/hash filter?), verify with cryptopp bytes sigppb(signer.MaxSignatureLength()); @@ -204,7 +208,6 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) 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)); - BOOST_CHECK(dev::recover(sigpp, hm) == key.pub()); // sign with cryptopp and stringsource hash filter string sigstr; @@ -213,7 +216,6 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) 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)); - BOOST_CHECK(dev::recover(retsig, hm) == key.pub()); /// verification w/sec256lib // requires public key and sig in standard format From 482a1241f78a221e255b9d4cc0700c0fdb30429b Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 2 Nov 2014 15:05:40 +0100 Subject: [PATCH 18/77] rename nonce generator --- libdevcrypto/Common.cpp | 18 +++++++++--------- libdevcrypto/Common.h | 16 +++++++++++----- libdevcrypto/EC.cpp | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index e763cc9b2..f039435ad 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -28,6 +28,7 @@ #include "Common.h" using namespace std; using namespace dev; +using namespace crypto; //#define ETH_ADDRESS_DEBUG 1 @@ -38,8 +39,8 @@ Address dev::toAddress(Secret _secret) KeyPair KeyPair::create() { - 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) { @@ -57,8 +58,8 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { - crypto::toPublic(m_secret, m_public); - if (crypto::verifySecret(m_secret, m_public)) + toPublic(m_secret, m_public); + if (verifySecret(m_secret, m_public)) m_address = right160(dev::sha3(m_public.ref())); #if ETH_ADDRESS_DEBUG @@ -106,7 +107,7 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } -h256 Sec::getNonce(bool _commit) +h256 Nonce::get(bool _commit) { // todo: atomic efface bit, periodic save, kdf, rr, rng static h256 seed; @@ -116,8 +117,7 @@ h256 Sec::getNonce(bool _commit) { if (!seed) { - static Sec sec; - + static Nonce nonce; bytes b = contents(seedFile); if (b.size() == 32) memcpy(seed.data(), b.data(), 32); @@ -139,7 +139,7 @@ h256 Sec::getNonce(bool _commit) return seed; } -Sec::~Sec() +Nonce::~Nonce() { - Sec::getNonce(true); + Nonce::get(true); } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e163fb1c4..167621ec0 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -110,13 +110,19 @@ private: Public m_public; Address m_address; }; - -struct Sec + +namespace crypto +{ +/** + * @brief Generator for nonce material + */ +struct Nonce { - static h256 getNonce(bool _commit = false); + static h256 get(bool _commit = false); private: - Sec() {} - ~Sec(); + Nonce() {} + ~Nonce(); }; +} } \ No newline at end of file diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index e6b4c19c8..73c36ffdc 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -56,7 +56,7 @@ void crypto::toPublic(Secret const& _s, Public& o_public) h256 crypto::kdf(Secret const& _priv, h256 const& _hash) { h256 s; - sha3mac(Sec::getNonce().ref(), _priv.ref(), s.ref()); + sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); assert(s); return sha3((_hash ^ s).asBytes()); } From a373315639f8763b740032b9d693d98342c84f98 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 3 Nov 2014 11:43:07 +0100 Subject: [PATCH 19/77] fix build (mutex header missing) --- libdevcrypto/Common.cpp | 2 +- libdevcrypto/EC.cpp | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index f039435ad..b06a16e57 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -20,8 +20,8 @@ * @date 2014 */ - #include +#include #include "EC.h" #include "SHA3.h" #include "FileSystem.h" diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 73c36ffdc..16f3c6830 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -21,17 +21,6 @@ * 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" From ab2442c39e286b2e0518d5915189f44c24943abc Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 3 Nov 2014 13:22:08 +0100 Subject: [PATCH 20/77] Fix: Search for jsonrpc locally. --- cmake/EthDependenciesDeprecated.cmake | 2 ++ 1 file changed, 2 insertions(+) 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}") From 5cc582c454c14a3691dc3f81322069960ce6d75c Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 3 Nov 2014 12:14:06 +0100 Subject: [PATCH 21/77] Bugfix: Swap before mod and div. --- libsolidity/ExpressionCompiler.cpp | 4 ++-- test/solidityExpressionCompiler.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 003d561a7..871b64184 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -336,10 +336,10 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty m_context << eth::Instruction::MUL; break; case Token::DIV: - m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); break; case Token::MOD: - m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; default: assert(false); diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index d28628fcd..83a7b2bbf 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -212,7 +212,9 @@ BOOST_AUTO_TEST_CASE(arithmetics) 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()); From 30e4cda0e9bddf58c0f89bcf3b21a90a2557fea6 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 31 Oct 2014 17:47:43 +0100 Subject: [PATCH 22/77] Some tests and bugfixes for the compiler. --- libethereum/Account.h | 2 +- libsolidity/Compiler.cpp | 32 ++--- libsolidity/Compiler.h | 1 - libsolidity/ExpressionCompiler.cpp | 1 + test/solidityEndToEndTest.cpp | 210 ++++++++++++++++++++++++++++ test/solidityExpressionCompiler.cpp | 3 +- 6 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 test/solidityEndToEndTest.cpp diff --git a/libethereum/Account.h b/libethereum/Account.h index ce7004083..7e2fc38ab 100644 --- a/libethereum/Account.h +++ b/libethereum/Account.h @@ -82,7 +82,7 @@ public: /// Construct an alive Account, with given endowment, for either a normal (non-contract) account or for a /// contract account in the /// conception phase, where the code is not yet known. - Account(u256 _balance, NewAccountType _t): m_isAlive(true), m_balance(_balance), m_codeHash(_t == NormalCreation ? c_contractConceptionCodeHash : EmptySHA3) {} + Account(u256 _balance, NewAccountType _t): m_isAlive(true), m_balance(_balance), m_codeHash(_t == NormalCreation ? EmptySHA3 : c_contractConceptionCodeHash) {} /// Explicit constructor for wierd cases of construction of a normal account. Account(u256 _nonce, u256 _balance): m_isAlive(true), m_nonce(_nonce), m_balance(_balance) {} diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 7909e0701..a44c177d7 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -94,25 +94,20 @@ void Compiler::appendFunctionSelector(vector> con for (pair> const& f: publicFunctions) m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST; - m_context << returnTag << eth::Instruction::RETURN; + m_context << returnTag << eth::Instruction::STOP; for (pair> const& f: publicFunctions) { + FunctionDefinition const& function = *f.second.first; m_context << f.second.second; - appendFunctionCallSection(*f.second.first); - } -} - -void Compiler::appendFunctionCallSection(FunctionDefinition const& _function) -{ - eth::AssemblyItem returnTag = m_context.pushNewTag(); - appendCalldataUnpacker(_function); + eth::AssemblyItem returnTag = m_context.pushNewTag(); + appendCalldataUnpacker(function); + m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); + m_context << returnTag; - m_context.appendJumpTo(m_context.getFunctionEntryLabel(_function)); - m_context << returnTag; - - appendReturnValuePacker(_function); + appendReturnValuePacker(function); + } } void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function) @@ -142,7 +137,7 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) //@todo this can be also done more efficiently unsigned dataOffset = 0; vector> const& parameters = _function.getReturnParameters(); - for (unsigned i = 0 ; i < parameters.size(); ++i) + for (unsigned i = 0; i < parameters.size(); ++i) { unsigned numBytes = parameters[i]->getType()->getCalldataEncodedSize(); if (numBytes == 0) @@ -150,11 +145,9 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) << errinfo_sourceLocation(parameters[i]->getLocation()) << errinfo_comment("Type not yet supported.")); m_context << eth::dupInstruction(parameters.size() - i); - if (numBytes == 32) - m_context << u256(dataOffset) << eth::Instruction::MSTORE; - else - m_context << u256(dataOffset) << (u256(1) << ((32 - numBytes) * 8)) - << eth::Instruction::MUL << eth::Instruction::MSTORE; + 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 @@ -215,6 +208,7 @@ bool Compiler::visit(FunctionDefinition& _function) m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1); swap(stackLayout[stackLayout.back()], stackLayout.back()); } + //@todo assert that everything is in place now m_context << eth::Instruction::JUMP; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index d10374a9b..4e4d90d45 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -43,7 +43,6 @@ private: /// Creates a new compiler context / assembly and packs the current code into the data part. void packIntoContractCreator(); void appendFunctionSelector(std::vector > const& _functions); - void appendFunctionCallSection(FunctionDefinition const& _function); void appendCalldataUnpacker(FunctionDefinition const& _function); void appendReturnValuePacker(FunctionDefinition const& _function); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 871b64184..f9cbee377 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -264,6 +264,7 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperati 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; } diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp new file mode 100644 index 000000000..7bb01fa12 --- /dev/null +++ b/test/solidityEndToEndTest.cpp @@ -0,0 +1,210 @@ + +/* + 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); + eth::Executive ex(m_state); + BOOST_REQUIRE(!ex.create(Address(), 0, m_gasPrice, m_gas, &code, Address())); + BOOST_REQUIRE(ex.go()); + ex.finalize(); + m_contractAddress = ex.newAddress(); + return ex.out().toBytes(); + } + + bytes callFunction(byte _index, bytes const& _data) + { + bytes data = bytes(1, _index) + _data; + eth::Executive ex(m_state); + BOOST_REQUIRE(!ex.call(m_contractAddress, Address(), 0, m_gasPrice, &data, m_gas, Address())); + BOOST_REQUIRE(ex.go()); + ex.finalize(); + return ex.out().toBytes(); + } + + bytes callFunction(byte _index, u256 const& _argument) + { + return callFunction(_index, toBigEndian(_argument)); + } + +private: + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 1000000; +}; + +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 index 83a7b2bbf..043a69496 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -177,8 +177,9 @@ BOOST_AUTO_TEST_CASE(short_circuiting) 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::PUSH1), 0x15, 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), From 331ed8c872883e1aff634d44f26c049ef29ca198 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 3 Nov 2014 16:10:07 +0100 Subject: [PATCH 23/77] Correct Solidity error formatting in AlethZero. --- alethzero/MainWin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3c874d8a2..55c240379 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1559,6 +1559,7 @@ 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); @@ -1574,7 +1575,7 @@ void Main::on_data_textChanged() { ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner); - errors.push_back(error.str()); + solidity = "

Solidity

" + QString::fromStdString(error.str()).toHtmlEscaped() + "
"; } } else @@ -1611,7 +1612,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); From 7e542f55d30e03c02ac51e0902b5cc8d1bf36740 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 3 Nov 2014 16:29:55 +0100 Subject: [PATCH 24/77] Test adjustments. --- test/solidityCompiler.cpp | 7 +++---- test/solidityExpressionCompiler.cpp | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 84aac6661..17de9af53 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -1,4 +1,3 @@ - /* This file is part of cpp-ethereum. @@ -101,7 +100,7 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 76; + unsigned shift = 75; unsigned boilerplateSize = 88; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize return variable d @@ -154,7 +153,7 @@ BOOST_AUTO_TEST_CASE(ifStatement) "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 39; + unsigned shift = 38; unsigned boilerplateSize = 51; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, @@ -196,7 +195,7 @@ BOOST_AUTO_TEST_CASE(loops) "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 39; + unsigned shift = 38; unsigned boilerplateSize = 51; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 043a69496..561cc3bda 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting) byte(eth::Instruction::GT), byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x15, + byte(eth::Instruction::PUSH1), 0x14, byte(eth::Instruction::JUMPI), // short-circuit if it is true byte(eth::Instruction::POP), byte(eth::Instruction::PUSH1), 0x2, @@ -320,13 +320,13 @@ BOOST_AUTO_TEST_CASE(function_call) {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(eth::Instruction::PUSH1), 0x0b, + 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), 0x15, + byte(eth::Instruction::PUSH1), 0x14, byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMPDEST), // Stack here: a b g(a+1, b) From 1c746c7233379026562d04dcd385821e8b4001fc Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 4 Nov 2014 10:54:46 +0100 Subject: [PATCH 25/77] codereview fixes --- libdevcrypto/Common.cpp | 34 ++++++++++++++++------------------ libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/EC.cpp | 14 ++++++++------ test/crypto.cpp | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b06a16e57..bd1c80268 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -114,28 +114,26 @@ h256 Nonce::get(bool _commit) static string seedFile(getDataDir() + "/seed"); static mutex x; lock_guard l(x); + if (!seed) { - if (!seed) + static Nonce nonce; + bytes b = contents(seedFile); + if (b.size() == 32) + memcpy(seed.data(), b.data(), 32); + else { - static Nonce nonce; - bytes b = contents(seedFile); - if (b.size() == 32) - memcpy(seed.data(), b.data(), 32); - else - { - std::mt19937_64 s_eng(time(0)); - std::uniform_int_distribution d(0, 255); - for (unsigned i = 0; i < 32; ++i) - seed[i] = (byte)d(s_eng); - } - writeFile(seedFile, bytes()); + std::mt19937_64 s_eng(time(0)); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + seed[i] = (byte)d(s_eng); } - assert(seed); - h256 prev(seed); - sha3(prev.ref(), seed.ref()); - if (_commit) - writeFile(seedFile, seed.asBytes()); + writeFile(seedFile, bytes()); } + assert(seed); + h256 prev(seed); + sha3(prev.ref(), seed.ref()); + if (_commit) + writeFile(seedFile, seed.asBytes()); return seed; } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 756bbb72a..dc5d6a610 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -67,7 +67,7 @@ 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 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)); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 16f3c6830..890b7e2f4 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -39,7 +39,7 @@ using namespace pp; void crypto::toPublic(Secret const& _s, Public& o_public) { - exponentToPublic(Integer(_s.data(),sizeof(_s)), o_public); + exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); } h256 crypto::kdf(Secret const& _priv, h256 const& _hash) @@ -92,10 +92,12 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) 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); - k %= secp256k1Params.GetSubgroupOrder()-1; + assert(k); + k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k); Integer r = secp256k1Params.ConvertElementToInteger(rp); @@ -105,7 +107,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q; assert(!!r && !!s); - if (s > secp256k1Params.GetSubgroupOrder()) + if (s > qs) { s = q - s; if (recid) @@ -114,7 +116,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Signature sig; r.Encode(sig.data(), 32); - s.Encode(sig.data()+32, 32); + s.Encode(sig.data() + 32, 32); sig[64] = recid; return sig; } @@ -147,8 +149,8 @@ Public crypto::recover(Signature _signature, bytesConstRef _message) { secp256k1_start(); - byte pubkey[65]; int pubkeylen = 65; + byte pubkey[pubkeylen]; if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) return Public(); @@ -172,8 +174,8 @@ bool crypto::verifySecret(Secret const& _s, Public const& _p) if (!ok) return false; - byte pubkey[65]; int pubkeylen = 65; + byte pubkey[pubkeylen]; ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); if (!ok || pubkeylen != 65) return false; diff --git a/test/crypto.cpp b/test/crypto.cpp index ab384a038..82950f09d 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) Signature sig; r.Encode(sig.data(), 32); - s.Encode(sig.data()+32, 32); + s.Encode(sig.data() + 32, 32); sig[64] = recid; Public p = dev::recover(sig, he); @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) pp::initializeDLScheme(key.pub(), verifier); Signature sigppraw; r.Encode(sigppraw.data(), 32); - s.Encode(sigppraw.data()+32, 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)); From 0f0a464b4e987a7cf76afc9d0ae407fb1d9fe70b Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Nov 2014 18:39:16 +0100 Subject: [PATCH 26/77] Stylistic changes. --- libsolidity/AST.cpp | 4 ---- libsolidity/AST.h | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 5391e71b7..0ecb639f0 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -333,11 +333,9 @@ void Assignment::checkTypeRequirements() 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() @@ -358,10 +356,8 @@ void UnaryOperation::checkTypeRequirements() // 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.")); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index a283a09b3..bbb73b080 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -180,7 +180,8 @@ public: Block& getBody() { return *m_body; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } - std::vectorconst& getLocalVariables() const { return m_localVariables; } + std::vector const& getLocalVariables() const { return m_localVariables; } + private: bool m_isPublic; ASTPointer m_parameters; @@ -345,6 +346,7 @@ public: Expression& getCondition() const { return *m_condition; } Statement& getTrueStatement() const { return *m_trueBody; } Statement* getFalseStatement() const { return m_falseBody.get(); } + private: ASTPointer m_condition; ASTPointer m_trueBody; @@ -373,6 +375,7 @@ public: Expression& getCondition() const { return *m_condition; } Statement& getBody() const { return *m_body; } + private: ASTPointer m_condition; ASTPointer m_body; From 104adbabcb41ff9354efe0552bf05e59cb090bcc Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Tue, 4 Nov 2014 13:36:29 +0100 Subject: [PATCH 27/77] Update tests to latest protocol changes (PoC7) --- libevm/VM.h | 3 +- test/vm.cpp | 10 +- test/vmArithmeticTestFiller.json | 804 ++++++++--------- test/vmBitwiseLogicOperationTestFiller.json | 934 +++++++++++--------- test/vmIOandFlowOperationsTestFiller.json | 80 +- test/vmPushDupSwapTestFiller.json | 134 +-- test/vmSha3TestFiller.json | 59 +- 7 files changed, 1079 insertions(+), 945 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index c76a45e33..8bf3854f3 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -104,7 +104,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { int in = _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; u256 p = 0; - for (; in--; i++) + for (i++; in--; i++) p = (p << 8) | _ext.getCode(i); if ((_ext.getCode(i) == (byte)Instruction::JUMP || _ext.getCode(i) == (byte)Instruction::JUMPI) && !(_ext.getCode(p) == (byte)Instruction::JUMP || _ext.getCode(p) == (byte)Instruction::JUMPI)) if (p >= _ext.code.size()) @@ -112,6 +112,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con else implicit.insert(p); else {} + i--; } for (unsigned i = 0; i < _ext.code.size(); i += instructionInfo((Instruction)_ext.getCode(i)).additional + 1) if (implicit.count(i)) diff --git a/test/vm.cpp b/test/vm.cpp index 617cb95c7..74d300b64 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -695,7 +695,7 @@ void executeTests(const string& _name) else testPath = ptestPath; - testPath += "/vmtests"; + testPath += "/VMTests"; #ifdef FILL_TESTS try @@ -782,10 +782,10 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) dev::test::executeTests("vmPushDupSwapTest"); } -BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) -{ - dev::test::executeTests("vmSystemOperationsTest"); -} +//BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) +//{ +// dev::test::executeTests("vmSystemOperationsTest"); +//} BOOST_AUTO_TEST_CASE(userDefinedFile) { 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..a3aec2696 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,63 @@ "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": {} } }, @@ -599,7 +655,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360016009596001600257", + "code" : "0x602360016009576001600255", "storage": {} } }, @@ -627,7 +683,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60236001600a5960015d600257", + "code" : "0x60236001600a5760015b600255", "storage": {} } }, @@ -655,7 +711,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360006009596001600257", + "code" : "0x602360006009576001600255", "storage": {} } }, @@ -683,7 +739,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" + } + } } From 8eaa26e71693fe47fa50a2bf4593f8dce795949a Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 4 Nov 2014 13:45:45 +0100 Subject: [PATCH 28/77] replace asserts with exception --- libdevcrypto/Common.cpp | 5 ++++- libdevcrypto/Common.h | 3 +++ libdevcrypto/EC.cpp | 12 +++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index bd1c80268..14dad127e 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -127,9 +127,12 @@ h256 Nonce::get(bool _commit) for (unsigned i = 0; i < 32; ++i) seed[i] = (byte)d(s_eng); } + if (!seed) + throw InvalidState(); + + // prevent seed reuse if process terminates abnormally writeFile(seedFile, bytes()); } - assert(seed); h256 prev(seed); sha3(prev.ref(), seed.ref()); if (_commit) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 167621ec0..7e74c754d 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -26,6 +26,7 @@ #include #include +#include namespace dev { @@ -113,6 +114,8 @@ private: namespace crypto { +struct InvalidState: virtual Exception {}; + /** * @brief Generator for nonce material */ diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 890b7e2f4..fd64f60d0 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -44,10 +44,15 @@ void crypto::toPublic(Secret const& _s, Public& o_public) h256 crypto::kdf(Secret const& _priv, h256 const& _hash) { + // H(H(r||k)^h) h256 s; sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); - assert(s); - return sha3((_hash ^ s).asBytes()); + s ^= _hash; + sha3(s.ref(), s.ref()); + + if (!s || !_hash || !_priv) + throw InvalidState(); + return std::move(s); } void crypto::encrypt(Public const& _k, bytes& io_cipher) @@ -96,7 +101,8 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer e(_hash.asBytes().data(), 32); Integer k(kdf(_key, _hash).data(), 32); - assert(k); + if (k == 0) + throw InvalidState(); k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k); From 1d16e1556fc4ffe0c57c1781fc77aa3ac236f64a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 4 Nov 2014 18:11:06 +0000 Subject: [PATCH 29/77] Ready for move to log entries in JS API. --- libdevcore/FixedHash.h | 5 ++ libdevcrypto/Common.h | 3 + libdevcrypto/SHA3.h | 3 + libethereum/MessageFilter.cpp | 55 ++++++++++++++++ libethereum/MessageFilter.h | 34 ++++++++++ libethereum/State.cpp | 3 +- libevm/ExtVMFace.h | 20 ++++-- libweb3jsonrpc/WebThreeStubServer.cpp | 71 ++++++++++++++++++--- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libweb3jsonrpc/abstractwebthreestubserver.h | 7 -- libweb3jsonrpc/spec.json | 1 - 11 files changed, 181 insertions(+), 25 deletions(-) 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.h b/libdevcrypto/Common.h index 7f2a8192e..4b4d34d87 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -50,6 +50,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; 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/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index fc6af1308..88f1a24f9 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -149,3 +149,58 @@ bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, return ret; } + + + +void LogFilter::streamRLP(RLPStream& _s) const +{ + _s.appendList(6) << m_addresses << m_topics << m_earliest << m_latest << m_max << m_skip; +} + +h256 LogFilter::sha3() const +{ + RLPStream s; + streamRLP(s); + return dev::sha3(s.out()); +} + +bool LogFilter::matches(LogBloom _bloom) const +{ + if (m_addresses.size()) + { + for (auto i: m_addresses) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK1; + return false; + } + OK1: + if (m_topics.size()) + { + for (auto i: m_topics) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK2; + return false; + } + OK2: + return true; +} + +bool LogFilter::matches(State const& _s, unsigned _i) const +{ + return matches(_s.receipt(_i)).size() > 0; +} + +LogEntries LogFilter::matches(TransactionReceipt const& _m) const +{ + LogEntries ret; + for (LogEntry const& e: _m.log()) + { + if (!m_addresses.empty() && !m_addresses.count(e.address)) + continue; + for (auto const& t: m_topics) + if (!e.topics.count(t)) + continue; + ret.push_back(e); + } + return ret; +} diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h index 83cbb7237..5602d7a17 100644 --- a/libethereum/MessageFilter.h +++ b/libethereum/MessageFilter.h @@ -25,6 +25,7 @@ #include #include #include "PastMessage.h" +#include "TransactionReceipt.h" namespace dev { @@ -72,5 +73,38 @@ private: unsigned m_skip; }; +class LogFilter +{ +public: + LogFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} + + void streamRLP(RLPStream& _s) const; + h256 sha3() const; + + int earliest() const { return m_earliest; } + int latest() const { return m_latest; } + unsigned max() const { return m_max; } + unsigned skip() const { return m_skip; } + bool matches(LogBloom _bloom) const; + bool matches(State const& _s, unsigned _i) const; + LogEntries matches(TransactionReceipt const& _r) const; + + LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } + LogFilter from(Address _a) { return topic(u256((u160)_a) + 1); } + LogFilter topic(h256 const& _t) { m_topics.insert(_t); return *this; } + LogFilter withMax(unsigned _m) { m_max = _m; return *this; } + LogFilter withSkip(unsigned _m) { m_skip = _m; return *this; } + LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } + LogFilter withLatest(int _e) { m_latest = _e; return *this; } + +private: + AddressSet m_addresses; + h256Set m_topics; + int m_earliest = 0; + int m_latest = -1; + unsigned m_max; + unsigned m_skip; +}; + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 51f5901c5..cd1a7f541 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -791,7 +791,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; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 1b1ae7455..9f662087c 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; }; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e7eb62e04..4ac048ee9 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -97,6 +97,24 @@ static Json::Value toJson(dev::eth::Transaction const& _t) 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) +{ + Json::Value res; + for (dev::eth::LogEntry const& e: _es) + res.append(toJson(e)); + return res; +} + static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { dev::eth::MessageFilter filter; @@ -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) +{ + 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 Date: Tue, 4 Nov 2014 19:35:59 +0100 Subject: [PATCH 30/77] Fixed doxygen comment. --- libevmface/Instruction.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index 0477f9ca1..8392c410b 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -176,13 +176,13 @@ enum class Instruction: uint8_t SUICIDE = 0xff ///< halt execution and register account for later deletion }; -/// Returs the PUSH<_number> instruction +/// @returns the PUSH<_number> instruction inline Instruction pushInstruction(unsigned _number) { assert(1 <= _number && _number <= 32); return Instruction(unsigned(Instruction::PUSH1) + _number - 1); } -/// Returs the DUP<_number> instruction +/// @returns the DUP<_number> instruction inline Instruction dupInstruction(unsigned _number) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::DUP1) + _number - 1); } -/// Returs the SWAP<_number> instruction +/// @returns the SWAP<_number> instruction inline Instruction swapInstruction(unsigned _number) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::SWAP1) + _number - 1); } /// Information structure for a particular instruction. From debab8c26fd7f71aa3c27d16181e91840acf5db4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Nov 2014 19:52:04 +0100 Subject: [PATCH 31/77] Added doxygen comment. --- libsolidity/AST.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index bbb73b080..43aa9bf5e 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -345,6 +345,7 @@ public: 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: From 98978db66213836a7b2bcef9b41bbcfc545f0b71 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 00:10:12 +0100 Subject: [PATCH 32/77] int to size_t for errinfo_required --- libdevcore/Exceptions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index f0d77043a..bb39cc3c9 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -46,7 +46,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::error_info errinfo_required; +typedef boost::error_info errinfo_got; typedef boost::tuple RequirementError; } From 5f768173916323c2a6f5649b4464d80088753083 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 00:12:29 +0100 Subject: [PATCH 33/77] uncomment vmIOandFlowOPerations test --- test/vm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 4061d789e..67ecc261f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -427,10 +427,10 @@ BOOST_AUTO_TEST_CASE(vmBlockInfoTest) dev::test::executeTests("vmBlockInfoTest", "/VMTests", dev::test::doVMTests); } -//BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) -//{ -// dev::test::executeTests("vmIOandFlowOperationsTest", "/VMTests", dev::test::doVMTests); -//} +BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) +{ + dev::test::executeTests("vmIOandFlowOperationsTest", "/VMTests", dev::test::doVMTests); +} BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) { From edfc06e2c6c8579e00e78bf298bcebb117dc5bb8 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 15:14:31 +0100 Subject: [PATCH 34/77] Bugfix: Special case of statements starting with type conversion. --- libsolidity/Parser.cpp | 8 ++++---- test/solidityParser.cpp | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 44f0a54ad..72770f679 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -290,10 +290,10 @@ ASTPointer Parser::parseStatement() // We have a variable definition if we ge 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(); 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() From b50578f1e6ccfdfa3fdda94ebdca1de910c5f67e Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Nov 2014 14:13:27 +0100 Subject: [PATCH 35/77] coding standards, documentation, new exception syntax --- libdevcore/Exceptions.h | 1 - libdevcrypto/Common.cpp | 32 +++++++++++++++++--------------- libdevcrypto/Common.h | 4 ++-- libwhisper/Message.h | 1 + test/crypto.cpp | 9 ++++++++- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 932276d01..7576050e6 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -24,7 +24,6 @@ #include #include #include -#include #include "CommonData.h" #include "FixedHash.h" diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 14dad127e..38d2eb934 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -110,34 +110,36 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) h256 Nonce::get(bool _commit) { // todo: atomic efface bit, periodic save, kdf, rr, rng - static h256 seed; - static string seedFile(getDataDir() + "/seed"); - static mutex x; - lock_guard l(x); - if (!seed) + // 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 nonce; - bytes b = contents(seedFile); + static Nonce s_nonce; + bytes b = contents(s_seedFile); if (b.size() == 32) - memcpy(seed.data(), b.data(), 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) - seed[i] = (byte)d(s_eng); + s_seed[i] = (byte)d(s_eng); } - if (!seed) + if (!s_seed) throw InvalidState(); // prevent seed reuse if process terminates abnormally - writeFile(seedFile, bytes()); + writeFile(s_seedFile, bytes()); } - h256 prev(seed); - sha3(prev.ref(), seed.ref()); + h256 prev(s_seed); + sha3(prev.ref(), s_seed.ref()); if (_commit) - writeFile(seedFile, seed.asBytes()); - return seed; + writeFile(s_seedFile, s_seed.asBytes()); + return std::move(s_seed); } Nonce::~Nonce() diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7e74c754d..6fcda73cb 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -114,8 +114,8 @@ private: namespace crypto { -struct InvalidState: virtual Exception {}; - +struct InvalidState: public dev::Exception {}; + /** * @brief Generator for nonce material */ diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 6b28073b7..677d16f00 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "Common.h" diff --git a/test/crypto.cpp b/test/crypto.cpp index 82950f09d..b0785aca1 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) } } -BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) +BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) { // cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature @@ -128,6 +128,12 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) 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 @@ -135,6 +141,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) if (recid) recid ^= 1; } + */ Signature sig; r.Encode(sig.data(), 32); From 2e551b5870193b7c07650dbe30f776e03faff3a6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 13:45:19 +0000 Subject: [PATCH 36/77] Classify Transaction. --- alethzero/MainWin.cpp | 91 +++++++++++++-------------- libethereum/Client.cpp | 42 ++++--------- libethereum/Executive.cpp | 42 ++++++------- libethereum/MessageFilter.cpp | 2 +- libethereum/State.cpp | 6 +- libethereum/Transaction.cpp | 30 ++++----- libethereum/Transaction.h | 53 +++++++++------- libweb3jsonrpc/WebThreeStubServer.cpp | 16 ++--- neth/main.cpp | 32 +++++----- test/crypto.cpp | 14 +---- test/state.cpp | 7 +-- test/vm.cpp | 38 ++++------- 12 files changed, 167 insertions(+), 206 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f413532b7..18270ff8c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -868,18 +868,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 +946,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(true).ref()) + " " + toHex(_t.sha3(false).ref()) + " " + toHex(_t.sender().ref()); if (info.find(_f) != string::npos) return true; return false; @@ -986,18 +986,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 +1144,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 +1251,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 << "
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(false) << ""; 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); @@ -1786,14 +1786,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/libethereum/Client.cpp b/libethereum/Client.cpp index 63e093b17..d87e9c33e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -316,19 +316,13 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ { startWorking(); - Transaction t; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::MessageCall; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); +// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); } @@ -338,22 +332,16 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat bytes out; try { + u256 n; State temp; - Transaction t; // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); { ReadGuard l(x_stateDB); temp = m_postMine; - t.nonce = temp.transactionsFrom(toAddress(_secret)); + n = temp.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); - u256 gasUsed = temp.execute(t.data, &out, false); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + u256 gasUsed = temp.execute(t.data(), &out, false); (void)gasUsed; // TODO: do something with gasused which it returns. } catch (...) @@ -367,21 +355,15 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2 { startWorking(); - Transaction t; + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _endowment; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = Address(); - t.data = _init; - t.sign(_secret); + Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); - return right160(sha3(rlpList(t.sender(), t.nonce))); + return right160(sha3(rlpList(t.sender(), t.nonce()))); } void Client::inject(bytesConstRef _rlp) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 885ab5535..e14401972 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,7 +177,7 @@ 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&) @@ -234,9 +234,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 88f1a24f9..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; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index cd1a7f541..c059922d5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -520,7 +520,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; @@ -1154,10 +1154,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()); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index bdc8bf34d..c65421e04 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -36,14 +36,14 @@ 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(); } @@ -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(false)); if (!p) BOOST_THROW_EXCEPTION(InvalidSignature()); m_sender = right160(dev::sha3(bytesConstRef(p.data(), sizeof(p)))); @@ -82,18 +82,18 @@ Address Transaction::sender() const void Transaction::sign(Secret _priv) { auto sig = dev::sign(_priv, sha3(false)); - vrs = *(SignatureStruct const*)&sig; + m_vrs = *(SignatureStruct const*)&sig; } void Transaction::streamRLP(RLPStream& _s, bool _sig) const { _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..bb04bcab7 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -30,47 +30,59 @@ namespace dev namespace eth { -struct Transaction +class Transaction { +public: enum Type { + NullTransaction, ContractCreation, MessageCall }; 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); } + 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); } + 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) {} + 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) {} 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; } + 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; } 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. - - bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - - SignatureStruct vrs; ///< The signature of the transaction. Encodes the sender. - 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. - bool isCreation() const { return !receiveAddress; } - - static h256 kFromMessage(h256 _msg, h256 _priv); + bool isCreation() const { return !m_receiveAddress; } 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()); } + Type type() const { return m_type; } + u256 nonce() const { return m_nonce; } + u256 value() const { return m_value; } + Address receiveAddress() const { return m_receiveAddress; } + u256 gasPrice() const { return m_gasPrice; } + u256 gas() const { return m_gas; } + bytes const& data() const { return m_data; } + SignatureStruct const& signature() const { return m_vrs; } + private: + Type m_type = NullTransaction; ///< True if this is a contract-creation transaction. F + 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; }; @@ -79,19 +91,18 @@ using Transactions = std::vector; 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/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 4ac048ee9..89d45f4e0 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -87,13 +87,13 @@ 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; } @@ -107,7 +107,7 @@ static Json::Value toJson(dev::eth::LogEntry const& _e) return res; } -static Json::Value toJson(dev::eth::LogEntries const& _es) +/*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) @@ -161,7 +161,7 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) return filter; } -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) +/*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()) 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/test/crypto.cpp b/test/crypto.cpp index 67286bfca..2f5314421 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -339,16 +339,11 @@ 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; + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); auto rlp = t.rlp(false); cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(false); - t.sign(p.secret()); rlp = t.rlp(true); cnote << RLP(rlp); cnote << toHex(rlp); @@ -368,16 +363,11 @@ int cryptoTest() assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { - eth::Transaction t; - t.nonce = 0; - t.type = eth::Transaction::MessageCall; - t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); - t.value = 1000; + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); auto rlp = t.rlp(false); cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(false); - t.sign(p.secret()); rlp = t.rlp(true); cnote << RLP(rlp); cnote << toHex(rlp); diff --git a/test/state.cpp b/test/state.cpp index b0f279bac..921be5f95 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -65,12 +65,7 @@ int stateTest() // Inject a transaction to transfer funds from miner to me. bytes tx; { - 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()); + Transaction t(1000, 0, 0, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); tx = t.rlp(); } diff --git a/test/vm.cpp b/test/vm.cpp index 617cb95c7..8344c0c5f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -36,11 +36,7 @@ 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(); + Transaction t(_endowment, gasPrice, *_gas, _init.toBytes()); m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); @@ -55,7 +51,6 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun get<3>(addresses[ret]) = m_s.code(ret); } - t.type = eth::Transaction::ContractCreation; callcreates.push_back(t); return ret; } @@ -64,13 +59,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { 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]) ); @@ -386,10 +375,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.type() == Transaction::ContractCreation ? "" : 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 +393,18 @@ 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"]); + bytes data; 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)); + data = fromHex(tx["data"].get_str().substr(2)); else - t.data = fromHex(tx["data"].get_str()); + data = fromHex(tx["data"].get_str()); else for (auto const& j: tx["data"].get_array()) - t.data.push_back(toByte(j)); + data.push_back(toByte(j)); + Transaction t = tx["destination"].get_str().empty() ? + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data) : + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data); callcreates.push_back(t); } } From 37216a246ae2ef73029c46861fc260cfe807b062 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 14:20:56 +0100 Subject: [PATCH 37/77] Converted all asserts to exceptions. --- libsolidity/AST.cpp | 25 ++++++----- libsolidity/AST.h | 32 ++++++++++++--- libsolidity/Compiler.cpp | 6 ++- libsolidity/CompilerContext.cpp | 7 ++-- libsolidity/Exceptions.h | 1 + libsolidity/ExpressionCompiler.cpp | 58 +++++++++++++------------- libsolidity/NameAndTypeResolver.cpp | 16 +++++--- libsolidity/Scanner.cpp | 33 +++++++-------- libsolidity/Scanner.h | 2 +- libsolidity/Token.h | 64 +++++------------------------ libsolidity/Types.cpp | 14 ++++--- libsolidity/Types.h | 7 +++- solc/main.cpp | 45 ++++++++++++-------- 13 files changed, 157 insertions(+), 153 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0ecb639f0..f9c49adc5 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -293,9 +293,10 @@ 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.")); @@ -377,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.")); @@ -393,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.")); @@ -434,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? @@ -487,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 43aa9bf5e..f42ff47d0 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -243,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); } @@ -407,7 +410,12 @@ public: virtual void checkTypeRequirements() override; void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } - ParameterList const& getFunctionReturnParameters() const { assert(m_returnParameters); return *m_returnParameters; } + ParameterList const& getFunctionReturnParameters() const + { + if (asserts(m_returnParameters)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + return *m_returnParameters; + } Expression* getExpression() const { return m_expression.get(); } private: @@ -495,7 +503,10 @@ 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; @@ -519,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; @@ -541,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; @@ -658,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/Compiler.cpp b/libsolidity/Compiler.cpp index a44c177d7..654eceadb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -252,14 +252,16 @@ bool Compiler::visit(WhileStatement& _whileStatement) bool Compiler::visit(Continue&) { - assert(!m_continueTags.empty()); + 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; } bool Compiler::visit(Break&) { - assert(!m_breakTags.empty()); + 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; } diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index b8f57618b..44d0844c2 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -20,7 +20,6 @@ * Utilities for the solidity compiler. */ -#include #include #include #include @@ -45,14 +44,16 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables) int CompilerContext::getStackPositionOfVariable(const Declaration& _declaration) { auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); - assert(res != m_localVariables.end()); + 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(const FunctionDefinition& _function) const { auto res = m_functionEntryLabels.find(&_function); - assert(res != m_functionEntryLabels.end()); + 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/Exceptions.h b/libsolidity/Exceptions.h index 1d981e7c0..1903c1dc2 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -35,6 +35,7 @@ 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 index f9cbee377..d23579b11 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -20,7 +20,6 @@ * Solidity AST to EVM bytecode compiler for expressions. */ -#include #include #include #include @@ -105,7 +104,8 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) m_context << u256(0) << eth::Instruction::SUB; break; default: - assert(false); // invalid operation + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + + string(Token::toString(_unaryOperation.getOperator())))); } } @@ -127,7 +127,8 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) rightExpression.accept(*this); // the types to compare have to be the same, but the resulting type is always bool - assert(*leftExpression.getType() == *rightExpression.getType()); + if (asserts(*leftExpression.getType() == *rightExpression.getType())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); appendCompareOperatorCode(op, *leftExpression.getType()); } else @@ -148,7 +149,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) if (_functionCall.isTypeConversion()) { //@todo we only have integers and bools for now which cannot be explicitly converted - assert(_functionCall.getArguments().size() == 1); + if (asserts(_functionCall.getArguments().size() == 1)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); Expression& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); @@ -159,28 +161,28 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) // Callee removes them and pushes return values m_currentLValue = nullptr; _functionCall.getExpression().accept(*this); - FunctionDefinition const* function = dynamic_cast(m_currentLValue); - assert(function); + FunctionDefinition const& function = dynamic_cast(*m_currentLValue); eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector> const& arguments = _functionCall.getArguments(); - assert(arguments.size() == function->getParameters().size()); + 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()); + *function.getParameters()[i]->getType()); } - m_context.appendJumpTo(m_context.getFunctionEntryLabel(*function)); + 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); + 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) + for (unsigned i = 1; i < function.getReturnParameters().size(); ++i) m_context << eth::Instruction::POP; } return false; @@ -227,7 +229,7 @@ void ExpressionCompiler::endVisit(Literal& _literal) m_context << _literal.getType()->literalValue(_literal); break; default: - assert(false); // @todo + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer and boolean literals implemented for now.")); } } @@ -249,15 +251,15 @@ void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, { // 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. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); } } void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) { Token::Value const op = _binaryOperation.getOperator(); - assert(op == Token::OR || op == Token::AND); + if (asserts(op == Token::OR || op == Token::AND)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); _binaryOperation.getLeftExpression().accept(*this); m_context << eth::Instruction::DUP1; @@ -279,9 +281,8 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type } else { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); + 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. @@ -302,7 +303,7 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; default: - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); } } } @@ -316,14 +317,13 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator else if (Token::isShiftOp(_operator)) appendShiftOperatorCode(_operator); else - assert(false); // unknown binary operator + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); } void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); + IntegerType const& type = dynamic_cast(_type); + bool const isSigned = type.isSigned(); switch (_operator) { @@ -343,7 +343,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; default: - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); } } @@ -361,22 +361,21 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) m_context << eth::Instruction::XOR; break; default: - assert(false); + 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: - assert(false); //@todo break; case Token::SAR: - assert(false); //@todo break; default: - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator.")); } } @@ -402,7 +401,8 @@ void ExpressionCompiler::moveToLValue(Expression const& _expression) unsigned ExpressionCompiler::stackPositionOfLValue() const { - assert(m_currentLValue); + 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/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 4b77ed132..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 @@ -123,7 +122,8 @@ void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefini { // Register the local variables with the function // This does not fit here perfectly, but it saves us another AST visit. - assert(m_currentFunction); + if (asserts(m_currentFunction)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable definition without function.")); m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); } @@ -138,19 +138,22 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) 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.")); @@ -177,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/Scanner.cpp b/libsolidity/Scanner.cpp index d8defb50a..c36820317 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -50,7 +50,6 @@ * Solidity scanner. */ -#include #include #include #include @@ -113,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) @@ -128,7 +126,7 @@ bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) x = x * 16 + d; advance(); } - o_scannedNumber = x; + o_scannedByte = x; return true; } @@ -175,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()) { @@ -418,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; } @@ -468,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) @@ -510,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(); @@ -606,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) @@ -634,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. @@ -656,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 c2dfb476f..537c2434e 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -169,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 4f5563391..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 @@ -187,7 +191,7 @@ u256 BoolType::literalValue(Literal const& _literal) const else if (_literal.getToken() == Token::FALSE_LITERAL) return u256(0); else - assert(false); + 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 190134d7a..4493b8037 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,11 @@ public: virtual unsigned getCalldataEncodedSize() const { return 0; } virtual std::string toString() const = 0; - virtual u256 literalValue(Literal const&) const { assert(false); } + virtual u256 literalValue(Literal const&) const + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " + "for type without literals.")); + } }; /** diff --git a/solc/main.cpp b/solc/main.cpp index 1cf466c72..04fee2905 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -84,21 +84,27 @@ int main(int argc, char** argv) ASTPointer ast; 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(cerr, exception, "Parser error", *scanner); return -1; } - - NameAndTypeResolver resolver; - try - { - resolver.resolveNamesAndTypes(*ast.get()); - } catch (DeclarationError const& exception) { SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); @@ -109,23 +115,26 @@ int main(int argc, char** argv) SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); return -1; } - - cout << "Syntax tree for the contract:" << endl; - dev::solidity::ASTPrinter printer(ast, sourceCode); - printer.print(cout); - - bytes instructions; - Compiler compiler; - try - { - compiler.compileContract(*ast); - instructions = compiler.getAssembledBytecode(); - } 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; + } cout << "EVM assembly:" << endl; compiler.streamAssembly(cout); From 052b74b1dcb0478c9bb08229c14481cae9d19f9f Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 15:04:33 +0100 Subject: [PATCH 38/77] Stylistic corrections. --- libsolidity/AST.cpp | 2 +- libsolidity/CompilerContext.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index f9c49adc5..026aef975 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -344,7 +344,7 @@ void ExpressionStatement::checkTypeRequirements() m_expression->checkTypeRequirements(); } -void Expression::expectType(const Type& _expectedType) +void Expression::expectType(Type const& _expectedType) { checkTypeRequirements(); if (!getType()->isImplicitlyConvertibleTo(_expectedType)) diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 44d0844c2..99cf090e0 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -41,7 +41,7 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables) } } -int CompilerContext::getStackPositionOfVariable(const Declaration& _declaration) +int CompilerContext::getStackPositionOfVariable(Declaration const& _declaration) { auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); if (asserts(res != m_localVariables.end())) @@ -49,7 +49,7 @@ int CompilerContext::getStackPositionOfVariable(const Declaration& _declaration) return end(m_localVariables) - res - 1 + m_asm.deposit(); } -eth::AssemblyItem CompilerContext::getFunctionEntryLabel(const FunctionDefinition& _function) const +eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const { auto res = m_functionEntryLabels.find(&_function); if (asserts(res != m_functionEntryLabels.end())) From 3b6ffcbe8d091e607c19604e938a5574a870a816 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 14:10:10 +0000 Subject: [PATCH 39/77] Minor fixes to Transaction. --- libethereum/Transaction.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index bb04bcab7..ba79f971c 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -51,11 +51,10 @@ public: 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; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } - Address safeSender() const noexcept; ///< Like sender() but will never throw. + Address safeSender() const noexcept; ///< Like sender() but will never throw. @returns a null Address if the signature is invalid. Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). - void sign(Secret _priv); ///< Sign the transaction. - bool isCreation() const { return !m_receiveAddress; } + bool isCreation() const { return m_type == ContractCreation; } void streamRLP(RLPStream& _s, bool _sig = true) const; @@ -74,6 +73,8 @@ public: SignatureStruct const& signature() const { return m_vrs; } private: + void sign(Secret _priv); ///< Sign the transaction. + Type m_type = NullTransaction; ///< True if this is a contract-creation transaction. F 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. From b813038c3c506fb66632c290dee38ae0ab0ebcfe Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 15:21:20 +0100 Subject: [PATCH 40/77] assert and exception corrections in solidity-external files. --- alethzero/MainWin.cpp | 4 ++++ libevmface/Instruction.h | 23 ++++++++++++++++++++--- liblll/Assembly.h | 10 +++++----- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 70f4b3017..dd417fbd3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1585,6 +1585,10 @@ void Main::on_data_textChanged() solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner); solidity = "

Solidity

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

Solidity

Uncaught exception.
"; + } } else { diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index 8392c410b..7cf205c03 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -32,6 +32,8 @@ namespace dev namespace eth { +class InvalidOpcode: public Exception {}; + /// Virtual machine bytecode instruction. enum class Instruction: uint8_t { @@ -177,13 +179,28 @@ enum class Instruction: uint8_t }; /// @returns the PUSH<_number> instruction -inline Instruction pushInstruction(unsigned _number) { assert(1 <= _number && _number <= 32); return Instruction(unsigned(Instruction::PUSH1) + _number - 1); } +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) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::DUP1) + _number - 1); } +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) { assert(1 <= _number && _number <= 16); return Instruction(unsigned(Instruction::SWAP1) + _number - 1); } +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/liblll/Assembly.h b/liblll/Assembly.h index 38baee0c5..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; } @@ -107,8 +107,8 @@ public: 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; assert(m_deposit >= 0); } - void setDeposit(int _deposit) { m_deposit = _deposit; assert(m_deposit >= 0); } + 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); From ef1c4d79671b9f6027b86db6cfe9d16e2d73b1ac Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 14:28:29 +0000 Subject: [PATCH 41/77] Documentation for Transaction. --- libethereum/Transaction.cpp | 8 ++-- libethereum/Transaction.h | 94 +++++++++++++++++++++++++++++-------- test/crypto.cpp | 4 +- test/vm.cpp | 2 +- 4 files changed, 82 insertions(+), 26 deletions(-) diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index c65421e04..cfbae92fc 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -71,7 +71,7 @@ Address Transaction::sender() const { if (!m_sender) { - auto p = recover(*(Signature const*)&m_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,12 +81,14 @@ Address Transaction::sender() const void Transaction::sign(Secret _priv) { - auto sig = dev::sign(_priv, sha3(false)); + 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 << m_nonce << m_gasPrice << m_gas; if (m_type == MessageCall) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index ba79f971c..56cc1295e 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -30,52 +30,104 @@ namespace dev namespace eth { +/// Named-boolean type to encode whether a signature be included in the serialisation process. +enum IncludeSignature +{ + 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: - enum Type - { - NullTransaction, - ContractCreation, - MessageCall - }; - + /// Constructs a null transaction. Transaction() {} + + /// 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. Transaction(bytesConstRef _rlp, bool _checkSender = false); + + /// Constructs a transaction from the given RLP. 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); } - Address safeSender() const noexcept; ///< Like sender() but will never throw. @returns a null Address if the signature is invalid. - Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). + /// @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; } + + /// @returns true if transaction is contract-creation. bool isCreation() const { return m_type == ContractCreation; } - void streamRLP(RLPStream& _s, bool _sig = true) const; + /// @returns true if transaction is message-call. + bool isMessageCall() const { return m_type == MessageCall; } - 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()); } + /// Serialises this transaction to an RLPStream. + void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature) const; - Type type() const { return m_type; } - u256 nonce() const { return m_nonce; } + /// @returns the RLP serialisation of this transaction. + bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } + + /// @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()); } + + /// @returns the amount of ETH to be transferred by this (message-call) transaction, in Wei. Synonym for endowment(). u256 value() const { return m_value; } - Address receiveAddress() const { return m_receiveAddress; } + /// @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: - void sign(Secret _priv); ///< Sign the transaction. + /// 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; ///< True if this is a contract-creation transaction. F + 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. @@ -84,11 +136,13 @@ private: 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; + 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 << "{"; diff --git a/test/crypto.cpp b/test/crypto.cpp index 2f5314421..cc35670af 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -397,8 +397,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/vm.cpp b/test/vm.cpp index 8344c0c5f..6ecfa8f68 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -375,7 +375,7 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = tx.type() == Transaction::ContractCreation ? "" : toString(tx.receiveAddress()); + o["destination"] = tx.isCreation() ? "" : toString(tx.receiveAddress()); push(o, "gasLimit", tx.gas()); push(o, "value", tx.value()); o["data"] = "0x" + toHex(tx.data()); From d5d81ea5c82e676312402e9cff77a16a6fd05f8b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 14:32:23 +0000 Subject: [PATCH 42/77] Transaction documentation and build fixes. --- alethzero/MainWin.cpp | 4 ++-- libethereum/State.cpp | 2 +- test/crypto.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 18270ff8c..e907352a7 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -946,7 +946,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; @@ -1266,7 +1266,7 @@ void Main::on_blocks_currentItemChanged() 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(false) << ""; + s << "
Msg: " << tx.sha3(eth::WithoutSignature) << ""; if (tx.isCreation()) { if (tx.data().size()) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c059922d5..f35d21946 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1126,7 +1126,7 @@ 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(); diff --git a/test/crypto.cpp b/test/crypto.cpp index cc35670af..de67ca99a 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -340,14 +340,14 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); - auto rlp = t.rlp(false); + auto rlp = t.rlp(eth::WithoutSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(false); - 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()); } @@ -364,14 +364,14 @@ int cryptoTest() assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); - auto rlp = t.rlp(false); + auto rlp = t.rlp(eth::WithoutSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(false); - 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()); } From 5eacc23cb1032cd851caecf43107d2c2d1a85aab Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Nov 2014 16:09:39 +0100 Subject: [PATCH 43/77] use boost_throw_exception --- libdevcrypto/Common.cpp | 2 +- libdevcrypto/EC.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 38d2eb934..d82098655 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -130,7 +130,7 @@ h256 Nonce::get(bool _commit) s_seed[i] = (byte)d(s_eng); } if (!s_seed) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); // prevent seed reuse if process terminates abnormally writeFile(s_seedFile, bytes()); diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index fd64f60d0..af6d0e65e 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -51,7 +51,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) sha3(s.ref(), s.ref()); if (!s || !_hash || !_priv) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); return std::move(s); } @@ -102,7 +102,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer k(kdf(_key, _hash).data(), 32); if (k == 0) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k); From 4256aa9cd308a376e4fbdaef9b1fb09ea0538e65 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 16:27:22 +0100 Subject: [PATCH 44/77] remove vmSystemOperationsTest completely --- test/vm.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 74d300b64..b4b5d5d82 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -782,11 +782,6 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) dev::test::executeTests("vmPushDupSwapTest"); } -//BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) -//{ -// dev::test::executeTests("vmSystemOperationsTest"); -//} - BOOST_AUTO_TEST_CASE(userDefinedFile) { From a6707cfadb6686255c3d262b8ed6432970f886c4 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 17:50:59 +0100 Subject: [PATCH 45/77] Fix test framework after change to Transaction. --- test/solidityEndToEndTest.cpp | 47 ++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 7bb01fa12..5aeaf3e61 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -39,39 +39,56 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } + ExecutionFramework(): m_executive(m_state) { g_logVerbosity = 0; } bytes compileAndRun(std::string const& _sourceCode) { bytes code = dev::solidity::CompilerStack::compile(_sourceCode); - eth::Executive ex(m_state); - BOOST_REQUIRE(!ex.create(Address(), 0, m_gasPrice, m_gas, &code, Address())); - BOOST_REQUIRE(ex.go()); - ex.finalize(); - m_contractAddress = ex.newAddress(); - return ex.out().toBytes(); + sendMessage(code, true); + m_contractAddress = m_executive.newAddress(); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + return m_output; } bytes callFunction(byte _index, bytes const& _data) { - bytes data = bytes(1, _index) + _data; - eth::Executive ex(m_state); - BOOST_REQUIRE(!ex.call(m_contractAddress, Address(), 0, m_gasPrice, &data, m_gas, Address())); - BOOST_REQUIRE(ex.go()); - ex.finalize(); - return ex.out().toBytes(); + sendMessage(bytes(1, _index) + _data, false); + return m_output; } - bytes callFunction(byte _index, u256 const& _argument) + bytes callFunction(byte _index, u256 const& _argument1) { - return callFunction(_index, toBigEndian(_argument)); + callFunction(_index, toBigEndian(_argument1)); + return m_output; } private: + void sendMessage(bytes const& _data, bool _isCreation) + { + 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 + m_executive.setup(&transactionRLP); + } + catch (...) {} + if (_isCreation) + BOOST_REQUIRE(!m_executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); + else + BOOST_REQUIRE(!m_executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); + BOOST_REQUIRE(m_executive.go()); + m_executive.finalize(); + m_output = m_executive.out().toBytes(); + } + Address m_contractAddress; eth::State m_state; + eth::Executive m_executive; u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gas = 1000000; + bytes m_output; }; BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest) From 49fcfb78e1c687e332f6470afb7f5d468756c5e8 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 18:30:38 +0100 Subject: [PATCH 46/77] Update transactions, style fix --- test/TestHelper.cpp | 61 +++++++++++++++++--------------------- test/state.cpp | 8 ++--- test/stateOriginal.cpp | 7 +---- test/vm.cpp | 14 ++------- test/vmSha3TestFiller.json | 30 +------------------ 5 files changed, 35 insertions(+), 85 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 68fdd748d..277c3351c 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -65,7 +65,7 @@ void connectClients(Client& c1, Client& c2) namespace test { -ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):m_TestObject(_o) +ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o) { importEnv(_o["env"].get_obj()); importState(_o["pre"].get_obj(), m_statePre); @@ -79,12 +79,12 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):m_TestObject(_o) void ImportTest::importEnv(json_spirit::mObject& _o) { - assert(_o.count("previousHash") > 0); - assert(_o.count("currentGasLimit") > 0); - assert(_o.count("currentDifficulty") > 0); - assert(_o.count("currentTimestamp") > 0); - assert(_o.count("currentCoinbase") > 0); - assert(_o.count("currentNumber") > 0); + 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"]); @@ -103,10 +103,10 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) { json_spirit::mObject o = i.second.get_obj(); - assert(o.count("balance") > 0); - assert(o.count("nonce") > 0); - assert(o.count("storage") > 0); - assert(o.count("code") > 0); + 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); @@ -115,8 +115,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) bytes code = importCode(o); - toInt(o["nonce"]); - if (toHex(code).size()) + if (code.size()) { _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); i.second.get_obj()["code"] = "0x" + toHex(code); //preperation for export @@ -134,23 +133,17 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) void ImportTest::importTransaction(json_spirit::mObject& _o) { - assert(_o.count("nonce")> 0); - assert(_o.count("gasPrice") > 0); - assert(_o.count("gasLimit") > 0); - assert(_o.count("to") > 0); - assert(_o.count("value") > 0); - assert(_o.count("secretKey") > 0); - assert(_o.count("data") > 0); - - m_transaction.nonce = toInt(_o["nonce"]); - m_transaction.gasPrice = toInt(_o["gasPrice"]); - m_transaction.gas = toInt(_o["gasLimit"]); - m_transaction.receiveAddress = Address(_o["to"].get_str()); - m_transaction.type = m_transaction.receiveAddress ? Transaction::MessageCall : Transaction::ContractCreation; - m_transaction.value = toInt(_o["value"]); - Secret secretKey = Secret(_o["secretKey"].get_str()); - m_transaction.sign(secretKey); - m_transaction.data = importData(_o); + BOOST_REQUIRE(_o.count("nonce")> 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) @@ -210,7 +203,7 @@ byte toByte(json_spirit::mValue const& _v) return 0; } -bytes importData(json_spirit::mObject & _o) +bytes importData(json_spirit::mObject& _o) { bytes data; if (_o["data"].type() == json_spirit::str_type) @@ -225,7 +218,7 @@ bytes importData(json_spirit::mObject & _o) return data; } -bytes importCode(json_spirit::mObject & _o) +bytes importCode(json_spirit::mObject& _o) { bytes code; if (_o["code"].type() == json_spirit::str_type) @@ -238,11 +231,11 @@ bytes importCode(json_spirit::mObject & _o) 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) +void checkOutput(bytes const& _output, json_spirit::mObject& _o) { int j = 0; if (_o["out"].type() == json_spirit::array_type) diff --git a/test/state.cpp b/test/state.cpp index 3a81821ef..2e313cc47 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -121,10 +121,10 @@ BOOST_AUTO_TEST_CASE(stExample) dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests); } -//BOOST_AUTO_TEST_CASE(stSystemOperationsTest) -//{ -// dev::test::executeStateTests("stSystemOperationsTest"); -//} +BOOST_AUTO_TEST_CASE(stSystemOperationsTest) +{ + dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); +} BOOST_AUTO_TEST_CASE(tmp) { diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index e6b3ab959..8344894f4 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -65,12 +65,7 @@ int stateTest() // Inject a transaction to transfer funds from miner to me. bytes tx; { - 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()); + Transaction t(1000, 0, 0, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); tx = t.rlp(); } diff --git a/test/vm.cpp b/test/vm.cpp index b9df6af2f..0457d7bbb 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -232,8 +232,8 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); Transaction t = tx["destination"].get_str().empty() ? - Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data) : - Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data); + 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); } } @@ -423,16 +423,6 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); } -BOOST_AUTO_TEST_CASE(vmNamecoin) -{ - dev::test::executeTests("vmNamecoin", "/VMTests", dev::test::doVMTests); -} - -//BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) -//{ -// dev::test::executeTests("vmSystemOperationsTest", "/VMTests", dev::test::doVMTests); -//} - BOOST_AUTO_TEST_CASE(userDefinedFile) { if (boost::unit_test::framework::master_test_suite().argc == 2) diff --git a/test/vmSha3TestFiller.json b/test/vmSha3TestFiller.json index 03391e8cb..beb1ea22f 100644 --- a/test/vmSha3TestFiller.json +++ b/test/vmSha3TestFiller.json @@ -167,7 +167,7 @@ } }, - "sha3_4": { + "sha3_5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -194,32 +194,4 @@ "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 100 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}", -// "storage": {} -// } -// }, -// "exec" : { -// "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", -// "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", -// "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", -// "value" : "1000000000000000000", -// "data" : "", -// "gasPrice" : "100000000000000", -// "gas" : "10000" -// } -// } } From 628e2048d8e10efbef882cb2ae4f1eee337445ff Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 5 Nov 2014 18:36:35 +0100 Subject: [PATCH 47/77] Corrected exception inheritance. --- libevmface/Instruction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index 7cf205c03..fadb5ab14 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -32,7 +32,7 @@ namespace dev namespace eth { -class InvalidOpcode: public Exception {}; +struct InvalidOpcode: virtual Exception {}; /// Virtual machine bytecode instruction. enum class Instruction: uint8_t From ca2f4ed2740dc50b20ab125a687c7dd24999ee49 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 17:39:44 +0000 Subject: [PATCH 48/77] Fix for State and Transaction. Serpent update. --- libethereum/Executive.cpp | 9 +- libethereum/State.cpp | 32 +- libethereum/Transaction.cpp | 2 +- libethereum/Transaction.h | 4 +- libserpent/bignum.cpp | 14 + libserpent/bignum.h | 12 +- libserpent/compiler.cpp | 212 +++++++-- libserpent/opcodes.h | 224 +++++----- libserpent/parser.cpp | 53 ++- libserpent/rewriter.cpp | 870 +++++++++++++++++++++++++++++++----- libserpent/tokenize.cpp | 2 +- libserpent/util.cpp | 22 + libserpent/util.h | 6 +- 13 files changed, 1145 insertions(+), 317 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index e14401972..71fc12a8c 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -184,15 +184,10 @@ bool Executive::go(OnOpFunc const& _onOp) { 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) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f35d21946..4aa916632 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1213,32 +1213,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 @@ -1281,16 +1278,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) { @@ -1317,8 +1311,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; } @@ -1380,7 +1372,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; @@ -1409,7 +1401,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/Transaction.cpp b/libethereum/Transaction.cpp index cfbae92fc..d94a31425 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -47,7 +47,7 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) 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; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 56cc1295e..490a2ac68 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -57,10 +57,10 @@ public: 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. - Transaction(bytesConstRef _rlp, bool _checkSender = false); + explicit Transaction(bytesConstRef _rlp, bool _checkSender = false); /// Constructs a transaction from the given RLP. - Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} + explicit Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} /// Checks equality of transactions. 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); From cd1d73008aec750d12c442a91c06b9967c2362f6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 17:40:40 +0000 Subject: [PATCH 49/77] Version bumps all round. --- libdevcore/Common.cpp | 2 +- libethcore/CommonEth.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 = { From 8ee9bcf87a3eec0628137b4b303817c45d8a3cc4 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 18:49:58 +0100 Subject: [PATCH 50/77] Further framework fix. --- test/solidityEndToEndTest.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 5aeaf3e61..b28b8499a 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -39,14 +39,12 @@ namespace test class ExecutionFramework { public: - ExecutionFramework(): m_executive(m_state) { g_logVerbosity = 0; } + ExecutionFramework() { g_logVerbosity = 0; } bytes compileAndRun(std::string const& _sourceCode) { bytes code = dev::solidity::CompilerStack::compile(_sourceCode); sendMessage(code, true); - m_contractAddress = m_executive.newAddress(); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); return m_output; } @@ -65,27 +63,31 @@ public: 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 - m_executive.setup(&transactionRLP); + executive.setup(&transactionRLP); } catch (...) {} if (_isCreation) - BOOST_REQUIRE(!m_executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); + { + 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(!m_executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); - BOOST_REQUIRE(m_executive.go()); - m_executive.finalize(); - m_output = m_executive.out().toBytes(); + 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; - eth::Executive m_executive; u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gas = 1000000; bytes m_output; From a89dc3eb110b8ad8f081193cf831a813df2daff8 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Nov 2014 19:04:14 +0100 Subject: [PATCH 51/77] fix crash on quit --- alethzero/MainWin.cpp | 6 ++++-- alethzero/MainWin.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e907352a7..e2b4cde1c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -149,7 +149,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 +160,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(); 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; }; From eed0b1651ce01394557ddda08adb390b5553e1c9 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 20:21:33 +0100 Subject: [PATCH 52/77] Moved code export to export function in ImportHelper --- test/TestHelper.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 277c3351c..b9c3223d6 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -27,7 +27,7 @@ #include #include -//#define FILL_TESTS +#define FILL_TESTS using namespace std; using namespace dev::eth; @@ -118,7 +118,6 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) if (code.size()) { _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); - i.second.get_obj()["code"] = "0x" + toHex(code); //preperation for export _state.m_cache[address].setCode(bytesConstRef(&code)); } else @@ -175,6 +174,29 @@ void ImportTest::exportTest(bytes _output, State& _statePost) 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) From 33bc5cb43177c4ecad59f2a9f166746ec8edbb21 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 21:02:16 +0100 Subject: [PATCH 53/77] Added dynamic jump out of code test --- test/vm.cpp | 2 +- test/vmIOandFlowOperationsTestFiller.json | 28 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/test/vm.cpp b/test/vm.cpp index 0457d7bbb..acede8001 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -213,7 +213,7 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = tx.type() == Transaction::ContractCreation ? "" : toString(tx.receiveAddress()); + o["destination"] = tx.isCreation() ? "" : toString(tx.receiveAddress()); push(o, "gasLimit", tx.gas()); push(o, "value", tx.value()); o["data"] = "0x" + toHex(tx.data()); diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index a3aec2696..e2ec1def1 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -642,6 +642,34 @@ } }, + "jump1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x620fffff620fffff0156", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "jumpi0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From e6e88c27afa17dd74654a7f02cbada5e756eada3 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 21:07:22 +0100 Subject: [PATCH 54/77] undefine FILL_TESTS --- test/TestHelper.cpp | 2 +- test/state.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b9c3223d6..ca46c2ca2 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -27,7 +27,7 @@ #include #include -#define FILL_TESTS +//#define FILL_TESTS using namespace std; using namespace dev::eth; diff --git a/test/state.cpp b/test/state.cpp index 2e313cc47..9c0a7188b 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -20,8 +20,6 @@ * State test functions. */ -#define FILL_TESTS - #include #include #include "JsonSpiritHeaders.h" From 9d035eb3176d72c3f59e2ac5d80d4a61334421eb Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 5 Nov 2014 21:55:10 +0100 Subject: [PATCH 55/77] style --- test/TestHelper.h | 6 +++--- test/vm.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/TestHelper.h b/test/TestHelper.h index d7ffe5cb5..622b83ac4 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -66,9 +66,9 @@ private: // 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); +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(); diff --git a/test/vm.cpp b/test/vm.cpp index acede8001..c6799daac 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -231,7 +231,7 @@ 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 = tx["destination"].get_str().empty() ? + 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); From 4eeb0eae1cd7f07205762b459fcd7bb1b9162abe Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 22:17:05 +0000 Subject: [PATCH 56/77] Compile warnings fixed. --- test/solidityCompiler.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 17de9af53..69d331339 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::DUP3), byte(Instruction::SWAP1), // assign b to d byte(Instruction::POP), - byte(Instruction::PUSH1), 0xa + shift, // jump to return + byte(Instruction::PUSH1), byte(0xa + shift), // jump to return byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::SWAP4), // store d and fetch return address @@ -119,11 +119,11 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), // initialized e and h - byte(Instruction::PUSH1), 0x20 + shift, // ret address + byte(Instruction::PUSH1), byte(0x20 + shift), // ret address byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x3, - byte(Instruction::PUSH1), 0x1 + shift, + byte(Instruction::PUSH1), byte(0x1 + shift), // stack here: ret e h 0x20 1 2 3 0x1 byte(Instruction::JUMP), byte(Instruction::JUMPDEST), @@ -158,24 +158,24 @@ BOOST_AUTO_TEST_CASE(ifStatement) bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x1b + shift, // "true" target + 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), 0x13 + shift, + byte(Instruction::PUSH1), byte(0x13 + shift), byte(Instruction::JUMPI), // "else" body byte(Instruction::PUSH1), 0x4f, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x17 + shift, // exit path of second part + 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), 0x1f + shift, + byte(Instruction::PUSH1), byte(0x1f + shift), byte(Instruction::JUMP), // "if" body byte(Instruction::JUMPDEST), @@ -201,23 +201,23 @@ BOOST_AUTO_TEST_CASE(loops) byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x21 + shift, + byte(Instruction::PUSH1), byte(0x21 + shift), byte(Instruction::JUMPI), byte(Instruction::PUSH1), 0x1, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x21 + shift, + byte(Instruction::PUSH1), byte(0x21 + shift), byte(Instruction::JUMP), // break byte(Instruction::PUSH1), 0x2, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2 + shift, + byte(Instruction::PUSH1), byte(0x2 + shift), byte(Instruction::JUMP), // continue byte(Instruction::PUSH1), 0x3, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x22 + shift, + byte(Instruction::PUSH1), byte(0x22 + shift), byte(Instruction::JUMP), // return byte(Instruction::PUSH1), 0x4, byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2 + shift, + byte(Instruction::PUSH1), byte(0x2 + shift), byte(Instruction::JUMP), byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), From 5dc7609c8080e59e8a7d053793a25e20038f8fe2 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 23:35:00 +0100 Subject: [PATCH 57/77] Minor cleanup. --- libsolidity/AST.cpp | 20 +------------------- libsolidity/AST.h | 4 ++-- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 026aef975..44cf39291 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -283,14 +283,6 @@ void WhileStatement::checkTypeRequirements() m_body->checkTypeRequirements(); } -void Continue::checkTypeRequirements() -{ -} - -void Break::checkTypeRequirements() -{ -} - void Return::checkTypeRequirements() { if (!m_expression) @@ -326,8 +318,6 @@ void VariableDefinition::checkTypeRequirements() void Assignment::checkTypeRequirements() { - //@todo lefthandside actually has to be assignable - // add a feature to the type system to check that m_leftHandSide->checkTypeRequirements(); if (!m_leftHandSide->isLvalue()) BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); @@ -366,8 +356,8 @@ void UnaryOperation::checkTypeRequirements() void BinaryOperation::checkTypeRequirements() { - m_right->checkTypeRequirements(); m_left->checkTypeRequirements(); + m_right->checkTypeRequirements(); if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType())) m_commonType = m_left->getType(); else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) @@ -446,14 +436,6 @@ void Identifier::checkTypeRequirements() 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? - // the only problem we get there is that in - // var x; - // x = 2; - // var y = x; - // the type of x is not yet determined. VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); if (variable) { diff --git a/libsolidity/AST.h b/libsolidity/AST.h index f42ff47d0..793ce863f 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -390,7 +390,7 @@ class Continue: public Statement public: Continue(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; - virtual void checkTypeRequirements() override; + virtual void checkTypeRequirements() override {} }; class Break: public Statement @@ -398,7 +398,7 @@ class Break: public Statement public: Break(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; - virtual void checkTypeRequirements() override; + virtual void checkTypeRequirements() override {} }; class Return: public Statement From 5bd4640b176d42a2a2b2fe9eef385c19c3b59928 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 13:24:35 +0100 Subject: [PATCH 58/77] Detect integer length from literals and remove "std::". --- libsolidity/AST.cpp | 2 ++ libsolidity/Types.cpp | 41 +++++++++++++++++++++++------------------ libsolidity/Types.h | 5 ++++- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 026aef975..536f04cbd 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -497,6 +497,8 @@ void ElementaryTypeNameExpression::checkTypeRequirements() void Literal::checkTypeRequirements() { m_type = Type::forLiteral(*this); + if (!m_type) + BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); } } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a4d70e3a0..8a1db1744 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -25,12 +25,14 @@ #include #include +using namespace std; + namespace dev { namespace solidity { -std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) +shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError()); @@ -44,52 +46,55 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) else bits = (1 << (bits - 1)) * 32; int modifier = offset / 5; - return std::make_shared(bits, + return make_shared(bits, modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED : IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) - return std::make_shared(0, IntegerType::Modifier::ADDRESS); + return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) - return std::make_shared(); + return make_shared(); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); - return std::shared_ptr(); + return shared_ptr(); } -std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) +shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) { - return std::make_shared(*_typeName.getReferencedStruct()); + return make_shared(*_typeName.getReferencedStruct()); } -std::shared_ptr Type::fromMapping(Mapping const&) +shared_ptr Type::fromMapping(Mapping const&) { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); - return std::shared_ptr(); + return shared_ptr(); } -std::shared_ptr Type::forLiteral(Literal const& _literal) +shared_ptr Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - return std::make_shared(); + return make_shared(); case Token::NUMBER: return IntegerType::smallestTypeForLiteral(_literal.getValue()); case Token::STRING_LITERAL: - return std::shared_ptr(); // @todo + return shared_ptr(); // @todo default: - return std::shared_ptr(); + return shared_ptr(); } } -std::shared_ptr IntegerType::smallestTypeForLiteral(std::string const&) +shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { - //@todo - return std::make_shared(256, Modifier::UNSIGNED); + bigint value(_literal); + unsigned bytes = max(bytesRequired(value), 1u); + if (bytes > 32) + return shared_ptr(); + return make_shared(bytes * 8, Modifier::UNSIGNED); } IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): @@ -155,11 +160,11 @@ bool IntegerType::operator==(Type const& _other) const return other.m_bits == m_bits && other.m_modifier == m_modifier; } -std::string IntegerType::toString() const +string IntegerType::toString() const { if (isAddress()) return "address"; - std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); + string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); return prefix + dev::toString(m_bits); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 4493b8037..8c88ca79f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -56,7 +56,8 @@ public: static std::shared_ptr fromMapping(Mapping const& _typeName); /// @} - /// Auto-detect the proper type for a literal + /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does + /// not fit any type. static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; @@ -95,6 +96,8 @@ public: }; virtual Category getCategory() const override { return Category::INTEGER; } + /// @returns the smallest integer type for the given literal or an empty pointer + /// if no type fits. static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); From bbf6c97e5bfcd37ff0d8dc7465c41302da315a09 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 15:01:07 +0100 Subject: [PATCH 59/77] Allow implicit type conversions for comparisons. --- libsolidity/AST.h | 3 +++ libsolidity/ExpressionCompiler.cpp | 21 +++++++-------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index f42ff47d0..f80031f42 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -565,12 +565,15 @@ public: Expression& getLeftExpression() const { return *m_left; } Expression& getRightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } + Type const& getCommonType() const { return *m_commonType; } private: ASTPointer m_left; Token::Value m_operator; ASTPointer m_right; + /// The common type that is used for the operation, not necessarily the result type (e.g. for + /// comparisons, this is always bool). std::shared_ptr m_commonType; }; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index d23579b11..a7d872217 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -113,7 +113,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) { Expression& leftExpression = _binaryOperation.getLeftExpression(); Expression& rightExpression = _binaryOperation.getRightExpression(); - Type const& resultType = *_binaryOperation.getType(); + Type const& commonType = _binaryOperation.getCommonType(); Token::Value const op = _binaryOperation.getOperator(); if (op == Token::AND || op == Token::OR) @@ -121,23 +121,16 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) // 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); + cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), commonType); rightExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); - appendOrdinaryBinaryOperatorCode(op, resultType); + cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), commonType); + if (Token::isCompareOp(op)) + appendCompareOperatorCode(op, commonType); + else + appendOrdinaryBinaryOperatorCode(op, commonType); } // do not visit the child nodes, we already did that explicitly From 2ece1f28bcbb6c8e1ddc92c81fc2f757041c517f Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 15:07:33 +0100 Subject: [PATCH 60/77] Tests for type conversion at comparison. --- test/solidityNameAndTypeResolution.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 9e34e6d0e..f46ad6733 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -162,6 +162,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison) +{ + char const* text = "contract test {\n" + " function f() { uint32(2) == int64(2); }" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid) +{ + char const* text = "contract test {\n" + " function f() { int32(2) == uint64(2); }" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) { char const* text = "contract test {\n" From bfafb32b0ba23cd14535fd2cd28e5e4cae11be33 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 15:29:08 +0100 Subject: [PATCH 61/77] More information for type expectation errors. --- libsolidity/AST.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 536f04cbd..e654dd575 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -347,9 +347,11 @@ void ExpressionStatement::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 + const Type& type = *getType(); + if (!type.isImplicitlyConvertibleTo(_expectedType)) + BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() + + " not implicitly convertible to expected type " + + _expectedType.toString() + ".")); } void UnaryOperation::checkTypeRequirements() @@ -373,14 +375,18 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " + + m_left->getType()->toString() + " vs. " + + m_right->getType()->toString())); if (Token::isCompareOp(m_operator)) m_type = make_shared(); else { m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + + " not compatible with type " + + m_commonType->toString())); } } From ab7d2c8fd1b4d6a602494e026f80cac0650d2e41 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 19:13:03 +0100 Subject: [PATCH 62/77] Proper type promotion and conversion. --- libsolidity/Compiler.cpp | 7 +-- libsolidity/ExpressionCompiler.cpp | 81 ++++++++++++++++++++---------- libsolidity/ExpressionCompiler.h | 10 +++- test/solidityEndToEndTest.cpp | 28 ++++++++++- 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 654eceadb..dfc351fae 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -273,7 +273,7 @@ bool Compiler::visit(Return& _return) { ExpressionCompiler::compileExpression(m_context, *expression); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); - ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), *firstVariable.getType()); + ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); int stackPosition = m_context.getStackPositionOfVariable(firstVariable); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } @@ -286,8 +286,9 @@ bool Compiler::visit(VariableDefinition& _variableDefinition) if (Expression* expression = _variableDefinition.getExpression()) { ExpressionCompiler::compileExpression(m_context, *expression); - ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), - *_variableDefinition.getDeclaration().getType()); + ExpressionCompiler::appendTypeConversion(m_context, + *expression->getType(), + *_variableDefinition.getDeclaration().getType()); int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration()); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a7d872217..0df741843 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -37,6 +37,13 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression _expression.accept(compiler); } +void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, + Type const& _typeOnStack, Type const& _targetType) +{ + ExpressionCompiler compiler(_context); + compiler.appendTypeConversion(_typeOnStack, _targetType); +} + bool ExpressionCompiler::visit(Assignment& _assignment) { m_currentLValue = nullptr; @@ -44,7 +51,7 @@ bool ExpressionCompiler::visit(Assignment& _assignment) Expression& rightHandSide = _assignment.getRightHandSide(); rightHandSide.accept(*this); Type const& resultType = *_assignment.getType(); - cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); + appendTypeConversion(*rightHandSide.getType(), resultType); _assignment.getLeftHandSide().accept(*this); Token::Value op = _assignment.getAssignmentOperator(); @@ -123,10 +130,21 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) } else { + bool cleanupNeeded = false; + if (commonType.getCategory() == Type::Category::INTEGER) + if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) + cleanupNeeded = true; + leftExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), commonType); + if (cleanupNeeded) + appendHighBitsCleanup(dynamic_cast(*leftExpression.getType())); + else + appendTypeConversion(*leftExpression.getType(), commonType); rightExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), commonType); + if (cleanupNeeded) + appendHighBitsCleanup(dynamic_cast(*leftExpression.getType())); + else + appendTypeConversion(*rightExpression.getType(), commonType); if (Token::isCompareOp(op)) appendCompareOperatorCode(op, commonType); else @@ -146,7 +164,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) BOOST_THROW_EXCEPTION(InternalCompilerError()); Expression& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); - cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); + appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); } else { @@ -163,7 +181,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(), + appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); } @@ -226,28 +244,6 @@ void ExpressionCompiler::endVisit(Literal& _literal) } } -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(); @@ -372,6 +368,37 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) } } +void ExpressionCompiler::appendTypeConversion(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) + { + appendHighBitsCleanup(dynamic_cast(_typeOnStack)); + } + else + { + // All other types should not be convertible to non-equal types. + assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); + assert(false); + } +} + +void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) +{ + if (_typeOnStack.getNumBits() == 256) + return; + else if (_typeOnStack.isSigned()) + m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND; + else + m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; +} + void ExpressionCompiler::storeInLValue(Expression const& _expression) { moveToLValue(_expression); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index a930723cc..7c731ec7f 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -26,6 +26,8 @@ namespace dev { namespace solidity { class CompilerContext; // forward +class Type; // forward +class IntegerType; // forward /// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream /// of EVM instructions. It needs a compiler context that is the same for the whole compilation @@ -37,7 +39,7 @@ public: 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); + static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); private: ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} @@ -62,6 +64,12 @@ private: void appendShiftOperatorCode(Token::Value _operator); /// @} + /// Appends an implicit or explicit type conversion. For now this comprises only erasing + /// higher-order bits (@see appendHighBitCleanup) when widening integer types. + void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType); + //// Appends code that cleans higher-order bits for integer types. + void appendHighBitsCleanup(IntegerType const& _typeOnStack); + /// 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); diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index b28b8499a..b4da53ba6 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -219,7 +219,33 @@ BOOST_AUTO_TEST_CASE(short_circuiting) BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8))); } -//@todo test smaller types +BOOST_AUTO_TEST_CASE(high_bits_cleaning) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffffff) + 10;\n" + " if (x >= 0xffffffff) return 0;\n" + " return x;" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(9))); +} + +BOOST_AUTO_TEST_CASE(sign_extension) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " int64 x = -int32(0xff);\n" + " if (x >= 0xff) return 0;\n" + " return -uint256(x);" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, bytes()) == bytes(32, 0xff)); +} BOOST_AUTO_TEST_SUITE_END() From 6ec55d3d5f6b3924516c91fb76d299fe14841314 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 4 Nov 2014 21:29:36 +0100 Subject: [PATCH 63/77] Type promotion fixes and tests. --- libsolidity/ExpressionCompiler.cpp | 16 ++++------- libsolidity/ExpressionCompiler.h | 4 ++- test/solidityCompiler.cpp | 8 +++--- test/solidityEndToEndTest.cpp | 42 ++++++++++++++++++++++++++++- test/solidityExpressionCompiler.cpp | 33 ++++++++++++----------- 5 files changed, 71 insertions(+), 32 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 0df741843..324cd10d0 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -136,15 +136,9 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) cleanupNeeded = true; leftExpression.accept(*this); - if (cleanupNeeded) - appendHighBitsCleanup(dynamic_cast(*leftExpression.getType())); - else - appendTypeConversion(*leftExpression.getType(), commonType); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); rightExpression.accept(*this); - if (cleanupNeeded) - appendHighBitsCleanup(dynamic_cast(*leftExpression.getType())); - else - appendTypeConversion(*rightExpression.getType(), commonType); + appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); if (Token::isCompareOp(op)) appendCompareOperatorCode(op, commonType); else @@ -368,20 +362,20 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType) +void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) { // 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) + if (_typeOnStack == _targetType && !_cleanupNeeded) return; if (_typeOnStack.getCategory() == Type::Category::INTEGER) { appendHighBitsCleanup(dynamic_cast(_typeOnStack)); } - else + else if (_typeOnStack != _targetType) { // All other types should not be convertible to non-equal types. assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 7c731ec7f..d67814be0 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -66,7 +66,9 @@ private: /// Appends an implicit or explicit type conversion. For now this comprises only erasing /// higher-order bits (@see appendHighBitCleanup) when widening integer types. - void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType); + /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be + /// necessary. + void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); //// Appends code that cleans higher-order bits for integer types. void appendHighBitsCleanup(IntegerType const& _typeOnStack); diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 69d331339..192fd61a4 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) 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), 0x29 + shift, // ret address + byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), byte(0x1 + shift), // stack here: ret e h 0x20 1 2 3 0x1 byte(Instruction::JUMP), diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index b4da53ba6..c60d6887e 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -192,6 +192,21 @@ BOOST_AUTO_TEST_CASE(many_local_variables) == toBigEndian(u256(0x121121))); } +BOOST_AUTO_TEST_CASE(packing_unpacking_types) +{ + char const* sourceCode = "contract test {\n" + " function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n" + " if (a) y = 1;\n" + " y = y * 0x100000000 | ~b;\n" + " y = y * 0x10000000000000000 | ~c;\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); +} + BOOST_AUTO_TEST_CASE(multiple_return_values) { char const* sourceCode = "contract test {\n" @@ -244,7 +259,32 @@ BOOST_AUTO_TEST_CASE(sign_extension) "}\n"; ExecutionFramework framework; framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()) == bytes(32, 0xff)); + BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xff))); +} + +BOOST_AUTO_TEST_CASE(small_unsigned_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffff) * 0xffffff;\n" + " return x / 0x100;" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xfffe0000))); +} + +BOOST_AUTO_TEST_CASE(small_signed_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(int256 y) {\n" + " return -int32(10) * -int64(20);\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(200))); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 561cc3bda..3be909c32 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(comparison) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, - byte(eth::Instruction::PUSH2), 0x11, 0xaa, + bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::GT), byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::EQ), @@ -172,16 +172,16 @@ BOOST_AUTO_TEST_CASE(short_circuiting) bytes expectation({byte(eth::Instruction::PUSH1), 0xa, byte(eth::Instruction::PUSH1), 0x8, - byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH1), 0x4, + byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::GT), byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::PUSH1), 0x20, byte(eth::Instruction::JUMPI), // short-circuit if it is true byte(eth::Instruction::POP), - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::PUSH1), 0x9, + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO), // after this we have 2 != 9 byte(eth::Instruction::JUMPDEST), @@ -197,10 +197,11 @@ BOOST_AUTO_TEST_CASE(arithmetics) " 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), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x3, + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0x5, byte(eth::Instruction::PUSH1), 0x6, @@ -213,8 +214,10 @@ BOOST_AUTO_TEST_CASE(arithmetics) byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::SWAP1), byte(eth::Instruction::MOD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::SWAP1), byte(eth::Instruction::DIV), byte(eth::Instruction::MUL)}); @@ -231,8 +234,8 @@ BOOST_AUTO_TEST_CASE(unary_operators) 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::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); @@ -305,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment) byte(eth::Instruction::POP), byte(eth::Instruction::DUP2), // Stack here: a+b b a+b - byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -320,17 +323,17 @@ BOOST_AUTO_TEST_CASE(function_call) {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(eth::Instruction::PUSH1), 0x0a, + bytes expectation({byte(eth::Instruction::PUSH1), 0x0d, byte(eth::Instruction::DUP3), - byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::ADD), // Stack here: a b (a+1) byte(eth::Instruction::DUP3), - byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::PUSH1), 0x1a, byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMPDEST), // Stack here: a b g(a+1, b) - byte(eth::Instruction::PUSH1), 0x02, + byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::MUL), // Stack here: a b g(a+1, b)*2 byte(eth::Instruction::DUP3), From 8b226a79063f0ed6c4c552c2ddadaeb2994bf81e Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 6 Nov 2014 01:39:59 +0100 Subject: [PATCH 64/77] Fixes for test framework (sign the transaction). --- test/solidityEndToEndTest.cpp | 111 +++++++++++++++------------------- 1 file changed, 49 insertions(+), 62 deletions(-) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index c60d6887e..dc8d34cb7 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -41,31 +41,31 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes compileAndRun(std::string const& _sourceCode) + bytes const& compileAndRun(std::string const& _sourceCode) { bytes code = dev::solidity::CompilerStack::compile(_sourceCode); sendMessage(code, true); + BOOST_REQUIRE(!m_output.empty()); return m_output; } - bytes callFunction(byte _index, bytes const& _data) + bytes const& callFunction(byte _index, bytes const& _data) { sendMessage(bytes(1, _index) + _data, false); return m_output; } - bytes callFunction(byte _index, u256 const& _argument1) + bytes const& callFunction(byte _index, u256 const& _argument1) { - callFunction(_index, toBigEndian(_argument1)); - return m_output; + return callFunction(_index, toBigEndian(_argument1)); } 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); + eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) + : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); bytes transactionRLP = t.rlp(); try { @@ -77,13 +77,14 @@ private: { BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); } else BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); BOOST_REQUIRE(executive.go()); executive.finalize(); - m_output = executive.out().toBytes(); + m_output = executive.out().toVector(); } Address m_contractAddress; @@ -93,27 +94,24 @@ private: bytes m_output; }; -BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest) +BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework) BOOST_AUTO_TEST_CASE(smoke_test) { char const* sourceCode = "contract test {\n" " function f(uint a) returns(uint d) { return a * 7; }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); + compileAndRun(sourceCode); u256 a = 0x200030004; - bytes result = framework.callFunction(0, a); - BOOST_CHECK(result == toBigEndian(a * 7)); + BOOST_CHECK(callFunction(0, a) == 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()); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()).empty()); } BOOST_AUTO_TEST_CASE(recursive_calls) @@ -124,13 +122,12 @@ BOOST_AUTO_TEST_CASE(recursive_calls) " 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))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); } BOOST_AUTO_TEST_CASE(while_loop) @@ -142,13 +139,12 @@ BOOST_AUTO_TEST_CASE(while_loop) " 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))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); } BOOST_AUTO_TEST_CASE(calling_other_functions) @@ -168,13 +164,12 @@ BOOST_AUTO_TEST_CASE(calling_other_functions) " 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))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1))); } BOOST_AUTO_TEST_CASE(many_local_variables) @@ -186,9 +181,8 @@ BOOST_AUTO_TEST_CASE(many_local_variables) " 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))) + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) == toBigEndian(u256(0x121121))); } @@ -201,9 +195,8 @@ BOOST_AUTO_TEST_CASE(packing_unpacking_types) " y = y * 0x10000000000000000 | ~c;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); } @@ -214,9 +207,8 @@ BOOST_AUTO_TEST_CASE(multiple_return_values) " y1 = x2; y2 = x1;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); } @@ -228,10 +220,9 @@ BOOST_AUTO_TEST_CASE(short_circuiting) " 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))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(8))); } BOOST_AUTO_TEST_CASE(high_bits_cleaning) @@ -243,9 +234,8 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning) " return x;" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(9))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(9))); } BOOST_AUTO_TEST_CASE(sign_extension) @@ -257,9 +247,8 @@ BOOST_AUTO_TEST_CASE(sign_extension) " return -uint256(x);" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xff))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xff))); } BOOST_AUTO_TEST_CASE(small_unsigned_types) @@ -270,9 +259,8 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types) " return x / 0x100;" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xfffe0000))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xfe0000))); } BOOST_AUTO_TEST_CASE(small_signed_types) @@ -282,9 +270,8 @@ BOOST_AUTO_TEST_CASE(small_signed_types) " return -int32(10) * -int64(20);\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(200))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(200))); } BOOST_AUTO_TEST_SUITE_END() From d8ad4f5910eb208a39048ef2e358fe96c54aea3e Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 11:38:26 +0100 Subject: [PATCH 65/77] Keywords for all integer types. --- libsolidity/Scanner.cpp | 84 +++++++++++++++++++++++++++++++++++++++++ libsolidity/Token.h | 84 +++++++++++++++++++++++++++++++++++++++++ libsolidity/Types.cpp | 18 ++++----- 3 files changed, 176 insertions(+), 10 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index c36820317..63deba495 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -556,17 +556,73 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("function", Token::FUNCTION) \ KEYWORD_GROUP('h') \ KEYWORD("hash", Token::HASH) \ + KEYWORD("hash8", Token::HASH8) \ + KEYWORD("hash16", Token::HASH16) \ + KEYWORD("hash24", Token::HASH24) \ KEYWORD("hash32", Token::HASH32) \ + KEYWORD("hash40", Token::HASH40) \ + KEYWORD("hash48", Token::HASH48) \ + KEYWORD("hash56", Token::HASH56) \ KEYWORD("hash64", Token::HASH64) \ + KEYWORD("hash72", Token::HASH72) \ + KEYWORD("hash80", Token::HASH80) \ + KEYWORD("hash88", Token::HASH88) \ + KEYWORD("hash96", Token::HASH96) \ + KEYWORD("hash104", Token::HASH104) \ + KEYWORD("hash112", Token::HASH112) \ + KEYWORD("hash120", Token::HASH120) \ KEYWORD("hash128", Token::HASH128) \ + KEYWORD("hash136", Token::HASH136) \ + KEYWORD("hash144", Token::HASH144) \ + KEYWORD("hash152", Token::HASH152) \ + KEYWORD("hash160", Token::HASH160) \ + KEYWORD("hash168", Token::HASH168) \ + KEYWORD("hash178", Token::HASH176) \ + KEYWORD("hash184", Token::HASH184) \ + KEYWORD("hash192", Token::HASH192) \ + KEYWORD("hash200", Token::HASH200) \ + KEYWORD("hash208", Token::HASH208) \ + KEYWORD("hash216", Token::HASH216) \ + KEYWORD("hash224", Token::HASH224) \ + KEYWORD("hash232", Token::HASH232) \ + KEYWORD("hash240", Token::HASH240) \ + KEYWORD("hash248", Token::HASH248) \ KEYWORD("hash256", Token::HASH256) \ KEYWORD_GROUP('i') \ KEYWORD("if", Token::IF) \ KEYWORD("in", Token::IN) \ KEYWORD("int", Token::INT) \ + KEYWORD("int8", Token::INT8) \ + KEYWORD("int16", Token::INT16) \ + KEYWORD("int24", Token::INT24) \ KEYWORD("int32", Token::INT32) \ + KEYWORD("int40", Token::INT40) \ + KEYWORD("int48", Token::INT48) \ + KEYWORD("int56", Token::INT56) \ KEYWORD("int64", Token::INT64) \ + KEYWORD("int72", Token::INT72) \ + KEYWORD("int80", Token::INT80) \ + KEYWORD("int88", Token::INT88) \ + KEYWORD("int96", Token::INT96) \ + KEYWORD("int104", Token::INT104) \ + KEYWORD("int112", Token::INT112) \ + KEYWORD("int120", Token::INT120) \ KEYWORD("int128", Token::INT128) \ + KEYWORD("int136", Token::INT136) \ + KEYWORD("int144", Token::INT144) \ + KEYWORD("int152", Token::INT152) \ + KEYWORD("int160", Token::INT160) \ + KEYWORD("int168", Token::INT168) \ + KEYWORD("int178", Token::INT176) \ + KEYWORD("int184", Token::INT184) \ + KEYWORD("int192", Token::INT192) \ + KEYWORD("int200", Token::INT200) \ + KEYWORD("int208", Token::INT208) \ + KEYWORD("int216", Token::INT216) \ + KEYWORD("int224", Token::INT224) \ + KEYWORD("int232", Token::INT232) \ + KEYWORD("int240", Token::INT240) \ + KEYWORD("int248", Token::INT248) \ KEYWORD("int256", Token::INT256) \ KEYWORD_GROUP('l') \ KEYWORD_GROUP('m') \ @@ -591,9 +647,37 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD_GROUP('u') \ KEYWORD("uint", Token::UINT) \ + KEYWORD("uint8", Token::UINT8) \ + KEYWORD("uint16", Token::UINT16) \ + KEYWORD("uint24", Token::UINT24) \ KEYWORD("uint32", Token::UINT32) \ + KEYWORD("uint40", Token::UINT40) \ + KEYWORD("uint48", Token::UINT48) \ + KEYWORD("uint56", Token::UINT56) \ KEYWORD("uint64", Token::UINT64) \ + KEYWORD("uint72", Token::UINT72) \ + KEYWORD("uint80", Token::UINT80) \ + KEYWORD("uint88", Token::UINT88) \ + KEYWORD("uint96", Token::UINT96) \ + KEYWORD("uint104", Token::UINT104) \ + KEYWORD("uint112", Token::UINT112) \ + KEYWORD("uint120", Token::UINT120) \ KEYWORD("uint128", Token::UINT128) \ + KEYWORD("uint136", Token::UINT136) \ + KEYWORD("uint144", Token::UINT144) \ + KEYWORD("uint152", Token::UINT152) \ + KEYWORD("uint160", Token::UINT160) \ + KEYWORD("uint168", Token::UINT168) \ + KEYWORD("uint178", Token::UINT176) \ + KEYWORD("uint184", Token::UINT184) \ + KEYWORD("uint192", Token::UINT192) \ + KEYWORD("uint200", Token::UINT200) \ + KEYWORD("uint208", Token::UINT208) \ + KEYWORD("uint216", Token::UINT216) \ + KEYWORD("uint224", Token::UINT224) \ + KEYWORD("uint232", Token::UINT232) \ + KEYWORD("uint240", Token::UINT240) \ + KEYWORD("uint248", Token::UINT248) \ KEYWORD("uint256", Token::UINT256) \ KEYWORD("ureal", Token::UREAL) \ KEYWORD_GROUP('v') \ diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 0fb9b670f..67971c3d0 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -169,19 +169,103 @@ namespace solidity * the implementation in Types.cpp has to be synced to this here * TODO more to be added */ \ K(INT, "int", 0) \ + K(INT8, "int8", 0) \ + K(INT16, "int16", 0) \ + K(INT24, "int24", 0) \ K(INT32, "int32", 0) \ + K(INT40, "int40", 0) \ + K(INT48, "int48", 0) \ + K(INT56, "int56", 0) \ K(INT64, "int64", 0) \ + K(INT72, "int72", 0) \ + K(INT80, "int80", 0) \ + K(INT88, "int88", 0) \ + K(INT96, "int96", 0) \ + K(INT104, "int104", 0) \ + K(INT112, "int112", 0) \ + K(INT120, "int120", 0) \ K(INT128, "int128", 0) \ + K(INT136, "int136", 0) \ + K(INT144, "int144", 0) \ + K(INT152, "int152", 0) \ + K(INT160, "int160", 0) \ + K(INT168, "int168", 0) \ + K(INT176, "int178", 0) \ + K(INT184, "int184", 0) \ + K(INT192, "int192", 0) \ + K(INT200, "int200", 0) \ + K(INT208, "int208", 0) \ + K(INT216, "int216", 0) \ + K(INT224, "int224", 0) \ + K(INT232, "int232", 0) \ + K(INT240, "int240", 0) \ + K(INT248, "int248", 0) \ K(INT256, "int256", 0) \ K(UINT, "uint", 0) \ + K(UINT8, "uint8", 0) \ + K(UINT16, "uint16", 0) \ + K(UINT24, "uint24", 0) \ K(UINT32, "uint32", 0) \ + K(UINT40, "uint40", 0) \ + K(UINT48, "uint48", 0) \ + K(UINT56, "uint56", 0) \ K(UINT64, "uint64", 0) \ + K(UINT72, "uint72", 0) \ + K(UINT80, "uint80", 0) \ + K(UINT88, "uint88", 0) \ + K(UINT96, "uint96", 0) \ + K(UINT104, "uint104", 0) \ + K(UINT112, "uint112", 0) \ + K(UINT120, "uint120", 0) \ K(UINT128, "uint128", 0) \ + K(UINT136, "uint136", 0) \ + K(UINT144, "uint144", 0) \ + K(UINT152, "uint152", 0) \ + K(UINT160, "uint160", 0) \ + K(UINT168, "uint168", 0) \ + K(UINT176, "uint178", 0) \ + K(UINT184, "uint184", 0) \ + K(UINT192, "uint192", 0) \ + K(UINT200, "uint200", 0) \ + K(UINT208, "uint208", 0) \ + K(UINT216, "uint216", 0) \ + K(UINT224, "uint224", 0) \ + K(UINT232, "uint232", 0) \ + K(UINT240, "uint240", 0) \ + K(UINT248, "uint248", 0) \ K(UINT256, "uint256", 0) \ K(HASH, "hash", 0) \ + K(HASH8, "hash8", 0) \ + K(HASH16, "hash16", 0) \ + K(HASH24, "hash24", 0) \ K(HASH32, "hash32", 0) \ + K(HASH40, "hash40", 0) \ + K(HASH48, "hash48", 0) \ + K(HASH56, "hash56", 0) \ K(HASH64, "hash64", 0) \ + K(HASH72, "hash72", 0) \ + K(HASH80, "hash80", 0) \ + K(HASH88, "hash88", 0) \ + K(HASH96, "hash96", 0) \ + K(HASH104, "hash104", 0) \ + K(HASH112, "hash112", 0) \ + K(HASH120, "hash120", 0) \ K(HASH128, "hash128", 0) \ + K(HASH136, "hash136", 0) \ + K(HASH144, "hash144", 0) \ + K(HASH152, "hash152", 0) \ + K(HASH160, "hash160", 0) \ + K(HASH168, "hash168", 0) \ + K(HASH176, "hash178", 0) \ + K(HASH184, "hash184", 0) \ + K(HASH192, "hash192", 0) \ + K(HASH200, "hash200", 0) \ + K(HASH208, "hash208", 0) \ + K(HASH216, "hash216", 0) \ + K(HASH224, "hash224", 0) \ + K(HASH232, "hash232", 0) \ + K(HASH240, "hash240", 0) \ + K(HASH248, "hash248", 0) \ K(HASH256, "hash256", 0) \ K(ADDRESS, "address", 0) \ K(BOOL, "bool", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 8a1db1744..334f50444 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -40,16 +40,14 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { int offset = _typeToken - Token::INT; - int bits = offset % 5; - if (bits == 0) - bits = 256; - else - bits = (1 << (bits - 1)) * 32; - int modifier = offset / 5; - return make_shared(bits, - modifier == 0 ? IntegerType::Modifier::SIGNED : - modifier == 1 ? IntegerType::Modifier::UNSIGNED : - IntegerType::Modifier::HASH); + int bytes = offset % 33; + if (bytes == 0) + bytes = 32; + int modifier = offset / 33; + return make_shared(bytes * 8, + modifier == 0 ? IntegerType::Modifier::SIGNED : + modifier == 1 ? IntegerType::Modifier::UNSIGNED : + IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) return make_shared(0, IntegerType::Modifier::ADDRESS); From 1b9e0143742dd8e188b2be941853b89e6b56269c Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 08:40:21 +0100 Subject: [PATCH 66/77] Support for negative literals. --- libsolidity/Scanner.cpp | 22 ++++++++-------- libsolidity/Scanner.h | 2 +- libsolidity/Types.cpp | 8 +++--- test/solidityExpressionCompiler.cpp | 41 ++++++++++++++++++++++++++++- test/solidityScanner.cpp | 26 +++++++++++++++--- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 63deba495..b13e52d7e 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -271,7 +271,7 @@ void Scanner::scanToken() token = Token::ADD; break; case '-': - // - -- -= + // - -- -= Number advance(); if (m_char == '-') { @@ -280,6 +280,8 @@ void Scanner::scanToken() } else if (m_char == '=') token = selectToken(Token::ASSIGN_SUB); + else if (m_char == '.' || IsDecimalDigit(m_char)) + token = scanNumber('-'); else token = Token::SUB; break; @@ -331,7 +333,7 @@ void Scanner::scanToken() // . Number advance(); if (IsDecimalDigit(m_char)) - token = scanNumber(true); + token = scanNumber('.'); else token = Token::PERIOD; break; @@ -372,7 +374,7 @@ void Scanner::scanToken() if (IsIdentifierStart(m_char)) token = scanIdentifierOrKeyword(); else if (IsDecimalDigit(m_char)) - token = scanNumber(false); + token = scanNumber(); else if (skipWhitespace()) token = Token::WHITESPACE; else if (isSourcePastEndOfInput()) @@ -461,14 +463,11 @@ void Scanner::scanDecimalDigits() } -Token::Value Scanner::scanNumber(bool _periodSeen) +Token::Value Scanner::scanNumber(char _charSeen) { - // 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; + enum { DECIMAL, HEX, BINARY } kind = DECIMAL; LiteralScope literal(this); - if (_periodSeen) + if (_charSeen == '.') { // we have already seen a decimal point of the float addLiteralChar('.'); @@ -476,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen) } else { + if (_charSeen == '-') + addLiteralChar('-'); // if the first character is '0' we must check for octals and hex if (m_char == '0') { addLiteralCharAndAdvance(); - // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or - // an octal number. + // either 0, 0exxx, 0Exxx, 0.xxx or a hex number if (m_char == 'x' || m_char == 'X') { // hex number diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 537c2434e..997365f3c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -180,7 +180,7 @@ private: Token::Value skipMultiLineComment(); void scanDecimalDigits(); - Token::Value scanNumber(bool _periodSeen); + Token::Value scanNumber(char _charSeen = 0); Token::Value scanIdentifierOrKeyword(); Token::Value scanString(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 334f50444..7354255e1 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -89,10 +89,14 @@ shared_ptr Type::forLiteral(Literal const& _literal) shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { bigint value(_literal); + bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-'); + if (isSigned) + // convert to positive number of same bit requirements + value = ((-value) - 1) << 1; unsigned bytes = max(bytesRequired(value), 1u); if (bytes > 32) return shared_ptr(); - return make_shared(bytes * 8, Modifier::UNSIGNED); + return make_shared(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED); } IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): @@ -169,8 +173,6 @@ string IntegerType::toString() const u256 IntegerType::literalValue(Literal const& _literal) const { bigint value(_literal.getValue()); - //@todo check that the number is not too large - //@todo does this work for signed numbers? return u256(value); } diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 3be909c32..8fc4a1a22 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(arithmetics) BOOST_AUTO_TEST_CASE(unary_operators) { char const* sourceCode = "contract test {\n" - " function f() { var x = !(~+-1 == 2); }" + " function f() { var x = !(~+- 1 == 2); }" "}\n"; bytes code = compileFirstExpression(sourceCode); @@ -347,6 +347,45 @@ BOOST_AUTO_TEST_CASE(function_call) BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } +BOOST_AUTO_TEST_CASE(negative_literals_8bits) +{ + // these all fit in 8 bits + char const* sourceCode = "contract test {\n" + " function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + + bytes({byte(eth::Instruction::ADD)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(negative_literals_16bits) +{ + // -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible + // from the SIGNEXTEND opcodes + char const* sourceCode = "contract test {\n" + " function f() { int64 x = int64(-1 + -129); }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::SIGNEXTEND), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::SIGNEXTEND)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index d2a960cfb..d714699a0 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers) BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); } +BOOST_AUTO_TEST_CASE(negative_numbers) +{ + Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9"); + BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_CASE(locations) { Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment")); @@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations) BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); - BOOST_CHECK_EQUAL(scanner.next(), Token::SUB); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27); + BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); From 8e02768b104b563fe28a1b70894f7f910b3124fb Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 18:37:27 +0100 Subject: [PATCH 67/77] Tests for break and continue in nested loops. --- test/solidityEndToEndTest.cpp | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index b28b8499a..7b9e07384 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -151,6 +151,42 @@ BOOST_AUTO_TEST_CASE(while_loop) BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); } +BOOST_AUTO_TEST_CASE(nested_loops) +{ + // tests that break and continue statements in nested loops jump to the correct place + char const* sourceCode = "contract test {\n" + " function f(uint x) returns(uint y) {\n" + " while (x > 1) {\n" + " if (x == 10) break;\n" + " while (x > 5) {\n" + " if (x == 8) break;\n" + " x--;\n" + " if (x == 6) continue;\n" + " return x;\n" + " }\n" + " x--;\n" + " if (x == 3) continue;\n" + " break;\n" + " }\n" + " return x;\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(1))); + BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(2))); + BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(2))); + BOOST_CHECK(framework.callFunction(0, u256(5)) == toBigEndian(u256(4))); + BOOST_CHECK(framework.callFunction(0, u256(6)) == toBigEndian(u256(5))); + BOOST_CHECK(framework.callFunction(0, u256(7)) == toBigEndian(u256(5))); + BOOST_CHECK(framework.callFunction(0, u256(8)) == toBigEndian(u256(7))); + BOOST_CHECK(framework.callFunction(0, u256(9)) == toBigEndian(u256(8))); + BOOST_CHECK(framework.callFunction(0, u256(10)) == toBigEndian(u256(10))); + BOOST_CHECK(framework.callFunction(0, u256(11)) == toBigEndian(u256(10))); +} + BOOST_AUTO_TEST_CASE(calling_other_functions) { // note that the index of a function is its index in the sorted sequence of functions From c87f1c76b4f36d816bc84eb5e0830a7855468b16 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 18:44:05 +0100 Subject: [PATCH 68/77] Ignore break and continue outside of loops. --- libsolidity/Compiler.cpp | 10 ++++------ test/solidityEndToEndTest.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 654eceadb..d05552b9e 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -252,17 +252,15 @@ bool Compiler::visit(WhileStatement& _whileStatement) bool Compiler::visit(Continue&) { - if (asserts(!m_continueTags.empty())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"continue\".")); - m_context.appendJumpTo(m_continueTags.back()); + if (!m_continueTags.empty()) + m_context.appendJumpTo(m_continueTags.back()); return false; } bool Compiler::visit(Break&) { - if (asserts(!m_breakTags.empty())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"break\".")); - m_context.appendJumpTo(m_breakTags.back()); + if (!m_breakTags.empty()) + m_context.appendJumpTo(m_breakTags.back()); return false; } diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 7b9e07384..116310aed 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -151,6 +151,19 @@ BOOST_AUTO_TEST_CASE(while_loop) BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); } +BOOST_AUTO_TEST_CASE(break_outside_loop) +{ + // break and continue outside loops should be simply ignored + char const* sourceCode = "contract test {\n" + " function f(uint x) returns(uint y) {\n" + " break; continue; return 2;\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(2))); +} + BOOST_AUTO_TEST_CASE(nested_loops) { // tests that break and continue statements in nested loops jump to the correct place From 99882a76a722e9836a31110be0cbe3361ddc0f0f Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 6 Nov 2014 14:50:18 +0100 Subject: [PATCH 69/77] Moved instructions and assembly to new libevmcore. --- CMakeLists.txt | 2 +- alethzero/CMakeLists.txt | 2 +- eth/main.cpp | 2 +- iethxi/MainWin.cpp | 2 +- libethereum/Executive.h | 2 +- libethereum/State.cpp | 2 +- libevm/CMakeLists.txt | 2 +- libevm/ExtVMFace.h | 2 +- libevm/VM.h | 2 +- {liblll => libevmcore}/Assembly.cpp | 0 {liblll => libevmcore}/Assembly.h | 2 +- {libevmface => libevmcore}/CMakeLists.txt | 2 +- libevmcore/Exceptions.h | 36 ++++++++++++++++++++++ {libevmface => libevmcore}/Instruction.cpp | 0 {libevmface => libevmcore}/Instruction.h | 7 +---- liblll/All.h | 1 - liblll/CMakeLists.txt | 2 +- liblll/CodeFragment.cpp | 2 +- liblll/CodeFragment.h | 4 +-- liblll/Exceptions.h | 3 -- libpyserpent/CMakeLists.txt | 2 +- libqethereum/QmlEthereum.cpp | 2 +- libserpent/CMakeLists.txt | 2 +- libsolidity/CMakeLists.txt | 3 +- libsolidity/CompilerContext.h | 4 +-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- lllc/CMakeLists.txt | 2 +- lllc/main.cpp | 2 +- neth/main.cpp | 2 +- sc/CMakeLists.txt | 2 +- test/createRandomTest.cpp | 2 +- test/vm.h | 2 +- third/CMakeLists.txt | 2 +- walleth/MainWin.cpp | 2 +- windows/LibEthereum.vcxproj | 8 ++--- windows/LibEthereum.vcxproj.filters | 16 +++++----- 36 files changed, 79 insertions(+), 53 deletions(-) rename {liblll => libevmcore}/Assembly.cpp (100%) rename {liblll => libevmcore}/Assembly.h (99%) rename {libevmface => libevmcore}/CMakeLists.txt (95%) create mode 100644 libevmcore/Exceptions.h rename {libevmface => libevmcore}/Instruction.cpp (100%) rename {libevmface => libevmcore}/Instruction.h (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4aa2352f..d8c517fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ include(EthDependenciesDeprecated) createBuildInfo() add_subdirectory(libdevcore) -add_subdirectory(libevmface) +add_subdirectory(libevmcore) add_subdirectory(liblll) add_subdirectory(libserpent) add_subdirectory(libsolidity) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 0da0acb4f..01dfb88dc 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 solidity evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/eth/main.cpp b/eth/main.cpp index 759dd40d0..408654018 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,7 @@ #include #endif #include -#include +#include #include #include #include diff --git a/iethxi/MainWin.cpp b/iethxi/MainWin.cpp index 276ff7630..2d5b57094 100644 --- a/iethxi/MainWin.cpp +++ b/iethxi/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/libethereum/Executive.h b/libethereum/Executive.h index cdfe23966..930c2859b 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include "Transaction.h" diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c125a687b..c1e1ad88e 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include "BlockChain.h" diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 0c31a9fc3..b4aa1eef2 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -17,7 +17,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} devcrypto) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 62132a462..666e7e9e8 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/libevm/VM.h b/libevm/VM.h index aa58bdbb1..d8f71dfc9 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include "FeeStructure.h" diff --git a/liblll/Assembly.cpp b/libevmcore/Assembly.cpp similarity index 100% rename from liblll/Assembly.cpp rename to libevmcore/Assembly.cpp diff --git a/liblll/Assembly.h b/libevmcore/Assembly.h similarity index 99% rename from liblll/Assembly.h rename to libevmcore/Assembly.h index e39f1899b..ef5294a54 100644 --- a/liblll/Assembly.h +++ b/libevmcore/Assembly.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "Exceptions.h" namespace dev diff --git a/libevmface/CMakeLists.txt b/libevmcore/CMakeLists.txt similarity index 95% rename from libevmface/CMakeLists.txt rename to libevmcore/CMakeLists.txt index f82d2b96b..738303271 100644 --- a/libevmface/CMakeLists.txt +++ b/libevmcore/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -set(EXECUTABLE evmface) +set(EXECUTABLE evmcore) file(GLOB HEADERS "*.h") if(ETH_STATIC) diff --git a/libevmcore/Exceptions.h b/libevmcore/Exceptions.h new file mode 100644 index 000000000..57e1ac9c6 --- /dev/null +++ b/libevmcore/Exceptions.h @@ -0,0 +1,36 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Exceptions.h + * @author Christian + * @date 2014 + */ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +struct AssemblyException: virtual Exception {}; +struct InvalidDeposit: virtual AssemblyException {}; +struct InvalidOpcode: virtual AssemblyException {}; + +} +} diff --git a/libevmface/Instruction.cpp b/libevmcore/Instruction.cpp similarity index 100% rename from libevmface/Instruction.cpp rename to libevmcore/Instruction.cpp diff --git a/libevmface/Instruction.h b/libevmcore/Instruction.h similarity index 98% rename from libevmface/Instruction.h rename to libevmcore/Instruction.h index fadb5ab14..0892c50dc 100644 --- a/libevmface/Instruction.h +++ b/libevmcore/Instruction.h @@ -22,18 +22,13 @@ #pragma once #include -#include - -namespace boost { namespace spirit { class utree; } } -namespace sp = boost::spirit; +#include namespace dev { namespace eth { -struct InvalidOpcode: virtual Exception {}; - /// Virtual machine bytecode instruction. enum class Instruction: uint8_t { diff --git a/liblll/All.h b/liblll/All.h index ec6989e66..7c4192f62 100644 --- a/liblll/All.h +++ b/liblll/All.h @@ -1,6 +1,5 @@ #pragma once -#include "Assembly.h" #include "CodeFragment.h" #include "Compiler.h" #include "CompilerState.h" diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index cb50cc36e..8b1581785 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -15,7 +15,7 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 47df8f3b9..2c200caa5 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "CompilerState.h" #include "Parser.h" using namespace std; diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h index d6ca86bbe..b24b474da 100644 --- a/liblll/CodeFragment.h +++ b/liblll/CodeFragment.h @@ -22,8 +22,8 @@ #pragma once #include -#include -#include "Assembly.h" +#include +#include #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } diff --git a/liblll/Exceptions.h b/liblll/Exceptions.h index c45215f1a..1e9671b36 100644 --- a/liblll/Exceptions.h +++ b/liblll/Exceptions.h @@ -32,16 +32,13 @@ namespace eth class CompilerException: public dev::Exception {}; class InvalidOperation: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; -class StringTooLong: public CompilerException {}; class EmptyList: public CompilerException {}; class DataNotExecutable: public CompilerException {}; class IncorrectParameterCount: public CompilerException {}; -class InvalidDeposit: public CompilerException {}; class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; -class ExpectedLiteral: public CompilerException {}; } } diff --git a/libpyserpent/CMakeLists.txt b/libpyserpent/CMakeLists.txt index 5108000f4..e6f32ec81 100644 --- a/libpyserpent/CMakeLists.txt +++ b/libpyserpent/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${PYTHON_LS}) diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp index a7ed3df4d..b1b926f42 100644 --- a/libqethereum/QmlEthereum.cpp +++ b/libqethereum/QmlEthereum.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libserpent/CMakeLists.txt b/libserpent/CMakeLists.txt index 0090b5dc3..c2fe89cc0 100644 --- a/libserpent/CMakeLists.txt +++ b/libserpent/CMakeLists.txt @@ -16,7 +16,7 @@ endif() include_directories(..) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index f425bba48..f335dd754 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,8 +16,7 @@ file(GLOB HEADERS "*.h") include_directories(..) -# @todo we only depend on Assembly, not on all of lll -target_link_libraries(${EXECUTABLE} evmface devcore lll) +target_link_libraries(${EXECUTABLE} evmcore devcore) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 46c4c72ab..088ef43bc 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -23,8 +23,8 @@ #pragma once #include -#include -#include +#include +#include #include namespace dev { diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 89d45f4e0..abb3c87cb 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -22,7 +22,7 @@ */ #include "WebThreeStubServer.h" -#include +#include #include #include #include diff --git a/lllc/CMakeLists.txt b/lllc/CMakeLists.txt index 9d5e8c5ff..a9b53c74c 100644 --- a/lllc/CMakeLists.txt +++ b/lllc/CMakeLists.txt @@ -9,7 +9,7 @@ set(EXECUTABLE lllc) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/lllc/main.cpp b/lllc/main.cpp index a4c9df78c..1a44ee950 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "BuildInfo.h" using namespace std; using namespace dev; diff --git a/neth/main.cpp b/neth/main.cpp index 06e22f963..6be555fbb 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -30,7 +30,7 @@ #include #endif #include -#include +#include #include #if ETH_JSONRPC #include diff --git a/sc/CMakeLists.txt b/sc/CMakeLists.txt index 3cacf78e6..9aa23b03b 100644 --- a/sc/CMakeLists.txt +++ b/sc/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 28e4342d7..321e515d6 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "vm.h" using namespace std; diff --git a/test/vm.h b/test/vm.h index 1ed33e5fa..a52a02e31 100644 --- a/test/vm.h +++ b/test/vm.h @@ -29,7 +29,7 @@ along with cpp-ethereum. If not, see . #include "JsonSpiritHeaders.h" #include #include -#include +#include #include #include #include diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index 6edea7456..d5371b666 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -53,7 +53,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp index 3fa5a9388..f56cad65d 100644 --- a/walleth/MainWin.cpp +++ b/walleth/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index c308f05e7..30deea983 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,7 +125,7 @@ - + true true @@ -341,7 +341,7 @@ - + true true @@ -367,7 +367,7 @@ true - + @@ -567,4 +567,4 @@ - \ No newline at end of file + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 137440619..514320472 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -37,8 +37,8 @@ libevm - - libevmface + + libevmcore liblll @@ -243,14 +243,14 @@ libevm - - libevmface + + libevmcore liblll - - liblll + + libevmcore liblll @@ -449,7 +449,7 @@ {37c37803-1515-47c1-b7e6-3879f4429ab3} - + {ed9ad1b3-700c-47f9-8548-a90b5ef179ac} @@ -471,4 +471,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - \ No newline at end of file + From 41da8fb27abb19de164ea9057e5789a18f1801bf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Nov 2014 14:57:46 +0000 Subject: [PATCH 70/77] Fix ECRECOVER to zero out the first 12 bytes of result. --- libethereum/State.cpp | 1 + stdserv.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c125a687b..c2bccad42 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -60,6 +60,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27)) ret = dev::sha3(bytesConstRef(&(pubkey[1]), 64)); + memset(ret.data(), 0, 12); memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); } diff --git a/stdserv.js b/stdserv.js index 68d33ddd9..55ae90d86 100644 --- a/stdserv.js +++ b/stdserv.js @@ -55,6 +55,14 @@ eth.transact({ 'code': nameRegCode }, function(a) { nameReg = a; }); env.note('Register NameReg...') eth.transact({ 'to': config, 'data': ['0', nameReg] }); +var nameRegJeff; + +env.note('Create NameRegJeff...') +eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); + +env.note('Register NameRegJeff...') +eth.transact({ 'to': config, 'data': ['4', nameReg] }); + var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; var dnsReg; From 4014a3d0c81d3765645fdd91fd87137b8151f7c4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Nov 2014 15:21:53 +0000 Subject: [PATCH 71/77] Fix all the asBytes stuff. --- alethzero/MainWin.cpp | 2 +- libdevcore/CommonJS.cpp | 3 +-- libweb3jsonrpc/WebThreeStubServer.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index cd6cad11a..56a9e35bc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1268,7 +1268,7 @@ void Main::on_blocks_currentItemChanged() s << "   #" << tx.nonce() << ""; s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; s << "
Gas: " << tx.gas() << ""; - s << "
V: " << hex << nouppercase << (int)tx.signature().v << ""; + s << "
V: " << hex << nouppercase << (int)tx.signature().v << " + 27"; s << "
R: " << hex << nouppercase << tx.signature().r << ""; s << "
S: " << hex << nouppercase << tx.signature().s << ""; s << "
Msg: " << tx.sha3(eth::WithoutSignature) << ""; diff --git a/libdevcore/CommonJS.cpp b/libdevcore/CommonJS.cpp index d362f66ab..96f4b1896 100644 --- a/libdevcore/CommonJS.cpp +++ b/libdevcore/CommonJS.cpp @@ -35,8 +35,7 @@ bytes jsToBytes(std::string const& _s) // Decimal return toCompactBigEndian(bigint(_s)); else - // Binary - return asBytes(_s); + return bytes(); } std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 89d45f4e0..031fc907a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -211,7 +211,7 @@ static shh::Message toMessage(Json::Value const& _json) if (!_json["to"].empty()) ret.setTo(jsToPublic(_json["to"].asString())); if (!_json["payload"].empty()) - ret.setPayload(asBytes(_json["payload"].asString())); + ret.setPayload(jsToBytes(_json["payload"].asString())); return ret; } @@ -228,10 +228,10 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, if (!_json["topic"].empty()) { if (_json["topic"].isString()) - bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32))); + bt.shift(jsToBytes(_json["topic"])); else if (_json["topic"].isArray()) for (auto i: _json["topic"]) - bt.shift(asBytes(jsPadded(i.asString(), 32))); + bt.shift(jsToBytes(i.asString())); } return _m.seal(_from, bt, ttl, workToProve); } @@ -247,12 +247,12 @@ static pair toWatch(Json::Value const& _json) if (!_json["topic"].empty()) { if (_json["topic"].isString()) - bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32))); + bt.shift(jsToBytes(_json["topic"].asString())); else if (_json["topic"].isArray()) for (auto i: _json["topic"]) { if (i.isString()) - bt.shift(asBytes(jsPadded(i.asString(), 32))); + bt.shift(jsToBytes(i.asString())); else bt.shift(); } @@ -372,10 +372,10 @@ static TransactionSkeleton toTransaction(Json::Value const& _json) ret.data = jsToBytes(_json["code"].asString()); else if (_json["data"].isArray()) for (auto i: _json["data"]) - dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32))); + dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); else if (_json["code"].isArray()) for (auto i: _json["code"]) - dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32))); + dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); else if (_json["dataclose"].isArray()) for (auto i: _json["dataclose"]) dev::operator +=(ret.data, jsToBytes(i.asString())); From d395b82f1b5705807048162430f4d3d28c504169 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Nov 2014 15:47:19 +0000 Subject: [PATCH 72/77] Nicer uncle info. Fix for fromAscii/toAscii and asBytes usage. --- alethzero/MainWin.cpp | 7 +++++++ libjsqrc/main.js | 4 +++- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 56a9e35bc..6d91767b8 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1243,6 +1243,13 @@ void Main::on_blocks_currentItemChanged() s << "
Log Bloom: " << info.logBloom << ""; s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; + for (auto u: block[2]) + { + BlockInfo uncle = BlockInfo::fromHeader(u.data()); + s << "
 Hash: " << uncle.hash << ""; + s << "
 Parent: " << uncle.parentHash << ""; + s << "
 Number: " << uncle.number << ""; + } if (info.parentHash) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << ""; else diff --git a/libjsqrc/main.js b/libjsqrc/main.js index 3e0a62c40..821de6382 100644 --- a/libjsqrc/main.js +++ b/libjsqrc/main.js @@ -217,6 +217,8 @@ // Find termination var str = ""; var i = 0, l = hex.length; + if (hex.substring(0, 2) == '0x') + i = 2; for(; i < l; i+=2) { var code = hex.charCodeAt(i) if(code == 0) { @@ -238,7 +240,7 @@ var hex = this.toHex(str); while(hex.length < pad*2) hex += "00"; - return hex + return "0x" + hex }, eth: { diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 031fc907a..5b7b56a19 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -228,7 +228,7 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, if (!_json["topic"].empty()) { if (_json["topic"].isString()) - bt.shift(jsToBytes(_json["topic"])); + bt.shift(jsToBytes(_json["topic"].asString())); else if (_json["topic"].isArray()) for (auto i: _json["topic"]) bt.shift(jsToBytes(i.asString())); From 5b134de6976dc75cb67211bf252f0ddd257f633f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Nov 2014 16:41:11 +0000 Subject: [PATCH 73/77] More fixes for WebThree JS stuff. --- alethzero/MainWin.cpp | 34 +++++++++++++----------- alethzero/MainWin.h | 4 +-- alethzero/OurWebThreeStubServer.cpp | 36 +++++++++++++++++++++++++ alethzero/OurWebThreeStubServer.h | 38 +++++++++++++++++++++++++++ libweb3jsonrpc/WebThreeStubServer.cpp | 2 ++ 5 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 alethzero/OurWebThreeStubServer.cpp create mode 100644 alethzero/OurWebThreeStubServer.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6d91767b8..343097bbf 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -50,6 +50,7 @@ #include "MiningView.h" #include "BuildInfo.h" #include "MainWin.h" +#include "OurWebThreeStubServer.h" #include "ui_Main.h" using namespace std; using namespace dev; @@ -154,7 +155,8 @@ Main::Main(QWidget *parent) : // 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.reset(new OurWebThreeStubServer(m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -205,12 +207,28 @@ Main::~Main() writeSettings(); } +void Main::on_newIdentity_triggered() +{ + KeyPair kp = KeyPair::create(); + m_myIdentities.append(kp); + m_server->setIdentities(keysAsVector(owned())); + refreshWhisper(); +} + +void Main::refreshWhisper() +{ + ui->shhFrom->clear(); + for (auto i: m_server->ids()) + ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); +} + void Main::addNewId(QString _ids) { Secret _id = jsToSecret(_ids.toStdString()); KeyPair kp(_id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); + refreshWhisper(); } dev::p2p::NetworkPreferences Main::netPrefs() const @@ -2176,20 +2194,6 @@ void Main::on_post_clicked() whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } -void Main::on_newIdentity_triggered() -{ - KeyPair kp = KeyPair::create(); - m_myIdentities.append(kp); - m_server->setIdentities(keysAsVector(owned())); -} - -void Main::refreshWhisper() -{ - ui->shhFrom->clear(); - for (auto i: m_server ->ids()) - ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); -} - void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index e62afb497..57f9c5ebd 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -47,7 +47,7 @@ class MessageFilter; }} class QQuickView; -class WebThreeStubServer; +class OurWebThreeStubServer; struct WorldState { @@ -256,6 +256,6 @@ private: bool m_logChanged = true; QWebThreeConnector* m_qwebConnector; - std::unique_ptr m_server; + std::unique_ptr m_server; QWebThree* m_qweb = nullptr; }; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp new file mode 100644 index 000000000..ca1b77649 --- /dev/null +++ b/alethzero/OurWebThreeStubServer.cpp @@ -0,0 +1,36 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file OurWebThreeStubServer.h + * @author Gav Wood + * @date 2014 + */ + +#include "OurWebThreeStubServer.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): + WebThreeStubServer(_conn, _web3, _accounts) +{} + +std::string OurWebThreeStubServer::newIdentity() +{ + dev::KeyPair kp = dev::KeyPair::create(); + emit onNewId(QString::fromStdString(toJS(kp.sec()))); + return toJS(kp.pub()); +} diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h new file mode 100644 index 000000000..be06da62d --- /dev/null +++ b/alethzero/OurWebThreeStubServer.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file OurWebThreeStubServer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include +#include +#include +#include + +class OurWebThreeStubServer: public QObject, public WebThreeStubServer +{ + Q_OBJECT + +public: + OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); + + virtual std::string newIdentity() override; + +signals: + void onNewId(QString _s); +}; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 5b7b56a19..12a18d938 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -509,6 +509,7 @@ std::string WebThreeStubServer::newGroup(std::string const& _id, std::string con std::string WebThreeStubServer::newIdentity() { + cnote << this << m_ids; KeyPair kp = KeyPair::create(); m_ids[kp.pub()] = kp.secret(); return toJS(kp.pub()); @@ -531,6 +532,7 @@ int WebThreeStubServer::peerCount() bool WebThreeStubServer::post(Json::Value const& _json) { + cnote << this << m_ids; shh::Message m = toMessage(_json); Secret from; From 6bc2777169426d2cb7ab8d0ba86764b953ac9f62 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Nov 2014 17:03:07 +0000 Subject: [PATCH 74/77] Don't use binary in the JS API. --- libweb3jsonrpc/WebThreeStubServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 12a18d938..83e56d97a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -269,7 +269,7 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message res["ttl"] = (int)_e.ttl(); res["workProved"] = (int)_e.workProved(); res["topic"] = toJS(_e.topic()); - res["payload"] = asString(_m.payload()); + res["payload"] = toJS(_m.payload()); res["from"] = toJS(_m.from()); res["to"] = toJS(_m.to()); return res; @@ -452,7 +452,7 @@ std::string WebThreeStubServer::get(std::string const& _name, std::string const& Json::Value WebThreeStubServer::getMessages(int const& _id) { if (!client()) - return Json::Value(); + return Json::Value(); return toJson(client()->messages(_id)); } @@ -618,7 +618,7 @@ Json::Value WebThreeStubServer::shhChanged(int const& _id) } else m = e.open(); - ret.append(toJson(h,e,m)); + ret.append(toJson(h, e, m)); } return ret; From b85638183d2b0c6678411b64aa89a18f8a019751 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Nov 2014 21:55:01 +0100 Subject: [PATCH 75/77] Stylistic changes. --- libsolidity/ExpressionCompiler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 324cd10d0..da054920d 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -372,9 +372,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con if (_typeOnStack == _targetType && !_cleanupNeeded) return; if (_typeOnStack.getCategory() == Type::Category::INTEGER) - { appendHighBitsCleanup(dynamic_cast(_typeOnStack)); - } else if (_typeOnStack != _targetType) { // All other types should not be convertible to non-equal types. From e1c01722d49b8a8bed28a7f345811d1fec7f27f9 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 6 Nov 2014 22:04:10 +0100 Subject: [PATCH 76/77] Re-added some changes lost in merges. --- libsolidity/AST.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index e654dd575..e146318c8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -347,7 +347,7 @@ void ExpressionStatement::checkTypeRequirements() void Expression::expectType(Type const& _expectedType) { checkTypeRequirements(); - const Type& type = *getType(); + Type const& type = *getType(); if (!type.isImplicitlyConvertibleTo(_expectedType)) BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() + " not implicitly convertible to expected type " diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index da054920d..48bcd578d 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -376,8 +376,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con else if (_typeOnStack != _targetType) { // All other types should not be convertible to non-equal types. - assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); } } From f60c661c06a91272bdd16b9e67140921f163ac98 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Nov 2014 22:11:21 +0100 Subject: [PATCH 77/77] Removed superfluous braces. --- libsolidity/ExpressionCompiler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 48bcd578d..6efb8b20c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -374,10 +374,8 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con if (_typeOnStack.getCategory() == Type::Category::INTEGER) appendHighBitsCleanup(dynamic_cast(_typeOnStack)); else if (_typeOnStack != _targetType) - { // All other types should not be convertible to non-equal types. BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); - } } void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)