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 secp256k1)
target_link_libraries(testeth gmp)
target_link_libraries(testeth solidity)
target_link_libraries(testeth ${CRYPTOPP_LS})
target_link_libraries(testeth evm)
target_link_libraries(testeth evmjit)

View File

@ -437,12 +437,12 @@ MemTrie::~MemTrie()
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
{
return m_root ? m_root->rlp() : bytes();
return m_root ? m_root->rlp() : dev::rlp(bytesConstRef());
}
void MemTrie::debugPrint()

View File

@ -21,23 +21,7 @@
#pragma once
//#include <ostream>
#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
#include <libdevcrypto/CryptoPP.h>
using namespace std;
using namespace CryptoPP;

View File

@ -162,7 +162,7 @@ h256 hash256(StringMap const& _s)
{
// build patricia tree.
if (_s.empty())
return h256();
return sha3(rlp(""));
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second;
@ -175,7 +175,7 @@ bytes rlp256(StringMap const& _s)
{
// build patricia tree.
if (_s.empty())
return bytes();
return rlp("");
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second;
@ -188,7 +188,7 @@ h256 hash256(u256Map const& _s)
{
// build patricia tree.
if (_s.empty())
return h256();
return sha3(rlp(""));
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
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[])
{
if (argc != 2)
{
cout << "usage: createRandomTest <filename>\n";
return 0;
}
g_logVerbosity = 0;
// create random code
@ -64,14 +60,48 @@ int main(int argc, char *argv[])
string randomCode;
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;
boost::filesystem::path p(__FILE__);
boost::filesystem::path dir = p.parent_path();
string s = asString(contents(dir.string() + "/randomTestFiller.json"));
read_string(s, v);
// insert new random code
@ -80,9 +110,8 @@ int main(int argc, char *argv[])
// execute code in vm
doMyTests(v);
// write new test
string filename = argv[1];
writeFile(filename, asBytes(json_spirit::write_string(v, true)));
// stream to output for further handling by the bash script
cout << json_spirit::write_string(v, true);
return 0;
}

View File

@ -27,37 +27,163 @@
#include <libdevcore/Log.h>
#include <libethereum/Transaction.h>
#include <boost/test/unit_test.hpp>
#include <libdevcrypto/EC.h>
#include "TestHelperCrypto.h"
using namespace std;
using namespace dev;
namespace dev
{
namespace crypto
{
inline CryptoPP::AutoSeededRandomPool& PRNG() {
static CryptoPP::AutoSeededRandomPool prng;
return prng;
}
}
}
using namespace dev::crypto;
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)
{
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(prng, ASN1::secp256r1());
ECIES<ECP>::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1());
SavePrivateKey(localDecryptor.GetPrivateKey());
ECIES<ECP>::Encryptor localEncryptor(localDecryptor);
@ -65,31 +191,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
ECIES<ECP>::Decryptor futureDecryptor;
LoadPrivateKey(futureDecryptor.AccessPrivateKey());
futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3);
futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3);
ECIES<ECP>::Encryptor futureEncryptor;
LoadPublicKey(futureEncryptor.AccessPublicKey());
futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3);
futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3);
// encrypt/decrypt with local
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;
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
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;
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
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
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);
@ -98,98 +224,112 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
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;
OID curve = ASN1::secp256r1();
ECDH<ECP>::Domain dhLocal(curve);
SecByteBlock privLocal(dhLocal.PrivateKeyLength());
SecByteBlock pubLocal(dhLocal.PublicKeyLength());
dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal);
// generate test key
AutoSeededRandomPool rng;
SecByteBlock key(0x00, aesKeyLen);
rng.GenerateBlock(key, key.size());
ECDH<ECP>::Domain dhRemote(curve);
SecByteBlock privRemote(dhRemote.PrivateKeyLength());
SecByteBlock pubRemote(dhRemote.PublicKeyLength());
dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote);
// cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
byte ctr[AES::BLOCKSIZE];
rng.GenerateBlock(ctr, sizeof(ctr));
assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength());
string text = "Now is the time for all good persons to come to the aide of humanity.";
// c++11 ftw
unsigned char const* in = (unsigned char*)&text[0];
unsigned char* out = (unsigned char*)&text[0];
string original = text;
// local: send public to remote; remote: send public to local
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
SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
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;
}
// Remote
SecByteBlock sharedRemote(dhRemote.AgreedValueLength());
assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal));
// Test
Integer ssLocal, ssRemote;
ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes());
ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
// reencrypt ciphertext...
try
{
assert(cipherCopy != text);
in = (unsigned char*)&cipherCopy[0];
out = (unsigned char*)&cipherCopy[0];
CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr);
e.ProcessData(out, in, text.size());
// yep, ctr mode.
assert(cipherCopy == original);
}
catch(CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
assert(ssLocal != 0);
assert(ssLocal == ssRemote);
}
BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth)
BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc)
{
// 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
const int aesKeyLen = 16;
assert(sizeof(char) == sizeof(byte));
AutoSeededRandomPool rng;
SecByteBlock key(0x00, aesKeyLen);
rng.GenerateBlock(key, key.size());
// Generate random IV
byte iv[AES::BLOCKSIZE];
rng.GenerateBlock(iv, AES::BLOCKSIZE);
string string128("AAAAAAAAAAAAAAAA");
string plainOriginal = string128;
CryptoPP::CBC_Mode<Rijndael>::Encryption cbcEncryption(key, key.size(), iv);
cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
assert(string128 != plainOriginal);
CBC_Mode<Rijndael>::Decryption cbcDecryption(key, key.size(), iv);
cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
assert(plainOriginal == string128);
// plaintext whose size isn't divisible by block size must use stream filter for padding
string string192("AAAAAAAAAAAAAAAABBBBBBBB");
plainOriginal = string192;
string cipher;
StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher));
StringSource source(string192, true, aesStream);
assert(cipher.size() == 32);
cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size());
assert(string192 == plainOriginal);
}
BOOST_AUTO_TEST_CASE(cryptopp_eth_fbba)
{
// Initial Authentication:
//
// New/Known Peer:
// pubkeyL = knownR? ? myKnown : myECDH
// pubkeyR = knownR? ? theirKnown : theirECDH
//
// Initial message = hmac(k=sha3(shared-secret[128..255]), address(pubkeyL)) || ECIES encrypt(pubkeyR, pubkeyL)
//
// Key Exchange (this could occur after handshake messages):
// If peers do not know each other they will need to exchange public keys.
//
// Drop ECDH (this could occur after handshake messages):
// After authentication and/or key exchange, both sides generate shared key
// from their 'known' keys and use this to encrypt all future messages.
//
// v2: If one side doesn't trust the other then a single-use key maybe sent.
// This will need to be tracked for future connections; when non-trusting peer
// 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
// that a new, 'new', public key be accepted.
//
// Handshake (all or nothing, padded):
// All Peers (except blacklisted):
//
//
// New Peer:
//
//
// Known Untrusted Peer:
//
//
// Known Trusted Peer:
//
//
// Blacklisted Peeer:
// Already dropped by now.
//
//
// MAC:
// ...
}
BOOST_AUTO_TEST_CASE(eth_keypairs)
{
cnote << "Testing Crypto...";
@ -201,6 +341,7 @@ BOOST_AUTO_TEST_CASE(eth_keypairs)
{
eth::Transaction t;
t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000;
auto rlp = t.rlp(false);
@ -229,6 +370,7 @@ int cryptoTest()
{
eth::Transaction t;
t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000;
auto rlp = t.rlp(false);
@ -257,6 +399,7 @@ int cryptoTest()
Transaction t;
t.nonce = 0;
t.value = 1; // 1 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = toAddress(sha3("123"));
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)
{
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...";
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?");
js::read_string(s, v);

View File

@ -33,9 +33,20 @@ namespace js = json_spirit;
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...";
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?");
js::read_string(s, v);
for (auto& i: v.get_obj())

View File

@ -44,7 +44,7 @@ using namespace dev::eth;
BOOST_AUTO_TEST_CASE(basic_tests)
{
/* RLPStream s;
BlockInfo::genesis().fillStream(s, false);
BlockInfo::genesis().streamRLP(s, false);
std::cout << RLP(s.out()) << std::endl;
std::cout << toHex(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)
{
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,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
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;
t.nonce = s.transactionsFrom(myMiner.address());
t.value = 1000; // 1e3 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = me.address();
t.sign(myMiner.secret());
assert(t.sender() == myMiner.address());

View File

@ -49,9 +49,20 @@ static unsigned fac(unsigned _i)
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...";
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?");
js::read_string(s, v);
for (auto& i: v.get_obj())

121
vm.cpp
View File

@ -20,11 +20,9 @@
* vm test functions.
*/
#include "vm.h"
#include <libdevcore/CommonIO.h>
#include <libevmjit/VM.h>
#include <boost/filesystem/path.hpp>
#include <chrono>
#include <boost/filesystem/path.hpp>
#include "vm.h"
//#define FILL_TESTS
using namespace std;
@ -46,7 +44,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress);
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)
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);
}
t.receiveAddress = ret;
t.type = eth::Transaction::ContractCreation;
callcreates.push_back(t);
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;
Transaction t;
@ -72,6 +69,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _data.toVector();
t.type = eth::Transaction::MessageCall;
t.receiveAddress = _receiveAddress;
callcreates.push_back(t);
@ -92,7 +90,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!m_s.addresses().count(myAddress))
{
m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &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)
m_ms.internal.pop_back();
if (na != myAddress)
@ -117,7 +115,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &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)
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);
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)
m_ms.internal.pop_back();
@ -147,12 +145,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!ret)
return false;
// TODO: @CJentzsch refund SSTORE stuff.
// TODO: @CJentzsch test logs.
// do suicides
for (auto const& f: suicides)
for (auto const& f: sub.suicides)
addresses.erase(f);
// 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))
{
@ -357,10 +358,10 @@ void FakeExtVM::importExec(mObject& _o)
thisTxCode.clear();
code = &thisTxCode;
if (_o["code"].type() == str_type)
if (_o["code"].get_str().find_first_of("0x") != 0)
thisTxCode = compileLLL(_o["code"].get_str());
else
if (_o["code"].get_str().find_first_of("0x") == 0)
thisTxCode = fromHex(_o["code"].get_str().substr(2));
else
thisTxCode = compileLLL(_o["code"].get_str());
else if (_o["code"].type() == array_type)
for (auto const& j: _o["code"].get_array())
thisTxCode.push_back(toByte(j));
@ -385,7 +386,7 @@ mArray FakeExtVM::exportCallCreates()
for (Transaction const& tx: callcreates)
{
mObject o;
o["destination"] = toString(tx.receiveAddress);
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);
@ -404,6 +405,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
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"]);
@ -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)
_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());
// Execute init code.
auto vmObj = VMFace::create(VMFace::Interpreter, *_gas);
VMFace& vm = *vmObj;
auto vmObj = VMFace::create(getVMKind(), *_gas);
auto& vm = *vmObj;
ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level);
bool revert = false;
bytesConstRef out;
@ -447,9 +452,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
out = vm.go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
// TODO: deal with evm.sub
}
catch (OutOfGas const& /*_e*/)
{
@ -484,8 +487,6 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
return _newAddress;
}
namespace dev { namespace test {
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("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;
fev.setVMKind(vmKind);
fev.importEnv(o["env"].get_obj());
fev.importState(o["pre"].get_obj());
@ -512,25 +520,15 @@ void doTests(json_spirit::mValue& v, bool _fillin)
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode;
}
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);
auto vm = VMFace::create(fev.getVMKind(), fev.gas);
bytes output;
auto outOfGas = false;
auto startTime = std::chrono::high_resolution_clock::now();
try
{
output = vm->go(fev).toVector();
output = vm->go(fev, fev.simpleTrace<FakeExtVM>()).toVector();
}
catch (OutOfGas const&)
{
@ -546,12 +544,16 @@ void doTests(json_spirit::mValue& v, bool _fillin)
}
auto endTime = std::chrono::high_resolution_clock::now();
if (showTimes)
{
auto testDuration = endTime - startTime;
cnote << "Execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count()
<< " ms";
for (auto i = 0; i < argc; ++i)
{
if (std::string(argv[i]) == "--show-times")
{
auto testDuration = endTime - startTime;
cnote << "Execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count()
<< " ms";
}
break;
}
auto gas = vm->gas();
@ -686,11 +688,13 @@ void executeTests(const string& _name)
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests/vmtests";
testPath = "../../../tests";
}
else
testPath = ptestPath;
testPath += "/vmtests";
#ifdef FILL_TESTS
try
{
@ -719,7 +723,7 @@ void executeTests(const string& _name)
cnote << "Testing VM..." << _name;
json_spirit::mValue v;
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);
dev::test::doTests(v, false);
}
@ -786,4 +790,31 @@ BOOST_AUTO_TEST_CASE(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 "JsonSpiritHeaders.h"
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h>
#include <libevm/ExtVMFace.h>
#include <libevm/VM.h>
@ -44,24 +45,24 @@ class FakeState: public eth::State
{
public:
/// Execute a contract-creation transaction.
h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = 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
{
public:
FakeExtVM() {}
FakeExtVM() = default;
FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0);
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; }
u256 balance(Address _a) override { return std::get<0>(addresses[_a]); }
void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; }
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); }
bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); }
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 u256 store(u256 _n) override { return std::get<2>(addresses[myAddress])[_n]; }
virtual void setStore(u256 _n, u256 _v) override { std::get<2>(addresses[myAddress])[_n] = _v; }
virtual u256 balance(Address _a) override { return std::get<0>(addresses[_a]); }
virtual void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; }
virtual u256 txCount(Address _a) override { return std::get<1>(addresses[_a]); }
virtual void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); }
virtual bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); }
virtual h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc const&) 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 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);
@ -79,6 +80,13 @@ public:
void importExec(json_spirit::mObject& _o);
json_spirit::mArray exportCallCreates();
void importCallCreates(json_spirit::mArray& _callcreates);
void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); }
eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); }
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;
eth::Transactions callcreates;
@ -91,4 +99,32 @@ private:
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

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": {
"env" : {
"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": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

View File

@ -509,7 +509,7 @@
}
},
"CallRecursiveBomb": {
"CallRecursiveBomb0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"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": {
"env" : {
"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": {
"env" : {