github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/core/vm/gas_table.go (about) 1 package vm 2 3 import ( 4 "math/big" 5 6 "github.com/ethereum/go-ethereum/common" 7 "github.com/ethereum/go-ethereum/params" 8 ) 9 10 func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int { 11 gas := new(big.Int) 12 if newMemSize.Cmp(common.Big0) > 0 { 13 newMemSizeWords := toWordSize(newMemSize) 14 15 if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { 16 // be careful reusing variables here when changing. 17 // The order has been optimised to reduce allocation 18 oldSize := toWordSize(big.NewInt(int64(mem.Len()))) 19 pow := new(big.Int).Exp(oldSize, common.Big2, Zero) 20 linCoef := oldSize.Mul(oldSize, params.MemoryGas) 21 quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv) 22 oldTotalFee := new(big.Int).Add(linCoef, quadCoef) 23 24 pow.Exp(newMemSizeWords, common.Big2, Zero) 25 linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas) 26 quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv) 27 newTotalFee := linCoef.Add(linCoef, quadCoef) 28 29 fee := newTotalFee.Sub(newTotalFee, oldTotalFee) 30 gas.Add(gas, fee) 31 } 32 } 33 return gas 34 } 35 36 func constGasFunc(gas *big.Int) gasFunc { 37 return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 38 return gas 39 } 40 } 41 42 func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 43 gas := memoryGasCost(mem, memorySize) 44 gas.Add(gas, GasFastestStep) 45 words := toWordSize(stack.Back(2)) 46 47 return gas.Add(gas, words.Mul(words, params.CopyGas)) 48 } 49 50 func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 51 var ( 52 y, x = stack.Back(1), stack.Back(0) 53 val = env.StateDB.GetState(contract.Address(), common.BigToHash(x)) 54 ) 55 // This checks for 3 scenario's and calculates gas accordingly 56 // 1. From a zero-value address to a non-zero value (NEW VALUE) 57 // 2. From a non-zero value address to a zero-value address (DELETE) 58 // 3. From a non-zero to a non-zero (CHANGE) 59 if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { 60 // 0 => non 0 61 return new(big.Int).Set(params.SstoreSetGas) 62 } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { 63 env.StateDB.AddRefund(params.SstoreRefundGas) 64 65 return new(big.Int).Set(params.SstoreClearGas) 66 } else { 67 // non 0 => non 0 (or 0 => 0) 68 return new(big.Int).Set(params.SstoreResetGas) 69 } 70 } 71 72 func makeGasLog(n uint) gasFunc { 73 return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 74 mSize := stack.Back(1) 75 76 gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas) 77 gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas)) 78 gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) 79 return gas 80 } 81 } 82 83 func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 84 gas := memoryGasCost(mem, memorySize) 85 gas.Add(gas, params.Sha3Gas) 86 words := toWordSize(stack.Back(1)) 87 return gas.Add(gas, words.Mul(words, params.Sha3WordGas)) 88 } 89 90 func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 91 gas := memoryGasCost(mem, memorySize) 92 gas.Add(gas, GasFastestStep) 93 words := toWordSize(stack.Back(2)) 94 95 return gas.Add(gas, words.Mul(words, params.CopyGas)) 96 } 97 98 func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 99 gas := memoryGasCost(mem, memorySize) 100 gas.Add(gas, gt.ExtcodeCopy) 101 words := toWordSize(stack.Back(3)) 102 103 return gas.Add(gas, words.Mul(words, params.CopyGas)) 104 } 105 106 func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 107 return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) 108 } 109 110 func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 111 return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) 112 } 113 114 func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 115 return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) 116 } 117 118 func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 119 return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize)) 120 } 121 122 func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 123 return gt.Balance 124 } 125 126 func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 127 return gt.ExtcodeSize 128 } 129 130 func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 131 return gt.SLoad 132 } 133 134 func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 135 expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8) 136 gas := big.NewInt(expByteLen) 137 gas.Mul(gas, gt.ExpByte) 138 return gas.Add(gas, GasSlowStep) 139 } 140 141 func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 142 gas := new(big.Int).Set(gt.Calls) 143 144 transfersValue := stack.Back(2).BitLen() > 0 145 var ( 146 address = common.BigToAddress(stack.Back(1)) 147 eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) 148 ) 149 if eip158 { 150 if env.StateDB.Empty(address) && transfersValue { 151 gas.Add(gas, params.CallNewAccountGas) 152 } 153 } else if !env.StateDB.Exist(address) { 154 gas.Add(gas, params.CallNewAccountGas) 155 } 156 if transfersValue { 157 gas.Add(gas, params.CallValueTransferGas) 158 } 159 gas.Add(gas, memoryGasCost(mem, memorySize)) 160 161 cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) 162 // Replace the stack item with the new gas calculation. This means that 163 // either the original item is left on the stack or the item is replaced by: 164 // (availableGas - gas) * 63 / 64 165 // We replace the stack item so that it's available when the opCall instruction is 166 // called. This information is otherwise lost due to the dependency on *current* 167 // available gas. 168 stack.data[stack.len()-1] = cg 169 170 return gas.Add(gas, cg) 171 } 172 173 func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 174 gas := new(big.Int).Set(gt.Calls) 175 if stack.Back(2).BitLen() > 0 { 176 gas.Add(gas, params.CallValueTransferGas) 177 } 178 gas.Add(gas, memoryGasCost(mem, memorySize)) 179 180 cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) 181 // Replace the stack item with the new gas calculation. This means that 182 // either the original item is left on the stack or the item is replaced by: 183 // (availableGas - gas) * 63 / 64 184 // We replace the stack item so that it's available when the opCall instruction is 185 // called. This information is otherwise lost due to the dependency on *current* 186 // available gas. 187 stack.data[stack.len()-1] = cg 188 189 return gas.Add(gas, cg) 190 } 191 192 func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 193 return memoryGasCost(mem, memorySize) 194 } 195 196 func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 197 gas := new(big.Int) 198 // EIP150 homestead gas reprice fork: 199 if env.ChainConfig().IsEIP150(env.BlockNumber) { 200 gas.Set(gt.Suicide) 201 var ( 202 address = common.BigToAddress(stack.Back(0)) 203 eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) 204 ) 205 206 if eip158 { 207 // if empty and transfers value 208 if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 { 209 gas.Add(gas, gt.CreateBySuicide) 210 } 211 } else if !env.StateDB.Exist(address) { 212 gas.Add(gas, gt.CreateBySuicide) 213 } 214 } 215 216 if !env.StateDB.HasSuicided(contract.Address()) { 217 env.StateDB.AddRefund(params.SuicideRefundGas) 218 } 219 return gas 220 } 221 222 func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 223 gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize)) 224 225 cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) 226 // Replace the stack item with the new gas calculation. This means that 227 // either the original item is left on the stack or the item is replaced by: 228 // (availableGas - gas) * 63 / 64 229 // We replace the stack item so that it's available when the opCall instruction is 230 // called. 231 stack.data[stack.len()-1] = cg 232 233 return gas.Add(gas, cg) 234 } 235 236 func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 237 return GasFastestStep 238 } 239 240 func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 241 return GasFastestStep 242 } 243 244 func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { 245 return GasFastestStep 246 }