aboutsummaryrefslogtreecommitdiffstats
path: root/libevmasm/GasMeter.h
blob: 0bc10f1f2b10782403efb9bd6876b6e712551219 (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
131
132
133
134
135
136
137
/*
    This file is part of solidity.

    solidity 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.

    solidity 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 solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file GasMeter.cpp
 * @author Christian <c@ethdev.com>
 * @date 2015
 */

#pragma once

#include <ostream>
#include <tuple>
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/AssemblyItem.h>

namespace dev
{
namespace eth
{

class KnownState;

namespace GasCosts
{
    static unsigned const stackLimit = 1024;
    static unsigned const tier0Gas = 0;
    static unsigned const tier1Gas = 2;
    static unsigned const tier2Gas = 3;
    static unsigned const tier3Gas = 5;
    static unsigned const tier4Gas = 8;
    static unsigned const tier5Gas = 10;
    static unsigned const tier6Gas = 20;
    static unsigned const tier7Gas = 0;
    static unsigned const expGas = 10;
    static unsigned const expByteGas = 10;
    static unsigned const sha3Gas = 30;
    static unsigned const sha3WordGas = 6;
    static unsigned const sloadGas = 50;
    static unsigned const sstoreSetGas = 20000;
    static unsigned const sstoreResetGas = 5000;
    static unsigned const sstoreRefundGas = 15000;
    static unsigned const jumpdestGas = 1;
    static unsigned const logGas = 375;
    static unsigned const logDataGas = 8;
    static unsigned const logTopicGas = 375;
    static unsigned const createGas = 32000;
    static unsigned const callGas = 40;
    static unsigned const callStipend = 2300;
    static unsigned const callValueTransferGas = 9000;
    static unsigned const callNewAccountGas = 25000;
    static unsigned const suicideRefundGas = 24000;
    static unsigned const memoryGas = 3;
    static unsigned const quadCoeffDiv = 512;
    static unsigned const createDataGas = 200;
    static unsigned const txGas = 21000;
    static unsigned const txCreateGas = 53000;
    static unsigned const txDataZeroGas = 4;
    static unsigned const txDataNonZeroGas = 68;
    static unsigned const copyGas = 3;
}

/**
 * Class that helps computing the maximum gas consumption for instructions.
 * Has to be initialized with a certain known state that will be automatically updated for
 * each call to estimateMax. These calls have to supply strictly subsequent AssemblyItems.
 * A new gas meter has to be constructed (with a new state) for control flow changes.
 */
class GasMeter
{
public:
    struct GasConsumption
    {
        GasConsumption(unsigned _value = 0, bool _infinite = false): value(_value), isInfinite(_infinite) {}
        GasConsumption(u256 _value, bool _infinite = false): value(_value), isInfinite(_infinite) {}
        static GasConsumption infinite() { return GasConsumption(0, true); }

        GasConsumption& operator+=(GasConsumption const& _other);
        bool operator<(GasConsumption const& _other) const { return this->tuple() < _other.tuple(); }

        std::tuple<bool const&, u256 const&> tuple() const { return std::tie(isInfinite, value); }

        u256 value;
        bool isInfinite;
    };

    /// Constructs a new gas meter given the current state.
    explicit GasMeter(std::shared_ptr<KnownState> const& _state, u256 const& _largestMemoryAccess = 0):
        m_state(_state), m_largestMemoryAccess(_largestMemoryAccess) {}

    /// @returns an upper bound on the gas consumed by the given instruction and updates
    /// the state.
    /// @param _inculdeExternalCosts if true, include costs caused by other contracts in calls.
    GasConsumption estimateMax(AssemblyItem const& _item, bool _includeExternalCosts = true);

    u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; }

    static unsigned runGas(Instruction _instruction);

private:
    /// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
    GasConsumption wordGas(u256 const& _multiplier, ExpressionClasses::Id _value);
    /// @returns the gas needed to access the given memory position.
    /// @todo this assumes that memory was never accessed before and thus over-estimates gas usage.
    GasConsumption memoryGas(ExpressionClasses::Id _position);
    /// @returns the memory gas for accessing the memory at a specific offset for a number of bytes
    /// given as values on the stack at the given relative positions.
    GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);

    std::shared_ptr<KnownState> m_state;
    /// Largest point where memory was accessed since the creation of this object.
    u256 m_largestMemoryAccess;
};

inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption)
{
    if (_consumption.isInfinite)
        return _str << "[???]";
    else
        return _str << std::dec << _consumption.value;
}


}
}