github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/core/vm/gas_table.go (about) 1 // Copyright 2017 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "github.com/SmartMeshFoundation/Spectrum/common" 21 "github.com/SmartMeshFoundation/Spectrum/common/math" 22 "github.com/SmartMeshFoundation/Spectrum/params" 23 ) 24 25 // memoryGasCost calculates the quadratic gas for memory expansion. It does so 26 // only for the memory region that is expanded, not the total memory. 27 func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { 28 if newMemSize == 0 { 29 return 0, nil 30 } 31 // The maximum that will fit in a uint64 is max_word_count - 1. Anything above 32 // that will result in an overflow. Additionally, a newMemSize which results in 33 // a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to 34 // overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used 35 // without overflowing the gas calculation. 36 if newMemSize > 0x1FFFFFFFE0 { 37 return 0, ErrGasUintOverflow 38 } 39 newMemSizeWords := toWordSize(newMemSize) 40 newMemSize = newMemSizeWords * 32 41 42 if newMemSize > uint64(mem.Len()) { 43 square := newMemSizeWords * newMemSizeWords 44 linCoef := newMemSizeWords * params.MemoryGas 45 quadCoef := square / params.QuadCoeffDiv 46 newTotalFee := linCoef + quadCoef 47 48 fee := newTotalFee - mem.lastGasCost 49 mem.lastGasCost = newTotalFee 50 51 return fee, nil 52 } 53 return 0, nil 54 } 55 56 // memoryCopierGas creates the gas functions for the following opcodes, and takes 57 // the stack position of the operand which determines the size of the data to copy 58 // as argument: 59 // CALLDATACOPY (stack position 2) 60 // CODECOPY (stack position 2) 61 // EXTCODECOPY (stack position 3) 62 // RETURNDATACOPY (stack position 2) 63 func memoryCopierGas(stackpos int) gasFunc { 64 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 65 // Gas for expanding the memory 66 gas, err := memoryGasCost(mem, memorySize) 67 if err != nil { 68 return 0, err 69 } 70 // And gas for copying data, charged per word at param.CopyGas 71 words, overflow := stack.Back(stackpos).Uint64WithOverflow() 72 if overflow { 73 return 0, ErrGasUintOverflow 74 } 75 76 if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { 77 return 0, ErrGasUintOverflow 78 } 79 80 if gas, overflow = math.SafeAdd(gas, words); overflow { 81 return 0, ErrGasUintOverflow 82 } 83 return gas, nil 84 } 85 } 86 87 var ( 88 gasCallDataCopy = memoryCopierGas(2) 89 gasCodeCopy = memoryCopierGas(2) 90 gasExtCodeCopy = memoryCopierGas(3) 91 gasReturnDataCopy = memoryCopierGas(2) 92 ) 93 94 func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 95 var ( 96 y, x = stack.Back(1), stack.Back(0) 97 val = evm.StateDB.GetState(contract.Address(), x.Bytes32()) 98 ) 99 // This checks for 3 scenario's and calculates gas accordingly 100 // 1. From a zero-value address to a non-zero value (NEW VALUE) 101 // 2. From a non-zero value address to a zero-value address (DELETE) 102 // 3. From a non-zero to a non-zero (CHANGE) 103 switch { 104 case val == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 105 return params.SstoreSetGas, nil 106 case val != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 107 evm.StateDB.AddRefund(params.SstoreRefundGas) 108 return params.SstoreClearGas, nil 109 default: // non 0 => non 0 (or 0 => 0) 110 return params.SstoreResetGas, nil 111 } 112 } 113 func makeGasLog(n uint64) gasFunc { 114 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 115 requestedSize, overflow := stack.Back(1).Uint64WithOverflow() 116 if overflow { 117 return 0, ErrGasUintOverflow 118 } 119 120 gas, err := memoryGasCost(mem, memorySize) 121 if err != nil { 122 return 0, err 123 } 124 125 if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { 126 return 0, ErrGasUintOverflow 127 } 128 if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { 129 return 0, ErrGasUintOverflow 130 } 131 132 var memorySizeGas uint64 133 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { 134 return 0, ErrGasUintOverflow 135 } 136 if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { 137 return 0, ErrGasUintOverflow 138 } 139 return gas, nil 140 } 141 } 142 143 func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 144 gas, err := memoryGasCost(mem, memorySize) 145 if err != nil { 146 return 0, err 147 } 148 wordGas, overflow := stack.Back(1).Uint64WithOverflow() 149 if overflow { 150 return 0, ErrGasUintOverflow 151 } 152 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 153 return 0, ErrGasUintOverflow 154 } 155 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 156 return 0, ErrGasUintOverflow 157 } 158 return gas, nil 159 } 160 161 // pureMemoryGascost is used by several operations, which aside from their 162 // static cost have a dynamic cost which is solely based on the memory 163 // expansion 164 func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 165 return memoryGasCost(mem, memorySize) 166 } 167 168 var ( 169 gasReturn = pureMemoryGascost 170 gasRevert = pureMemoryGascost 171 gasMLoad = pureMemoryGascost 172 gasMStore8 = pureMemoryGascost 173 gasMStore = pureMemoryGascost 174 gasCreate = pureMemoryGascost 175 ) 176 177 func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 178 gas, err := memoryGasCost(mem, memorySize) 179 if err != nil { 180 return 0, err 181 } 182 wordGas, overflow := stack.Back(2).Uint64WithOverflow() 183 if overflow { 184 return 0, ErrGasUintOverflow 185 } 186 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 187 return 0, ErrGasUintOverflow 188 } 189 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 190 return 0, ErrGasUintOverflow 191 } 192 return gas, nil 193 } 194 195 func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 196 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 197 198 var ( 199 gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas 200 overflow bool 201 ) 202 if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { 203 return 0, ErrGasUintOverflow 204 } 205 return gas, nil 206 } 207 208 func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 209 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 210 211 var ( 212 gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas 213 overflow bool 214 ) 215 if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { 216 return 0, ErrGasUintOverflow 217 } 218 return gas, nil 219 } 220 221 func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 222 var ( 223 gas uint64 224 transfersValue = !stack.Back(2).IsZero() 225 address = common.Address(stack.Back(1).Bytes20()) 226 ) 227 if evm.chainRules.IsEIP158 { 228 if transfersValue && evm.StateDB.Empty(address) { 229 gas += params.CallNewAccountGas 230 } 231 } else if !evm.StateDB.Exist(address) { 232 gas += params.CallNewAccountGas 233 } 234 if transfersValue { 235 gas += params.CallValueTransferGas 236 } 237 memoryGas, err := memoryGasCost(mem, memorySize) 238 if err != nil { 239 return 0, err 240 } 241 var overflow bool 242 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 243 return 0, ErrGasUintOverflow 244 } 245 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 246 if err != nil { 247 return 0, err 248 } 249 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 250 return 0, ErrGasUintOverflow 251 } 252 return gas, nil 253 } 254 255 func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 256 memoryGas, err := memoryGasCost(mem, memorySize) 257 if err != nil { 258 return 0, err 259 } 260 var ( 261 gas uint64 262 overflow bool 263 ) 264 if stack.Back(2).Sign() != 0 { 265 gas += params.CallValueTransferGas 266 } 267 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 268 return 0, ErrGasUintOverflow 269 } 270 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 271 if err != nil { 272 return 0, err 273 } 274 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 275 return 0, ErrGasUintOverflow 276 } 277 return gas, nil 278 } 279 280 func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 281 gas, err := memoryGasCost(mem, memorySize) 282 if err != nil { 283 return 0, err 284 } 285 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 286 if err != nil { 287 return 0, err 288 } 289 var overflow bool 290 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 291 return 0, ErrGasUintOverflow 292 } 293 return gas, nil 294 } 295 296 func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 297 gas, err := memoryGasCost(mem, memorySize) 298 if err != nil { 299 return 0, err 300 } 301 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 302 if err != nil { 303 return 0, err 304 } 305 var overflow bool 306 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 307 return 0, ErrGasUintOverflow 308 } 309 return gas, nil 310 } 311 312 func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 313 var gas uint64 314 // EIP150 homestead gas reprice fork: 315 if evm.chainRules.IsEIP150 { 316 gas = params.SelfdestructGasEIP150 317 var address = common.Address(stack.Back(0).Bytes20()) 318 319 if evm.chainRules.IsEIP158 { 320 // if empty and transfers value 321 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 322 gas += params.CreateBySelfdestructGas 323 } 324 } else if !evm.StateDB.Exist(address) { 325 gas += params.CreateBySelfdestructGas 326 } 327 } 328 329 if !evm.StateDB.HasSuicided(contract.Address()) { 330 evm.StateDB.AddRefund(params.SelfdestructRefundGas) 331 } 332 return gas, nil 333 }