aboutsummaryrefslogtreecommitdiffstats
path: root/vm.h
blob: e51fe3f89efa744ae15795b12cab498c13a51200 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
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 vm.h
 * @author Christoph Jentzsch <jentzsch.simulationsoftware@gmail.com>
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * vm test functions.
 */

#pragma once

#include <fstream>
#include <cstdint>
#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>
#include <liblll/Compiler.h>
#include <libethereum/Transaction.h>
#include <libethereum/ExtVM.h>
#include <libethereum/State.h>

namespace dev { namespace test {

struct FakeExtVMFailure : virtual Exception {};

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 = {}, eth::SubState* o_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
};

class FakeExtVM: public eth::ExtVMFace
{
public:
    FakeExtVM() = default;
    FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0);

    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);
    void reset(u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage);
    u256 toInt(json_spirit::mValue const& _v);
    byte toByte(json_spirit::mValue const& _v);
    void push(json_spirit::mObject& o, std::string const& _n, u256 _v);
    void push(json_spirit::mArray& a, u256 _v);
    u256 doPosts();
    json_spirit::mObject exportEnv();
    void importEnv(json_spirit::mObject& _o);
    json_spirit::mObject exportState();
    void importState(json_spirit::mObject& _object);
    json_spirit::mObject exportExec();
    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;
    bytes thisTxData;
    bytes thisTxCode;
    u256 gas;

private:
    FakeState m_s;
    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