Browse Source

bug fix

cl-refactor
Christoph Jentzsch 10 years ago
parent
commit
5a5a867eb3
  1. 20
      libethereum/ExtVM.h
  2. 35
      libevm/ExtVMFace.h
  3. 5
      libevmface/Instruction.cpp
  4. 3
      libevmface/Instruction.h
  5. 55
      test/createRandomTest.cpp
  6. 47
      test/vm.cpp
  7. 22
      test/vm.h

20
libethereum/ExtVM.h

@ -46,16 +46,16 @@ public:
}
/// Read storage location.
u256 store(u256 _n) { return m_s.storage(myAddress, _n); }
virtual u256 store(u256 _n) override final { return m_s.storage(myAddress, _n); }
/// Write a value in storage.
void setStore(u256 _n, u256 _v) { m_s.setStorage(myAddress, _n, _v); if (m_ms) m_ms->altered.push_back(_n); }
virtual void setStore(u256 _n, u256 _v) override final { m_s.setStorage(myAddress, _n, _v); if (m_ms) m_ms->altered.push_back(_n); }
/// Read address's code.
bytes const& codeAt(Address _a) { return m_s.code(_a); }
virtual bytes const& codeAt(Address _a) override final { return m_s.code(_a); }
/// Create a new contract.
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, OnOpFunc const& _onOp = OnOpFunc())
virtual h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, OnOpFunc const& _onOp = OnOpFunc()) override final
{
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
@ -68,7 +68,7 @@ public:
}
/// Create a new message call. Leave _myAddressOverride as the default to use the present address as caller.
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out, OnOpFunc const& _onOp = OnOpFunc(), Address _myAddressOverride = Address(), Address _codeAddressOverride = Address())
virtual bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out, OnOpFunc const& _onOp = {}, Address _myAddressOverride = {}, Address _codeAddressOverride = {}) override final
{
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
@ -79,16 +79,16 @@ public:
}
/// Read address's balance.
u256 balance(Address _a) { return m_s.balance(_a); }
virtual u256 balance(Address _a) override final { return m_s.balance(_a); }
/// Subtract amount from account's balance.
void subBalance(u256 _a) { m_s.subBalance(myAddress, _a); }
virtual void subBalance(u256 _a) override final { m_s.subBalance(myAddress, _a); }
/// Determine account's TX count.
u256 txCount(Address _a) { return m_s.transactionsFrom(_a); }
virtual u256 txCount(Address _a) override final { return m_s.transactionsFrom(_a); }
/// Suicide the associated contract to the given address.
void suicide(Address _a)
virtual void suicide(Address _a) override final
{
m_s.addBalance(_a, m_s.balance(myAddress));
ExtVMFace::suicide(_a);
@ -96,7 +96,7 @@ public:
/// Revert any changes made (by any of the other calls).
/// @TODO check call site for the parent manifest being discarded.
void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
virtual void revert() override final { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
State& state() const { return m_s; }

35
libevm/ExtVMFace.h

@ -21,7 +21,7 @@
#pragma once
#include <list>
#include <set>
#include <functional>
#include <libdevcore/Common.h>
#include <libevmface/Instruction.h>
@ -45,49 +45,54 @@ struct Post
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>;
/**
* @brief A null implementation of the class for specifying VM externalities.
* @brief Interface and null implementation of the class for specifying VM externalities.
*/
class ExtVMFace
{
public:
/// Null constructor.
ExtVMFace() {}
ExtVMFace() = default;
/// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; }
virtual ~ExtVMFace() = default;
ExtVMFace(ExtVMFace const&) = delete;
void operator=(ExtVMFace) = delete;
/// Read storage location.
u256 store(u256) { return 0; }
virtual u256 store(u256) { return 0; }
/// Write a value in storage.
void setStore(u256, u256) {}
virtual void setStore(u256, u256) {}
/// Read address's balance.
u256 balance(Address) { return 0; }
virtual u256 balance(Address) { return 0; }
/// Read address's code.
bytes const& codeAt(Address) { return NullBytes; }
virtual bytes const& codeAt(Address) { return NullBytes; }
/// Subtract amount from account's balance.
void subBalance(u256) {}
virtual void subBalance(u256) {}
/// Determine account's TX count.
u256 txCount(Address) { return 0; }
virtual u256 txCount(Address) { return 0; }
/// Suicide the associated contract and give proceeds to the given address.
void suicide(Address) { suicides.insert(myAddress); }
virtual void suicide(Address) { suicides.insert(myAddress); }
/// Create a new (contract) account.
h160 create(u256, u256*, bytesConstRef, bytesConstRef) { return h160(); }
virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); }
/// Make a new message call.
bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; }
virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; }
/// Revert any changes made (by any of the other calls).
void revert() {}
virtual void revert() {}
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }
Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
Address caller; ///< Address which sent the message (either equal to origin or a contract).

5
libevmface/Instruction.cpp

@ -318,3 +318,8 @@ InstructionInfo dev::eth::instructionInfo(Instruction _inst)
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0});
}
}
bool dev::eth::isValidInstruction(Instruction _inst)
{
return c_instructionInfo.count(_inst);
}

3
libevmface/Instruction.h

@ -180,6 +180,9 @@ struct InstructionInfo
/// Information on all the instructions.
InstructionInfo instructionInfo(Instruction _inst);
/// check whether instructions exists
bool isValidInstruction(Instruction _inst);
/// Convert from string mnemonic to Instruction type.
extern const std::map<std::string, Instruction> c_instructions;

55
test/createRandomTest.cpp

@ -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();
// disregard all invalid commands, except of one (0x10)
if (dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || opcode == 0x10)
randomCode += toHex(toCompactBigEndian(opcode));
else
i--;
}
// read template test file
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;
}

47
test/vm.cpp

@ -35,7 +35,7 @@ using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc)
h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&)
{
Transaction t;
t.value = _endowment;
@ -45,7 +45,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, OnOpFunc(), 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -61,7 +61,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
return ret;
}
bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc, 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;
@ -576,8 +576,44 @@ void doTests(json_spirit::mValue& v, bool _fillin)
else
BOOST_CHECK(output == fromHex(o["out"].get_str()));
BOOST_CHECK(test.toInt(o["gas"]) == vm.gas());
BOOST_CHECK(test.addresses == fev.addresses);
BOOST_CHECK_EQUAL(test.toInt(o["gas"]), vm.gas());
auto& expectedAddrs = test.addresses;
auto& resultAddrs = fev.addresses;
for (auto&& expectedPair : expectedAddrs)
{
auto& expectedAddr = expectedPair.first;
auto resultAddrIt = resultAddrs.find(expectedAddr);
if (resultAddrIt == resultAddrs.end())
BOOST_ERROR("Missing expected address " << expectedAddr);
else
{
auto& expectedState = expectedPair.second;
auto& resultState = resultAddrIt->second;
BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState));
BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState));
BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code");
auto&& expectedStore = std::get<2>(expectedState);
auto&& resultStore = std::get<2>(resultState);
for (auto&& expectedStorePair : expectedStore)
{
auto& expectedStoreKey = expectedStorePair.first;
auto resultStoreIt = resultStore.find(expectedStoreKey);
if (resultStoreIt == resultStore.end())
BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey);
else
{
auto& expectedStoreValue = expectedStorePair.second;
auto& resultStoreValue = resultStoreIt->second;
BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue);
}
}
}
}
BOOST_CHECK(test.addresses == fev.addresses); // Just to make sure nothing missed
BOOST_CHECK(test.callcreates == fev.callcreates);
}
}
@ -715,3 +751,4 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest)
{
dev::test::executeTests("vmSystemOperationsTest");
}

22
test/vm.h

@ -44,24 +44,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 = {}, std::set<Address>* o_suicides = 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) { return std::get<2>(addresses[myAddress])[_n]; }
void setStore(u256 _n, u256 _v) { std::get<2>(addresses[myAddress])[_n] = _v; }
u256 balance(Address _a) { return std::get<0>(addresses[_a]); }
void subBalance(u256 _a) { std::get<0>(addresses[myAddress]) -= _a; }
u256 txCount(Address _a) { return std::get<1>(addresses[_a]); }
void suicide(Address _a) { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); }
bytes const& codeAt(Address _a) { return std::get<3>(addresses[_a]); }
h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc);
bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc, Address, Address);
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);

Loading…
Cancel
Save