github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/vm/gas.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"reflect"
    23  )
    24  
    25  const stackLimit = 1024 // maximum size of VM stack allowed.
    26  
    27  var (
    28  	GasQuickStep   = big.NewInt(2)
    29  	GasFastestStep = big.NewInt(3)
    30  	GasFastStep    = big.NewInt(5)
    31  	GasMidStep     = big.NewInt(8)
    32  	GasSlowStep    = big.NewInt(10)
    33  	GasExtStep     = big.NewInt(20)
    34  
    35  	GasReturn = big.NewInt(0)
    36  	GasStop   = big.NewInt(0)
    37  
    38  	GasContractByte = big.NewInt(200)
    39  
    40  	n64 = big.NewInt(64)
    41  )
    42  
    43  type GasTable struct {
    44  	ExtcodeSize *big.Int
    45  	ExtcodeCopy *big.Int
    46  	Balance     *big.Int
    47  	SLoad       *big.Int
    48  	Calls       *big.Int
    49  	Suicide     *big.Int
    50  	ExpByte     *big.Int
    51  
    52  	// CreateBySuicide occurs when the
    53  	// refunded account is one that does
    54  	// not exist. This logic is similar
    55  	// to call. May be left nil. Nil means
    56  	// not charged.
    57  	CreateBySuicide *big.Int
    58  }
    59  
    60  // calcGas returns the actual gas cost of the call.
    61  //
    62  // The cost of gas was changed during the homestead price change HF. To allow for EIP150
    63  // to be implemented. The returned gas is gas - base * 63 / 64.
    64  func callGas(gasTable *GasTable, availableGas, base, callCost *big.Int) *big.Int {
    65  	if gasTable.CreateBySuicide != nil {
    66  		availableGas = new(big.Int).Sub(availableGas, base)
    67  		g := new(big.Int).Div(availableGas, n64)
    68  		g.Sub(availableGas, g)
    69  
    70  		if g.Cmp(callCost) < 0 {
    71  			return g
    72  		}
    73  	}
    74  	return callCost
    75  }
    76  
    77  // IsEmpty return true if all values are zero values,
    78  // which useful for checking JSON-decoded empty state.
    79  func (g *GasTable) IsEmpty() bool {
    80  	return reflect.DeepEqual(g, GasTable{})
    81  }
    82  
    83  // baseCheck checks for any stack error underflows
    84  func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
    85  	// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
    86  	// PUSH is also allowed to calculate the same price for all PUSHes
    87  	// DUP requirements are handled elsewhere (except for the stack limit check)
    88  	if op >= PUSH1 && op <= PUSH32 {
    89  		op = PUSH1
    90  	}
    91  	if op >= DUP1 && op <= DUP16 {
    92  		op = DUP1
    93  	}
    94  
    95  	if r, ok := _baseCheck[op]; ok {
    96  		err := stack.require(r.stackPop)
    97  		if err != nil {
    98  			return err
    99  		}
   100  
   101  		if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > stackLimit {
   102  			return fmt.Errorf("stack length %d exceed limit %d", stack.len(), stackLimit)
   103  		}
   104  
   105  		gas.Add(gas, r.gas)
   106  	}
   107  	return nil
   108  }
   109  
   110  // casts a arbitrary number to the amount of words (sets of 32 bytes)
   111  func toWordSize(size *big.Int) *big.Int {
   112  	tmp := new(big.Int)
   113  	tmp.Add(size, u256(31))
   114  	tmp.Div(tmp, u256(32))
   115  	return tmp
   116  }
   117  
   118  type req struct {
   119  	stackPop  int
   120  	gas       *big.Int
   121  	stackPush int
   122  }
   123  
   124  var _baseCheck = map[OpCode]req{
   125  	// opcode  |  stack pop | gas price | stack push
   126  	ADD:          {2, GasFastestStep, 1},
   127  	LT:           {2, GasFastestStep, 1},
   128  	GT:           {2, GasFastestStep, 1},
   129  	SLT:          {2, GasFastestStep, 1},
   130  	SGT:          {2, GasFastestStep, 1},
   131  	EQ:           {2, GasFastestStep, 1},
   132  	ISZERO:       {1, GasFastestStep, 1},
   133  	SUB:          {2, GasFastestStep, 1},
   134  	AND:          {2, GasFastestStep, 1},
   135  	OR:           {2, GasFastestStep, 1},
   136  	XOR:          {2, GasFastestStep, 1},
   137  	NOT:          {1, GasFastestStep, 1},
   138  	BYTE:         {2, GasFastestStep, 1},
   139  	CALLDATALOAD: {1, GasFastestStep, 1},
   140  	CALLDATACOPY: {3, GasFastestStep, 1},
   141  	MLOAD:        {1, GasFastestStep, 1},
   142  	MSTORE:       {2, GasFastestStep, 0},
   143  	MSTORE8:      {2, GasFastestStep, 0},
   144  	CODECOPY:     {3, GasFastestStep, 0},
   145  	MUL:          {2, GasFastStep, 1},
   146  	DIV:          {2, GasFastStep, 1},
   147  	SDIV:         {2, GasFastStep, 1},
   148  	MOD:          {2, GasFastStep, 1},
   149  	SMOD:         {2, GasFastStep, 1},
   150  	SIGNEXTEND:   {2, GasFastStep, 1},
   151  	ADDMOD:       {3, GasMidStep, 1},
   152  	MULMOD:       {3, GasMidStep, 1},
   153  	JUMP:         {1, GasMidStep, 0},
   154  	JUMPI:        {2, GasSlowStep, 0},
   155  	EXP:          {2, GasSlowStep, 1},
   156  	ADDRESS:      {0, GasQuickStep, 1},
   157  	ORIGIN:       {0, GasQuickStep, 1},
   158  	CALLER:       {0, GasQuickStep, 1},
   159  	CALLVALUE:    {0, GasQuickStep, 1},
   160  	CODESIZE:     {0, GasQuickStep, 1},
   161  	GASPRICE:     {0, GasQuickStep, 1},
   162  	COINBASE:     {0, GasQuickStep, 1},
   163  	TIMESTAMP:    {0, GasQuickStep, 1},
   164  	NUMBER:       {0, GasQuickStep, 1},
   165  	CALLDATASIZE: {0, GasQuickStep, 1},
   166  	DIFFICULTY:   {0, GasQuickStep, 1},
   167  	GASLIMIT:     {0, GasQuickStep, 1},
   168  	POP:          {1, GasQuickStep, 0},
   169  	PC:           {0, GasQuickStep, 1},
   170  	MSIZE:        {0, GasQuickStep, 1},
   171  	GAS:          {0, GasQuickStep, 1},
   172  	BLOCKHASH:    {1, GasExtStep, 1},
   173  	BALANCE:      {1, new(big.Int), 1},
   174  	EXTCODESIZE:  {1, new(big.Int), 1},
   175  	EXTCODECOPY:  {4, new(big.Int), 0},
   176  	SLOAD:        {1, big.NewInt(50), 1},
   177  	SSTORE:       {2, new(big.Int), 0},
   178  	SHA3:         {2, big.NewInt(30), 1},
   179  	CREATE:       {3, big.NewInt(32000), 1},
   180  	// Zero is calculated in the gasSwitch
   181  	CALL:         {7, new(big.Int), 1},
   182  	CALLCODE:     {7, new(big.Int), 1},
   183  	DELEGATECALL: {6, new(big.Int), 1},
   184  	SUICIDE:      {1, new(big.Int), 0},
   185  	JUMPDEST:     {0, big.NewInt(1), 0},
   186  	RETURN:       {2, new(big.Int), 0},
   187  	PUSH1:        {0, GasFastestStep, 1},
   188  	DUP1:         {0, new(big.Int), 1},
   189  }