Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc

Conflicts:
	test/vm.cpp
This commit is contained in:
artur-zawlocki 2014-10-29 11:02:37 +00:00
commit ec9330609f
20 changed files with 1223 additions and 201 deletions

View File

@ -17,6 +17,7 @@ target_link_libraries(testeth ethereum)
target_link_libraries(testeth ethcore) target_link_libraries(testeth ethcore)
target_link_libraries(testeth secp256k1) target_link_libraries(testeth secp256k1)
target_link_libraries(testeth gmp) target_link_libraries(testeth gmp)
target_link_libraries(testeth solidity)
target_link_libraries(testeth ${CRYPTOPP_LS}) target_link_libraries(testeth ${CRYPTOPP_LS})
target_link_libraries(testeth evm) target_link_libraries(testeth evm)
target_link_libraries(testeth evmjit) target_link_libraries(testeth evmjit)

View File

@ -437,12 +437,12 @@ MemTrie::~MemTrie()
h256 MemTrie::hash256() const h256 MemTrie::hash256() const
{ {
return m_root ? m_root->hash256() : h256(); return m_root ? m_root->hash256() : sha3(dev::rlp(bytesConstRef()));
} }
bytes MemTrie::rlp() const bytes MemTrie::rlp() const
{ {
return m_root ? m_root->rlp() : bytes(); return m_root ? m_root->rlp() : dev::rlp(bytesConstRef());
} }
void MemTrie::debugPrint() void MemTrie::debugPrint()

View File

@ -21,23 +21,7 @@
#pragma once #pragma once
//#include <ostream> #include <libdevcrypto/CryptoPP.h>
#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 <eccrypto.h>
#include <ecp.h>
#include <files.h>
#include <osrng.h>
#include <oids.h>
#pragma warning(pop)
#pragma GCC diagnostic pop
using namespace std; using namespace std;
using namespace CryptoPP; using namespace CryptoPP;

View File

@ -162,7 +162,7 @@ h256 hash256(StringMap const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return h256(); return sha3(rlp(""));
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
@ -175,7 +175,7 @@ bytes rlp256(StringMap const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return bytes(); return rlp("");
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
@ -188,7 +188,7 @@ h256 hash256(u256Map const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return h256(); return sha3(rlp(""));
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second));

View File

@ -42,11 +42,7 @@ void doMyTests(json_spirit::mValue& v);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc != 2) g_logVerbosity = 0;
{
cout << "usage: createRandomTest <filename>\n";
return 0;
}
// create random code // create random code
@ -64,14 +60,48 @@ int main(int argc, char *argv[])
string randomCode; string randomCode;
for (int i = 0; i < lengthOfCode; ++i) for (int i = 0; i < lengthOfCode; ++i)
randomCode += toHex(toCompactBigEndian(randGen())); {
uint8_t opcode = randGen();
// read template test file // disregard all invalid commands, except of one (0x10)
if (dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || opcode == 0x10)
randomCode += toHex(toCompactBigEndian(opcode));
else
i--;
}
const string s =\
"{\n\
\"randomVMtest\": {\n\
\"env\" : {\n\
\"previousHash\" : \"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6\",\n\
\"currentNumber\" : \"0\",\n\
\"currentGasLimit\" : \"1000000\",\n\
\"currentDifficulty\" : \"256\",\n\
\"currentTimestamp\" : 1,\n\
\"currentCoinbase\" : \"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n\
},\n\
\"pre\" : {\n\
\"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6\" : {\n\
\"balance\" : \"1000000000000000000\",\n\
\"nonce\" : 0,\n\
\"code\" : \"random\",\n\
\"storage\": {}\n\
}\n\
},\n\
\"exec\" : {\n\
\"address\" : \"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6\",\n\
\"origin\" : \"cd1722f3947def4cf144679da39c4c32bdc35681\",\n\
\"caller\" : \"cd1722f3947def4cf144679da39c4c32bdc35681\",\n\
\"value\" : \"1000000000000000000\",\n\
\"data\" : \"\",\n\
\"gasPrice\" : \"100000000000000\",\n\
\"gas\" : \"10000\"\n\
}\n\
}\n\
}";
mValue v; mValue v;
boost::filesystem::path p(__FILE__);
boost::filesystem::path dir = p.parent_path();
string s = asString(contents(dir.string() + "/randomTestFiller.json"));
read_string(s, v); read_string(s, v);
// insert new random code // insert new random code
@ -80,9 +110,8 @@ int main(int argc, char *argv[])
// execute code in vm // execute code in vm
doMyTests(v); doMyTests(v);
// write new test // stream to output for further handling by the bash script
string filename = argv[1]; cout << json_spirit::write_string(v, true);
writeFile(filename, asBytes(json_spirit::write_string(v, true)));
return 0; return 0;
} }

View File

@ -27,37 +27,163 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libethereum/Transaction.h> #include <libethereum/Transaction.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libdevcrypto/EC.h>
#include "TestHelperCrypto.h" #include "TestHelperCrypto.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto;
namespace dev
{
namespace crypto
{
inline CryptoPP::AutoSeededRandomPool& PRNG() {
static CryptoPP::AutoSeededRandomPool prng;
return prng;
}
}
}
using namespace CryptoPP; using namespace CryptoPP;
BOOST_AUTO_TEST_SUITE(crypto) BOOST_AUTO_TEST_SUITE(devcrypto)
BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
{
string message("Now is the time for all good persons to come to the aide of humanity.");
bytes m = asBytes(message);
bytesConstRef bcr(&m);
KeyPair k = KeyPair::create();
bytes cipher;
encrypt(k.pub(), bcr, cipher);
assert(cipher != asBytes(message) && cipher.size() > 0);
bytes plain;
decrypt(k.sec(), bytesConstRef(&cipher), plain);
assert(asString(plain) == message);
assert(plain == asBytes(message));
}
BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1)
{
ECIES<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s);
Public p;
pp::PublicFromDL_PublicKey_EC(e.GetKey(), p);
assert(dev::toAddress(s) == right160(dev::sha3(p.ref())));
Secret previous = s;
for (auto i = 0; i < 30; i++)
{
ECIES<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s);
assert(s != previous);
Public p;
pp::PublicFromDL_PublicKey_EC(e.GetKey(), p);
assert(dev::toAddress(s) == right160(dev::sha3(p.ref())));
}
}
BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_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<CryptoPP::ECP> privatek;
privatek.AccessGroupParameters().Initialize(pp::secp256k1());
privatek.SetPrivateExponent(e);
assert(e == privatek.GetPrivateExponent());
// Test that exported secret is same as decryptor(privatek) secret
ECIES<ECP>::Decryptor d;
d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1());
d.AccessKey().SetPrivateExponent(e);
assert(d.AccessKey().GetPrivateExponent() == e);
// Test that decryptor->encryptor->public == private->makepublic->public
CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pubk;
pubk.AccessGroupParameters().Initialize(pp::secp256k1());
privatek.MakePublicKey(pubk);
ECIES<ECP>::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<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s);
Public p;
pp::PublicFromDL_PublicKey_EC(e.GetKey(), p);
Address addr = right160(dev::sha3(p.ref()));
assert(toAddress(s) == addr);
KeyPair l(s);
assert(l.address() == addr);
DL_PublicKey_EC<ECP> 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)
{
KeyPair k = KeyPair::create();
string message("Now is the time for all good persons to come to the aide of humanity.");
string original = message;
bytes b = asBytes(message);
encrypt(k.pub(), b);
assert(b != asBytes(original));
decrypt(k.sec(), b);
assert(b == asBytes(original));
}
BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac)
{
// New connections require new ECDH keypairs
// Every new connection requires a new EC keypair
// Every new trust requires a new EC keypair
// All connections should share seed for PRF (or PRNG) for nonces
}
BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
{ {
cnote << "Testing cryptopp_ecies_message..."; cnote << "Testing cryptopp_ecies_message...";
string const message("Now is the time for all good men to come to the aide of humanity."); string const message("Now is the time for all good persons to come to the aide of humanity.");
AutoSeededRandomPool prng; ECIES<ECP>::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Decryptor localDecryptor(prng, ASN1::secp256r1());
SavePrivateKey(localDecryptor.GetPrivateKey()); SavePrivateKey(localDecryptor.GetPrivateKey());
ECIES<ECP>::Encryptor localEncryptor(localDecryptor); ECIES<ECP>::Encryptor localEncryptor(localDecryptor);
@ -65,31 +191,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
ECIES<ECP>::Decryptor futureDecryptor; ECIES<ECP>::Decryptor futureDecryptor;
LoadPrivateKey(futureDecryptor.AccessPrivateKey()); LoadPrivateKey(futureDecryptor.AccessPrivateKey());
futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3); futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3);
ECIES<ECP>::Encryptor futureEncryptor; ECIES<ECP>::Encryptor futureEncryptor;
LoadPublicKey(futureEncryptor.AccessPublicKey()); LoadPublicKey(futureEncryptor.AccessPublicKey());
futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3); futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3);
// encrypt/decrypt with local // encrypt/decrypt with local
string cipherLocal; string cipherLocal;
StringSource ss1 (message, true, new PK_EncryptorFilter(prng, localEncryptor, new StringSink(cipherLocal) ) ); StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) );
string plainLocal; string plainLocal;
StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocal) ) ); StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) );
// encrypt/decrypt with future // encrypt/decrypt with future
string cipherFuture; string cipherFuture;
StringSource ss3 (message, true, new PK_EncryptorFilter(prng, futureEncryptor, new StringSink(cipherFuture) ) ); StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) );
string plainFuture; string plainFuture;
StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFuture) ) ); StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) );
// decrypt local w/future // decrypt local w/future
string plainFutureFromLocal; string plainFutureFromLocal;
StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) );
// decrypt future w/local // decrypt future w/local
string plainLocalFromFuture; string plainLocalFromFuture;
StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocalFromFuture) ) ); StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) );
assert(plainLocal == message); assert(plainLocal == message);
@ -98,96 +224,110 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
assert(plainLocalFromFuture == plainLocal); assert(plainLocalFromFuture == plainLocal);
} }
BOOST_AUTO_TEST_CASE(cryptopp_ecdh_prime) BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
{ {
cnote << "Testing cryptopp_ecdh_prime..."; const int aesKeyLen = 16;
assert(sizeof(char) == sizeof(byte));
using namespace CryptoPP; // generate test key
OID curve = ASN1::secp256r1(); AutoSeededRandomPool rng;
SecByteBlock key(0x00, aesKeyLen);
rng.GenerateBlock(key, key.size());
ECDH<ECP>::Domain dhLocal(curve); // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
SecByteBlock privLocal(dhLocal.PrivateKeyLength()); byte ctr[AES::BLOCKSIZE];
SecByteBlock pubLocal(dhLocal.PublicKeyLength()); rng.GenerateBlock(ctr, sizeof(ctr));
dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal);
ECDH<ECP>::Domain dhRemote(curve); string text = "Now is the time for all good persons to come to the aide of humanity.";
SecByteBlock privRemote(dhRemote.PrivateKeyLength()); // c++11 ftw
SecByteBlock pubRemote(dhRemote.PublicKeyLength()); unsigned char const* in = (unsigned char*)&text[0];
dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote); unsigned char* out = (unsigned char*)&text[0];
string original = text;
assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); string cipherCopy;
try
{
CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr);
e.ProcessData(out, in, text.size());
assert(text != original);
cipherCopy = text;
}
catch(CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
// local: send public to remote; remote: send public to local try
{
CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, key.size(), ctr);
d.ProcessData(out, in, text.size());
assert(text == original);
}
catch(CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
// Local
SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
// Remote // reencrypt ciphertext...
SecByteBlock sharedRemote(dhRemote.AgreedValueLength()); try
assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal)); {
assert(cipherCopy != text);
in = (unsigned char*)&cipherCopy[0];
out = (unsigned char*)&cipherCopy[0];
// Test CTR_Mode<AES>::Encryption e;
Integer ssLocal, ssRemote; e.SetKeyWithIV(key, key.size(), ctr);
ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes()); e.ProcessData(out, in, text.size());
ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
assert(ssLocal != 0);
assert(ssLocal == ssRemote);
}
BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth)
{
// ECDH gives 256-bit shared while aes uses 128-bits
// Use first 128-bits of shared secret as symmetric key
// IV is 0
// New connections require new ECDH keypairs
// yep, ctr mode.
assert(cipherCopy == original);
}
catch(CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
} }
BOOST_AUTO_TEST_CASE(cryptopp_eth_fbba) BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc)
{ {
// Initial Authentication: const int aesKeyLen = 16;
// assert(sizeof(char) == sizeof(byte));
// New/Known Peer:
// pubkeyL = knownR? ? myKnown : myECDH AutoSeededRandomPool rng;
// pubkeyR = knownR? ? theirKnown : theirECDH SecByteBlock key(0x00, aesKeyLen);
// rng.GenerateBlock(key, key.size());
// Initial message = hmac(k=sha3(shared-secret[128..255]), address(pubkeyL)) || ECIES encrypt(pubkeyR, pubkeyL)
// // Generate random IV
// Key Exchange (this could occur after handshake messages): byte iv[AES::BLOCKSIZE];
// If peers do not know each other they will need to exchange public keys. rng.GenerateBlock(iv, AES::BLOCKSIZE);
//
// Drop ECDH (this could occur after handshake messages): string string128("AAAAAAAAAAAAAAAA");
// After authentication and/or key exchange, both sides generate shared key string plainOriginal = string128;
// from their 'known' keys and use this to encrypt all future messages.
// CryptoPP::CBC_Mode<Rijndael>::Encryption cbcEncryption(key, key.size(), iv);
// v2: If one side doesn't trust the other then a single-use key maybe sent. cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
// This will need to be tracked for future connections; when non-trusting peer assert(string128 != plainOriginal);
// wants to trust the other, it can request that it's old, 'new', public key be
// accepted. And, if the peer *really* doesn't trust the other side, it can request CBC_Mode<Rijndael>::Decryption cbcDecryption(key, key.size(), iv);
// that a new, 'new', public key be accepted. cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
// assert(plainOriginal == string128);
// Handshake (all or nothing, padded):
// All Peers (except blacklisted):
// // plaintext whose size isn't divisible by block size must use stream filter for padding
// string string192("AAAAAAAAAAAAAAAABBBBBBBB");
// New Peer: plainOriginal = string192;
//
// string cipher;
// Known Untrusted Peer: StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher));
// StringSource source(string192, true, aesStream);
// assert(cipher.size() == 32);
// Known Trusted Peer:
// cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size());
// assert(string192 == plainOriginal);
// Blacklisted Peeer:
// Already dropped by now.
//
//
// MAC:
// ...
} }
BOOST_AUTO_TEST_CASE(eth_keypairs) BOOST_AUTO_TEST_CASE(eth_keypairs)
@ -201,6 +341,7 @@ BOOST_AUTO_TEST_CASE(eth_keypairs)
{ {
eth::Transaction t; eth::Transaction t;
t.nonce = 0; t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
auto rlp = t.rlp(false); auto rlp = t.rlp(false);
@ -229,6 +370,7 @@ int cryptoTest()
{ {
eth::Transaction t; eth::Transaction t;
t.nonce = 0; t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
auto rlp = t.rlp(false); auto rlp = t.rlp(false);
@ -257,6 +399,7 @@ int cryptoTest()
Transaction t; Transaction t;
t.nonce = 0; t.nonce = 0;
t.value = 1; // 1 wei. t.value = 1; // 1 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = toAddress(sha3("123")); t.receiveAddress = toAddress(sha3("123"));
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);

View File

@ -35,9 +35,20 @@ namespace js = json_spirit;
BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_AUTO_TEST_CASE(genesis_tests)
{ {
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Genesis block..."; cnote << "Testing Genesis block...";
js::mValue v; js::mValue v;
string s = asString(contents("../../../tests/genesishashestest.json")); string s = asString(contents(testPath + "/genesishashestest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);

View File

@ -33,9 +33,20 @@ namespace js = json_spirit;
BOOST_AUTO_TEST_CASE(hexPrefix_test) BOOST_AUTO_TEST_CASE(hexPrefix_test)
{ {
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Hex-Prefix-Encode..."; cnote << "Testing Hex-Prefix-Encode...";
js::mValue v; js::mValue v;
string s = asString(contents("../../../tests/hexencodetest.json")); string s = asString(contents(testPath + "/hexencodetest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())

View File

@ -44,7 +44,7 @@ using namespace dev::eth;
BOOST_AUTO_TEST_CASE(basic_tests) BOOST_AUTO_TEST_CASE(basic_tests)
{ {
/* RLPStream s; /* RLPStream s;
BlockInfo::genesis().fillStream(s, false); BlockInfo::genesis().streamRLP(s, false);
std::cout << RLP(s.out()) << std::endl; std::cout << RLP(s.out()) << std::endl;
std::cout << toHex(s.out()) << std::endl; std::cout << toHex(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;*/ std::cout << sha3(s.out()) << std::endl;*/

13
rlp.cpp
View File

@ -61,7 +61,18 @@ namespace dev
static void getRLPTestCases(js::mValue& v) static void getRLPTestCases(js::mValue& v)
{ {
string s = asString(contents("../../../tests/rlptest.json")); const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
string s = asString(contents(testPath + "/rlptest.json"));
BOOST_REQUIRE_MESSAGE( s.length() > 0, BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?"); "Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);

View File

@ -0,0 +1,178 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Unit tests for the name and type resolution of the solidity parser.
*/
#include <string>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>
namespace dev
{
namespace solidity
{
namespace test
{
namespace
{
void parseTextAndResolveNames(const std::string& _source)
{
Parser parser;
ASTPointer<ContractDefinition> contract = parser.parse(
std::make_shared<Scanner>(CharStream(_source)));
NameAndTypeResolver resolver;
resolver.resolveNamesAndTypes(*contract);
}
}
BOOST_AUTO_TEST_SUITE(SolidityNameAndTypeResolution)
BOOST_AUTO_TEST_CASE(smoke_test)
{
char const* text = "contract test {\n"
" uint256 stateVariable1;\n"
" function fun(uint256 arg1) { var x; uint256 y; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
{
char const* text = "contract test {\n"
" uint256 variable;\n"
" uint128 variable;\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(double_function_declaration)
{
char const* text = "contract test {\n"
" function fun() { var x; }\n"
" function fun() { var x; }\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(double_variable_declaration)
{
char const* text = "contract test {\n"
" function f() { uint256 x; if (true) { uint256 x; } }\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(name_shadowing)
{
char const* text = "contract test {\n"
" uint256 variable;\n"
" function f() { uint32 variable ; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(name_references)
{
char const* text = "contract test {\n"
" uint256 variable;\n"
" function f(uint256 arg) returns (uint out) { f(variable); test; out; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(undeclared_name)
{
char const* text = "contract test {\n"
" uint256 variable;\n"
" function f(uint256 arg) { f(notfound); }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
{
char const* text = "contract test {\n"
" function g() { f(); }"
" function f() { }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
{
char const* text = "contract test {\n"
" function f(uint256 arg1, uint32 arg2) returns (bool ret) { var x = arg1 + arg2 == 8; ret = x; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_checking_return)
{
char const* text = "contract test {\n"
" function f() returns (bool r) { return 1 >= 2; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number)
{
char const* text = "contract test {\n"
" function f() returns (bool r1, bool r2) { return 1 >= 2; }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_type)
{
char const* text = "contract test {\n"
" function f() returns (uint256 r) { return 1 >= 2; }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_checking_function_call)
{
char const* text = "contract test {\n"
" function f() returns (bool r) { return g(12, true) == 3; }\n"
" function g(uint256 a, bool b) returns (uint256 r) { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
{
char const* text = "contract test {\n"
" function f() returns (int256 r) { var x = int256(uint32(2)); return x; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_SUITE_END()
}
}
} // end namespaces

221
solidityParser.cpp Normal file
View File

@ -0,0 +1,221 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Unit tests for the solidity parser.
*/
#include <string>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>
namespace dev
{
namespace solidity
{
namespace test
{
namespace
{
ASTPointer<ASTNode> parseText(const std::string& _source)
{
Parser parser;
return parser.parse(std::make_shared<Scanner>(CharStream(_source)));
}
}
BOOST_AUTO_TEST_SUITE(SolidityParser)
BOOST_AUTO_TEST_CASE(smoke_test)
{
char const* text = "contract test {\n"
" uint256 stateVariable1;\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
{
char const* text = "contract test {\n"
" uint256 ;\n"
"}\n";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(empty_function)
{
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function functionName(hash160 arg1, address addr) const\n"
" returns (int id)\n"
" { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(no_function_params)
{
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function functionName() {}\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(single_function_param)
{
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(struct_definition)
{
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" struct MyStructName {\n"
" address addr;\n"
" uint256 count;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(mapping)
{
char const* text = "contract test {\n"
" mapping(address => string) names;\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(mapping_in_struct)
{
char const* text = "contract test {\n"
" struct test_struct {\n"
" address addr;\n"
" uint256 count;\n"
" mapping(hash => test_struct) self_reference;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
{
char const* text = "contract test {\n"
" struct test_struct {\n"
" address addr;\n"
" mapping (uint64 => mapping (hash => uint)) complex_mapping;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(variable_definition)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" var b;\n"
" uint256 c;\n"
" mapping(address=>hash) d;\n"
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" var b = 2;\n"
" uint256 c = 0x87;\n"
" mapping(address=>hash) d;\n"
" string name = \"Solidity\";"
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(operator_expression)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(complex_expression)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
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"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(if_statement)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" if (a >= 8) return 2; else { var b = 7; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(else_if_statement)
{
char const* text = "contract test {\n"
" function fun(uint256 a) returns (address b) {\n"
" if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_SUITE_END()
}
}
} // end namespaces

143
solidityScanner.cpp Normal file
View File

@ -0,0 +1,143 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Unit tests for the solidity scanner.
*/
#include <libsolidity/Scanner.h>
#include <boost/test/unit_test.hpp>
namespace dev
{
namespace solidity
{
namespace test
{
BOOST_AUTO_TEST_SUITE(SolidityScanner)
BOOST_AUTO_TEST_CASE(test_empty)
{
Scanner scanner(CharStream(""));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(smoke_test)
{
Scanner scanner(CharStream("function break;765 \t \"string1\",'string2'\nidentifier1"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::FUNCTION);
BOOST_CHECK_EQUAL(scanner.next(), Token::BREAK);
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "765");
BOOST_CHECK_EQUAL(scanner.next(), Token::STRING_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "string1");
BOOST_CHECK_EQUAL(scanner.next(), Token::COMMA);
BOOST_CHECK_EQUAL(scanner.next(), Token::STRING_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "string2");
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "identifier1");
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(string_escapes)
{
Scanner scanner(CharStream(" { \"a\\x61\""));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::LBRACE);
BOOST_CHECK_EQUAL(scanner.next(), Token::STRING_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "aa");
}
BOOST_AUTO_TEST_CASE(string_escapes_with_zero)
{
Scanner scanner(CharStream(" { \"a\\x61\\x00abc\""));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::LBRACE);
BOOST_CHECK_EQUAL(scanner.next(), Token::STRING_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), std::string("aa\0abc", 6));
}
BOOST_AUTO_TEST_CASE(string_escape_illegal)
{
Scanner scanner(CharStream(" bla \"\\x6rf\" (illegalescape)"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ILLEGAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "");
// TODO recovery from illegal tokens should be improved
BOOST_CHECK_EQUAL(scanner.next(), Token::ILLEGAL);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ILLEGAL);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(hex_numbers)
{
Scanner scanner(CharStream("var x = 0x765432536763762734623472346;"));
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(), "0x765432536763762734623472346");
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"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 0);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 19);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 20);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 23);
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().end, 32);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 50);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(ambiguities)
{
// test scanning of some operators which need look-ahead
Scanner scanner(CharStream("<=""<""+ +=a++ =>""<<"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::LTE);
BOOST_CHECK_EQUAL(scanner.next(), Token::LT);
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN_ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::INC);
BOOST_CHECK_EQUAL(scanner.next(), Token::ARROW);
BOOST_CHECK_EQUAL(scanner.next(), Token::SHL);
}
BOOST_AUTO_TEST_SUITE_END()
}
}
} // end namespaces

View File

@ -68,6 +68,7 @@ int stateTest()
Transaction t; Transaction t;
t.nonce = s.transactionsFrom(myMiner.address()); t.nonce = s.transactionsFrom(myMiner.address());
t.value = 1000; // 1e3 wei. t.value = 1000; // 1e3 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = me.address(); t.receiveAddress = me.address();
t.sign(myMiner.secret()); t.sign(myMiner.secret());
assert(t.sender() == myMiner.address()); assert(t.sender() == myMiner.address());

View File

@ -49,9 +49,20 @@ static unsigned fac(unsigned _i)
BOOST_AUTO_TEST_CASE(trie_tests) BOOST_AUTO_TEST_CASE(trie_tests)
{ {
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Trie..."; cnote << "Testing Trie...";
js::mValue v; js::mValue v;
string s = asString(contents("../../../tests/trietest.json")); string s = asString(contents(testPath + "/trietest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())

111
vm.cpp
View File

@ -20,11 +20,9 @@
* vm test functions. * vm test functions.
*/ */
#include "vm.h"
#include <libdevcore/CommonIO.h>
#include <libevmjit/VM.h>
#include <boost/filesystem/path.hpp>
#include <chrono> #include <chrono>
#include <boost/filesystem/path.hpp>
#include "vm.h"
//#define FILL_TESTS //#define FILL_TESTS
using namespace std; using namespace std;
@ -46,7 +44,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -57,14 +55,13 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
get<3>(addresses[ret]) = m_s.code(ret); get<3>(addresses[ret]) = m_s.code(ret);
} }
t.receiveAddress = ret; t.type = eth::Transaction::ContractCreation;
callcreates.push_back(t); callcreates.push_back(t);
return ret; return ret;
} }
bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address()) bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride)
{ {
u256 contractgas = 0xffff; u256 contractgas = 0xffff;
Transaction t; Transaction t;
@ -72,6 +69,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
t.gasPrice = gasPrice; t.gasPrice = gasPrice;
t.gas = *_gas; t.gas = *_gas;
t.data = _data.toVector(); t.data = _data.toVector();
t.type = eth::Transaction::MessageCall;
t.receiveAddress = _receiveAddress; t.receiveAddress = _receiveAddress;
callcreates.push_back(t); callcreates.push_back(t);
@ -92,7 +90,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!m_s.addresses().count(myAddress)) if (!m_s.addresses().count(myAddress))
{ {
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
if (na != myAddress) if (na != myAddress)
@ -117,7 +115,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{ {
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -132,7 +130,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1); auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), simpleTrace<ExtVM>(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -147,12 +145,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!ret) if (!ret)
return false; return false;
// TODO: @CJentzsch refund SSTORE stuff.
// TODO: @CJentzsch test logs.
// do suicides // do suicides
for (auto const& f: suicides) for (auto const& f: sub.suicides)
addresses.erase(f); addresses.erase(f);
// get storage // get storage
if ((get<0>(addresses[myAddress]) >= _value) && (suicides.find(_receiveAddress) == suicides.end())) if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end()))
{ {
for (auto const& j: m_s.storage(_receiveAddress)) for (auto const& j: m_s.storage(_receiveAddress))
{ {
@ -357,10 +358,10 @@ void FakeExtVM::importExec(mObject& _o)
thisTxCode.clear(); thisTxCode.clear();
code = &thisTxCode; code = &thisTxCode;
if (_o["code"].type() == str_type) if (_o["code"].type() == str_type)
if (_o["code"].get_str().find_first_of("0x") != 0) if (_o["code"].get_str().find_first_of("0x") == 0)
thisTxCode = compileLLL(_o["code"].get_str());
else
thisTxCode = fromHex(_o["code"].get_str().substr(2)); thisTxCode = fromHex(_o["code"].get_str().substr(2));
else
thisTxCode = compileLLL(_o["code"].get_str());
else if (_o["code"].type() == array_type) else if (_o["code"].type() == array_type)
for (auto const& j: _o["code"].get_array()) for (auto const& j: _o["code"].get_array())
thisTxCode.push_back(toByte(j)); thisTxCode.push_back(toByte(j));
@ -385,7 +386,7 @@ mArray FakeExtVM::exportCallCreates()
for (Transaction const& tx: callcreates) for (Transaction const& tx: callcreates)
{ {
mObject o; mObject o;
o["destination"] = toString(tx.receiveAddress); o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress);
push(o, "gasLimit", tx.gas); push(o, "gasLimit", tx.gas);
push(o, "value", tx.value); push(o, "value", tx.value);
o["data"] = "0x" + toHex(tx.data); o["data"] = "0x" + toHex(tx.data);
@ -404,6 +405,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("destination") > 0);
BOOST_REQUIRE(tx.count("gasLimit") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0);
Transaction t; Transaction t;
t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = Address(tx["destination"].get_str()); t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]); t.value = toInt(tx["value"]);
t.gas = toInt(tx["gasLimit"]); t.gas = toInt(tx["gasLimit"]);
@ -419,8 +421,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
} }
} }
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) // THIS IS BROKEN AND NEEDS TO BE REMOVED.
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
(void)o_sub;
if (!_origin) if (!_origin)
_origin = _sender; _origin = _sender;
@ -436,8 +441,8 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256()); m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256());
// Execute init code. // Execute init code.
auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); auto vmObj = VMFace::create(getVMKind(), *_gas);
VMFace& vm = *vmObj; auto& vm = *vmObj;
ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level);
bool revert = false; bool revert = false;
bytesConstRef out; bytesConstRef out;
@ -447,9 +452,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
out = vm.go(evm, _onOp); out = vm.go(evm, _onOp);
if (o_ms) if (o_ms)
o_ms->output = out.toBytes(); o_ms->output = out.toBytes();
if (o_suicides) // TODO: deal with evm.sub
for (auto i: evm.suicides)
o_suicides->insert(i);
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {
@ -484,8 +487,6 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
return _newAddress; return _newAddress;
} }
namespace dev { namespace test { namespace dev { namespace test {
void doTests(json_spirit::mValue& v, bool _fillin) void doTests(json_spirit::mValue& v, bool _fillin)
@ -499,7 +500,14 @@ void doTests(json_spirit::mValue& v, bool _fillin)
BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("pre") > 0);
BOOST_REQUIRE(o.count("exec") > 0); BOOST_REQUIRE(o.count("exec") > 0);
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
auto useJit = argc >= 2 && std::string(argv[1]) == "--jit";
auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter;
dev::test::FakeExtVM fev; dev::test::FakeExtVM fev;
fev.setVMKind(vmKind);
fev.importEnv(o["env"].get_obj()); fev.importEnv(o["env"].get_obj());
fev.importState(o["pre"].get_obj()); fev.importState(o["pre"].get_obj());
@ -513,24 +521,14 @@ void doTests(json_spirit::mValue& v, bool _fillin)
fev.code = &fev.thisTxCode; fev.code = &fev.thisTxCode;
} }
auto vm = VMFace::create(fev.getVMKind(), fev.gas);
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
auto useJit = argc >= 2 && std::string(argv[1]) == "--jit";
auto showTimes = false;
for (auto i = 0; i < argc; ++i)
showTimes |= std::string(argv[i]) == "--show-times";
auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter;
auto vm = VMFace::create(vmKind, fev.gas);
bytes output; bytes output;
auto outOfGas = false; auto outOfGas = false;
auto startTime = std::chrono::high_resolution_clock::now(); auto startTime = std::chrono::high_resolution_clock::now();
try try
{ {
output = vm->go(fev).toVector(); output = vm->go(fev, fev.simpleTrace<FakeExtVM>()).toVector();
} }
catch (OutOfGas const&) catch (OutOfGas const&)
{ {
@ -546,13 +544,17 @@ void doTests(json_spirit::mValue& v, bool _fillin)
} }
auto endTime = std::chrono::high_resolution_clock::now(); auto endTime = std::chrono::high_resolution_clock::now();
if (showTimes) for (auto i = 0; i < argc; ++i)
{
if (std::string(argv[i]) == "--show-times")
{ {
auto testDuration = endTime - startTime; auto testDuration = endTime - startTime;
cnote << "Execution time: " cnote << "Execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count() << std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count()
<< " ms"; << " ms";
} }
break;
}
auto gas = vm->gas(); auto gas = vm->gas();
@ -686,11 +688,13 @@ void executeTests(const string& _name)
if (ptestPath == NULL) if (ptestPath == NULL)
{ {
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests/vmtests"; testPath = "../../../tests";
} }
else else
testPath = ptestPath; testPath = ptestPath;
testPath += "/vmtests";
#ifdef FILL_TESTS #ifdef FILL_TESTS
try try
{ {
@ -719,7 +723,7 @@ void executeTests(const string& _name)
cnote << "Testing VM..." << _name; cnote << "Testing VM..." << _name;
json_spirit::mValue v; json_spirit::mValue v;
string s = asString(contents(testPath + "/" + _name + ".json")); string s = asString(contents(testPath + "/" + _name + ".json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
dev::test::doTests(v, false); dev::test::doTests(v, false);
} }
@ -786,4 +790,31 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest)
dev::test::executeTests("vmSystemOperationsTest"); dev::test::executeTests("vmSystemOperationsTest");
} }
BOOST_AUTO_TEST_CASE(userDefinedFile)
{
if (boost::unit_test::framework::master_test_suite().argc == 2)
{
string filename = boost::unit_test::framework::master_test_suite().argv[1];
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try
{
cnote << "Testing VM..." << "user defined test";
json_spirit::mValue v;
string s = asString(contents(filename));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
dev::test::doTests(v, false);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e));
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed VM Test with Exception: " << _e.what());
}
g_logVerbosity = currentVerbosity;
}
}

58
vm.h
View File

@ -28,6 +28,7 @@ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h" #include "JsonSpiritHeaders.h"
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <libevm/VM.h> #include <libevm/VM.h>
@ -44,24 +45,24 @@ class FakeState: public eth::State
{ {
public: public:
/// Execute a contract-creation transaction. /// Execute a contract-creation transaction.
h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = eth::OnOpFunc(), unsigned _level = 0); h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
}; };
class FakeExtVM: public eth::ExtVMFace class FakeExtVM: public eth::ExtVMFace
{ {
public: public:
FakeExtVM() {} FakeExtVM() = default;
FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0); FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0);
u256 store(u256 _n) override { return std::get<2>(addresses[myAddress])[_n]; } virtual u256 store(u256 _n) override { return std::get<2>(addresses[myAddress])[_n]; }
void setStore(u256 _n, u256 _v) override { std::get<2>(addresses[myAddress])[_n] = _v; } virtual void setStore(u256 _n, u256 _v) override { std::get<2>(addresses[myAddress])[_n] = _v; }
u256 balance(Address _a) override { return std::get<0>(addresses[_a]); } virtual u256 balance(Address _a) override { return std::get<0>(addresses[_a]); }
void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; } virtual void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; }
u256 txCount(Address _a) override { return std::get<1>(addresses[_a]); } virtual u256 txCount(Address _a) override { return std::get<1>(addresses[_a]); }
void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } virtual void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); }
bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); } virtual bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); }
h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc const&) override; virtual h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc const&) override;
bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc const&, Address, Address) override; virtual bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc const&, Address, Address) override;
void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data); void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data);
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code);
void set(Address _a, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code);
@ -79,6 +80,13 @@ public:
void importExec(json_spirit::mObject& _o); void importExec(json_spirit::mObject& _o);
json_spirit::mArray exportCallCreates(); json_spirit::mArray exportCallCreates();
void importCallCreates(json_spirit::mArray& _callcreates); void importCallCreates(json_spirit::mArray& _callcreates);
void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); }
eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); }
template<typename ExtVMType>
eth::OnOpFunc simpleTrace();
FakeState state() const { return m_s; }
std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes>> addresses; std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes>> addresses;
eth::Transactions callcreates; eth::Transactions callcreates;
@ -91,4 +99,32 @@ private:
eth::Manifest m_ms; eth::Manifest m_ms;
}; };
template<typename ExtVMType>
eth::OnOpFunc FakeExtVM::simpleTrace()
{
return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
{
ExtVMType const& ext = *(ExtVMType const*)voidExt;
eth::VM& vm = *(eth::VM*)voidVM;
std::ostringstream o;
o << std::endl << " STACK" << std::endl;
for (auto i: vm.stack())
o << (h256)i << std::endl;
o << " MEMORY" << std::endl << memDump(vm.memory());
o << " STORAGE" << std::endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o << std::showbase << std::hex << i.first << ": " << i.second << std::endl;
dev::LogOutputStream<eth::VMTraceChannel, false>(true) << o.str();
dev::LogOutputStream<eth::VMTraceChannel, false>(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]";
if (eth::VMTraceChannel::verbosity <= g_logVerbosity)
{
std::ofstream f;
f.open("./vmtrace.log", std::ofstream::app);
f << o.str();
f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32";
}
};
}
} } // Namespace Close } } // Namespace Close

View File

@ -670,6 +670,34 @@
} }
}, },
"jumpi2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff596002600357",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"pc0": { "pc0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

View File

@ -27,6 +27,34 @@
} }
}, },
"push1_missingStack": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x60",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"push2": { "push2": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

View File

@ -509,7 +509,7 @@
} }
}, },
"CallRecursiveBomb": { "CallRecursiveBomb0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0", "currentNumber" : "0",
@ -543,6 +543,90 @@
} }
}, },
"CallRecursiveBomb1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "1",
"gas" : "364723"
}
},
"CallRecursiveBomb2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "1",
"gas" : "364724"
}
},
"CallRecursiveBomb3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "1",
"gas" : "1000000"
}
},
"suicide0": { "suicide0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -949,6 +1033,77 @@
} }
}, },
"ABAcalls2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "0",
"code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0 0) } ",
"nonce" : "0",
"storage" : {
}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000000000000"
}
},
"ABAcalls3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1025000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "0",
"code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0 0) } ",
"nonce" : "0",
"storage" : {
}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "1000000"
}
},
"ABAcallsSuicide0": { "ABAcallsSuicide0": {
"env" : { "env" : {