2014-03-26 05:01:17 +00:00
|
|
|
/*
|
|
|
|
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/>.
|
|
|
|
*/
|
|
|
|
/** @file TestHelper.cpp
|
|
|
|
* @author Marko Simovic <markobarko@gmail.com>
|
|
|
|
* @date 2014
|
|
|
|
*/
|
|
|
|
|
2014-09-05 15:09:58 +00:00
|
|
|
#include "TestHelper.h"
|
|
|
|
|
2014-03-26 05:01:17 +00:00
|
|
|
#include <thread>
|
|
|
|
#include <chrono>
|
2014-04-23 14:08:11 +00:00
|
|
|
#include <libethereum/Client.h>
|
2014-10-29 16:25:02 +00:00
|
|
|
#include <liblll/Compiler.h>
|
|
|
|
|
|
|
|
using namespace std;
|
2014-03-26 05:01:17 +00:00
|
|
|
|
2014-09-05 15:09:58 +00:00
|
|
|
namespace dev
|
|
|
|
{
|
2014-03-26 05:01:17 +00:00
|
|
|
namespace eth
|
|
|
|
{
|
|
|
|
|
|
|
|
void mine(Client& c, int numBlocks)
|
|
|
|
{
|
|
|
|
auto startBlock = c.blockChain().details().number;
|
|
|
|
|
|
|
|
c.startMining();
|
|
|
|
while(c.blockChain().details().number < startBlock + numBlocks)
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
c.stopMining();
|
|
|
|
}
|
|
|
|
|
2014-04-03 15:01:03 +00:00
|
|
|
void connectClients(Client& c1, Client& c2)
|
|
|
|
{
|
2014-09-30 14:53:15 +00:00
|
|
|
(void)c1;
|
|
|
|
(void)c2;
|
2014-09-16 12:09:48 +00:00
|
|
|
// TODO: Move to WebThree. eth::Client no longer handles networking.
|
2014-09-15 19:49:52 +00:00
|
|
|
#if 0
|
2014-04-03 15:01:03 +00:00
|
|
|
short c1Port = 20000;
|
|
|
|
short c2Port = 21000;
|
|
|
|
c1.startNetwork(c1Port);
|
|
|
|
c2.startNetwork(c2Port);
|
|
|
|
c2.connect("127.0.0.1", c1Port);
|
2014-09-15 19:49:52 +00:00
|
|
|
#endif
|
2014-04-03 15:01:03 +00:00
|
|
|
}
|
|
|
|
|
2014-10-29 16:25:02 +00:00
|
|
|
namespace test
|
|
|
|
{
|
|
|
|
|
2014-10-31 08:41:02 +00:00
|
|
|
ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):m_TestObject(_o)
|
2014-10-29 16:25:02 +00:00
|
|
|
{
|
2014-10-31 08:41:02 +00:00
|
|
|
|
2014-10-29 16:25:02 +00:00
|
|
|
importEnv(_o["env"].get_obj());
|
|
|
|
importState(_o["pre"].get_obj(), m_statePre);
|
|
|
|
importExec(_o["exec"].get_obj());
|
|
|
|
|
|
|
|
if (!isFiller)
|
|
|
|
{
|
|
|
|
importState(_o["post"].get_obj(), m_statePost);
|
2014-10-31 08:41:02 +00:00
|
|
|
//importCallCreates(_o["callcreates"].get_array());
|
2014-10-29 16:25:02 +00:00
|
|
|
importGas(_o);
|
|
|
|
importOutput(_o);
|
|
|
|
}
|
2014-10-31 08:41:02 +00:00
|
|
|
// else
|
|
|
|
// m_TestObject = &_o; // if Filler then change Test object to prepare for export
|
2014-03-26 05:01:17 +00:00
|
|
|
}
|
2014-10-29 16:25:02 +00:00
|
|
|
|
|
|
|
void ImportTest::importEnv(json_spirit::mObject& _o)
|
|
|
|
{
|
|
|
|
assert(_o.count("previousHash") > 0);
|
|
|
|
assert(_o.count("currentGasLimit") > 0);
|
|
|
|
assert(_o.count("currentDifficulty") > 0);
|
|
|
|
assert(_o.count("currentTimestamp") > 0);
|
|
|
|
assert(_o.count("currentCoinbase") > 0);
|
|
|
|
assert(_o.count("currentNumber") > 0);
|
|
|
|
|
|
|
|
m_environment.previousBlock.hash = h256(_o["previousHash"].get_str());
|
|
|
|
m_environment.currentBlock.number = toInt(_o["currentNumber"]);
|
|
|
|
m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]);
|
|
|
|
m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]);
|
|
|
|
m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]);
|
|
|
|
m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
|
2014-10-31 08:41:02 +00:00
|
|
|
|
|
|
|
m_statePre.m_previousBlock = m_environment.previousBlock;
|
|
|
|
m_statePre.m_currentBlock = m_environment.currentBlock;
|
2014-09-05 15:09:58 +00:00
|
|
|
}
|
2014-10-29 16:25:02 +00:00
|
|
|
|
|
|
|
void ImportTest::importState(json_spirit::mObject& _o, State& _state)
|
|
|
|
{
|
2014-10-31 08:41:02 +00:00
|
|
|
for (auto& i: _o)
|
2014-10-29 16:25:02 +00:00
|
|
|
{
|
|
|
|
json_spirit::mObject o = i.second.get_obj();
|
|
|
|
|
|
|
|
assert(o.count("balance") > 0);
|
|
|
|
assert(o.count("nonce") > 0);
|
|
|
|
assert(o.count("storage") > 0);
|
|
|
|
assert(o.count("code") > 0);
|
|
|
|
|
|
|
|
Address address = Address(i.first);
|
2014-10-31 08:41:02 +00:00
|
|
|
_state.m_cache[address] = AddressState(toInt(o["nonce"]), toInt(o["balance"]), EmptyTrie, h256());
|
2014-10-29 16:25:02 +00:00
|
|
|
|
|
|
|
for (auto const& j: o["storage"].get_obj())
|
|
|
|
_state.setStorage(address, toInt(j.first), toInt(j.second));
|
|
|
|
|
|
|
|
bytes code;
|
|
|
|
if (o["code"].type() == json_spirit::str_type)
|
|
|
|
if (o["code"].get_str().find_first_of("0x") != 0)
|
|
|
|
code = compileLLL(o["code"].get_str(), false);
|
|
|
|
else
|
|
|
|
code = fromHex(o["code"].get_str().substr(2));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
code.clear();
|
|
|
|
for (auto const& j: o["code"].get_array())
|
|
|
|
code.push_back(toByte(j));
|
|
|
|
}
|
|
|
|
|
2014-10-31 08:41:02 +00:00
|
|
|
i.second.get_obj()["code"] = "0x" + toHex(code); //preperation for export
|
|
|
|
|
2014-10-29 16:25:02 +00:00
|
|
|
_state.m_cache[address].setCode(bytesConstRef(&code));
|
|
|
|
_state.ensureCached(address, true, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImportTest::importExec(json_spirit::mObject& _o)
|
|
|
|
{
|
|
|
|
assert(_o.count("address")> 0);
|
|
|
|
assert(_o.count("caller") > 0);
|
|
|
|
assert(_o.count("origin") > 0);
|
|
|
|
assert(_o.count("value") > 0);
|
|
|
|
assert(_o.count("data") > 0);
|
|
|
|
assert(_o.count("gasPrice") > 0);
|
|
|
|
assert(_o.count("gas") > 0);
|
2014-10-31 08:41:02 +00:00
|
|
|
//assert(_o.count("code") > 0);
|
2014-10-29 16:25:02 +00:00
|
|
|
|
|
|
|
m_environment.myAddress = Address(_o["address"].get_str());
|
|
|
|
m_environment.caller = Address(_o["caller"].get_str());
|
|
|
|
m_environment.origin = Address(_o["origin"].get_str());
|
|
|
|
m_environment.value = toInt(_o["value"]);
|
|
|
|
m_environment.gasPrice = toInt(_o["gasPrice"]);
|
|
|
|
gasExec = toInt(_o["gas"]);
|
|
|
|
|
|
|
|
if (_o["code"].type() == json_spirit::str_type)
|
|
|
|
if (_o["code"].get_str().find_first_of("0x") == 0)
|
|
|
|
code = fromHex(_o["code"].get_str().substr(2));
|
|
|
|
else
|
|
|
|
code = compileLLL(_o["code"].get_str());
|
|
|
|
else if (_o["code"].type() == json_spirit::array_type)
|
|
|
|
for (auto const& j: _o["code"].get_array())
|
|
|
|
code.push_back(toByte(j));
|
|
|
|
else
|
|
|
|
m_environment.code.reset();
|
|
|
|
m_environment.code = &code;
|
|
|
|
|
|
|
|
if (_o["data"].type() == json_spirit::str_type)
|
|
|
|
if (_o["data"].get_str().find_first_of("0x") == 0)
|
|
|
|
data = fromHex(_o["data"].get_str().substr(2));
|
|
|
|
else
|
|
|
|
data = fromHex(_o["data"].get_str());
|
|
|
|
else
|
|
|
|
for (auto const& j: _o["data"].get_array())
|
|
|
|
data.push_back(toByte(j));
|
|
|
|
m_environment.data = &data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImportTest::importCallCreates(json_spirit::mArray& _callcreates)
|
|
|
|
{
|
|
|
|
for (json_spirit::mValue& v: _callcreates)
|
|
|
|
{
|
|
|
|
auto tx = v.get_obj();
|
|
|
|
assert(tx.count("data") > 0);
|
|
|
|
assert(tx.count("value") > 0);
|
|
|
|
assert(tx.count("destination") > 0);
|
|
|
|
assert(tx.count("gasLimit") > 0);
|
|
|
|
Transaction t;
|
|
|
|
t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall;
|
|
|
|
t.receiveAddress = Address(tx["destination"].get_str());
|
|
|
|
t.value = toInt(tx["value"]);
|
|
|
|
t.gas = toInt(tx["gasLimit"]);
|
|
|
|
if (tx["data"].type() == json_spirit::str_type)
|
|
|
|
if (tx["data"].get_str().find_first_of("0x") == 0)
|
|
|
|
t.data = fromHex(tx["data"].get_str().substr(2));
|
|
|
|
else
|
|
|
|
t.data = fromHex(tx["data"].get_str());
|
|
|
|
else
|
|
|
|
for (auto const& j: tx["data"].get_array())
|
|
|
|
t.data.push_back(toByte(j));
|
|
|
|
callcreates.push_back(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImportTest::importGas(json_spirit::mObject& _o)
|
|
|
|
{
|
|
|
|
gas = toInt(_o["gas"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImportTest::importOutput(json_spirit::mObject& _o)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
if (_o["out"].type() == json_spirit::array_type)
|
|
|
|
for (auto const& d: _o["out"].get_array())
|
|
|
|
{
|
|
|
|
output[i] = uint8_t(toInt(d));
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
else if (_o["out"].get_str().find("0x") == 0)
|
|
|
|
output = fromHex(_o["out"].get_str().substr(2));
|
|
|
|
else
|
|
|
|
output = fromHex(_o["out"].get_str());
|
|
|
|
}
|
|
|
|
|
2014-10-31 08:41:02 +00:00
|
|
|
void ImportTest::exportTest(bytes _output, u256 _gas, State& _statePost)
|
|
|
|
{
|
|
|
|
// export gas
|
|
|
|
m_TestObject["gas"] = toString(_gas);
|
|
|
|
|
|
|
|
// export output
|
|
|
|
m_TestObject["out"] = "0x" + toHex(_output);
|
|
|
|
|
|
|
|
// export post state
|
|
|
|
json_spirit::mObject postState;
|
|
|
|
|
|
|
|
std::map<Address, AddressState> genesis = genesisState();
|
|
|
|
|
|
|
|
for (auto const& a: _statePost.addresses())
|
|
|
|
{
|
|
|
|
if (genesis.count(a.first))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
json_spirit::mObject o;
|
|
|
|
o["balance"] = toString(_statePost.balance(a.first));
|
|
|
|
o["nonce"] = toString(_statePost.transactionsFrom(a.first));
|
|
|
|
{
|
|
|
|
json_spirit::mObject store;
|
|
|
|
for (auto const& s: _statePost.storage(a.first))
|
|
|
|
store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second));
|
|
|
|
o["storage"] = store;
|
|
|
|
}
|
|
|
|
o["code"] = "0x" + toHex(_statePost.code(a.first));
|
|
|
|
|
|
|
|
postState[toString(a.first)] = o;
|
|
|
|
}
|
|
|
|
m_TestObject["post"] = json_spirit::mValue(postState);
|
|
|
|
|
|
|
|
m_TestObject["exec"].get_obj()["code"] = "0x" + toHex(code);
|
|
|
|
|
|
|
|
// // export callcreates
|
|
|
|
// m_TestObject["callcreates"] = exportCallCreates();
|
|
|
|
|
|
|
|
// for (int i = 0; i < (m_manifest.internal.size(); ++i)
|
|
|
|
// {
|
|
|
|
// Transaction t;
|
|
|
|
// t.value = m_manifest.internal[i].value;
|
|
|
|
// t.gas = ;
|
|
|
|
// t.data = m_manifest.internal[i].input; ;
|
|
|
|
// t.receiveAddress = m_manifest.internal[i].to;
|
|
|
|
// t.type =
|
|
|
|
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
2014-10-29 16:25:02 +00:00
|
|
|
u256 toInt(json_spirit::mValue const& _v)
|
|
|
|
{
|
|
|
|
switch (_v.type())
|
|
|
|
{
|
|
|
|
case json_spirit::str_type: return u256(_v.get_str());
|
|
|
|
case json_spirit::int_type: return (u256)_v.get_uint64();
|
|
|
|
case json_spirit::bool_type: return (u256)(uint64_t)_v.get_bool();
|
|
|
|
case json_spirit::real_type: return (u256)(uint64_t)_v.get_real();
|
|
|
|
default: cwarn << "Bad type for scalar: " << _v.type();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte toByte(json_spirit::mValue const& _v)
|
|
|
|
{
|
|
|
|
switch (_v.type())
|
|
|
|
{
|
|
|
|
case json_spirit::str_type: return (byte)stoi(_v.get_str());
|
|
|
|
case json_spirit::int_type: return (byte)_v.get_uint64();
|
|
|
|
case json_spirit::bool_type: return (byte)_v.get_bool();
|
|
|
|
case json_spirit::real_type: return (byte)_v.get_real();
|
|
|
|
default: cwarn << "Bad type for scalar: " << _v.type();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} } } // namespaces
|