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 }