diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2017-02-08 20:39:26 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2017-02-13 22:15:12 +0800 |
commit | 57f4e9025757254536a738bb4771712038f1e763 (patch) | |
tree | 5d2f140139f3763a7da3c20a88acff96b58ec8ad /core/vm/gas_table.go | |
parent | f8f428cc18c5f70814d7b3937128781bac14bffd (diff) | |
download | go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar.gz go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar.bz2 go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar.lz go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar.xz go-tangerine-57f4e9025757254536a738bb4771712038f1e763.tar.zst go-tangerine-57f4e9025757254536a738bb4771712038f1e763.zip |
Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
This reverts commit 8b57c494908637a5c0e74f8f7a13b3218e026757.
Diffstat (limited to 'core/vm/gas_table.go')
-rw-r--r-- | core/vm/gas_table.go | 418 |
1 files changed, 124 insertions, 294 deletions
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index fba1eb066..4d2c4e94a 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -1,80 +1,56 @@ package vm import ( - gmath "math" "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" ) -// memoryGasCosts calculates the quadratic gas for memory expansion. It does so -// only for the memory region that is expanded, not the total memory. -func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { - // The maximum that will fit in a uint64 is max_word_count - 1 - // anything above that will result in an overflow. - if newMemSize > gmath.MaxUint64-32 { - return 0, errGasUintOverflow - } - - if newMemSize == 0 { - return 0, nil - } - - newMemSizeWords := toWordSize(newMemSize) - newMemSize = newMemSizeWords * 32 - - if newMemSize > uint64(mem.Len()) { - square := newMemSizeWords * newMemSizeWords - linCoef := newMemSizeWords * params.MemoryGas - quadCoef := square / params.QuadCoeffDiv - newTotalFee := linCoef + quadCoef - - fee := newTotalFee - mem.lastGasCost - mem.lastGasCost = newTotalFee - - return fee, nil +func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int { + gas := new(big.Int) + if newMemSize.Cmp(common.Big0) > 0 { + newMemSizeWords := toWordSize(newMemSize) + + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { + // be careful reusing variables here when changing. + // The order has been optimised to reduce allocation + oldSize := toWordSize(big.NewInt(int64(mem.Len()))) + pow := new(big.Int).Exp(oldSize, common.Big2, Zero) + linCoef := oldSize.Mul(oldSize, params.MemoryGas) + quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv) + oldTotalFee := new(big.Int).Add(linCoef, quadCoef) + + pow.Exp(newMemSizeWords, common.Big2, Zero) + linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas) + quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv) + newTotalFee := linCoef.Add(linCoef, quadCoef) + + fee := newTotalFee.Sub(newTotalFee, oldTotalFee) + gas.Add(gas, fee) + } } - return 0, nil + return gas } -func constGasFunc(gas uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gas, nil +func constGasFunc(gas *big.Int) gasFunc { + return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gas } } -func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } +func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, GasFastestStep) + words := toWordSize(stack.Back(2)) - words, overflow := bigUint64(stack.Back(2)) - if overflow { - return 0, errGasUintOverflow - } - - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { - return 0, errGasUintOverflow - } - - if gas, overflow = math.SafeAdd(gas, words); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, words.Mul(words, params.CopyGas)) } -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { var ( y, x = stack.Back(1), stack.Back(0) - val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) + val = env.StateDB.GetState(contract.Address(), common.BigToHash(x)) ) // This checks for 3 scenario's and calculates gas accordingly // 1. From a zero-value address to a non-zero value (NEW VALUE) @@ -82,335 +58,189 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m // 3. From a non-zero to a non-zero (CHANGE) if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { // 0 => non 0 - return params.SstoreSetGas, nil + return new(big.Int).Set(params.SstoreSetGas) } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { - evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas)) + env.StateDB.AddRefund(params.SstoreRefundGas) - return params.SstoreClearGas, nil + return new(big.Int).Set(params.SstoreClearGas) } else { // non 0 => non 0 (or 0 => 0) - return params.SstoreResetGas, nil + return new(big.Int).Set(params.SstoreResetGas) } } -func makeGasLog(n uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - requestedSize, overflow := bigUint64(stack.Back(1)) - if overflow { - return 0, errGasUintOverflow - } +func makeGasLog(n uint) gasFunc { + return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + mSize := stack.Back(1) - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { - return 0, errGasUintOverflow - } - - var memorySizeGas uint64 - if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil + gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas) + gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas)) + gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) + return gas } } -func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow { - return 0, errGasUintOverflow - } - - wordGas, overflow := bigUint64(stack.Back(1)) - if overflow { - return 0, errGasUintOverflow - } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, params.Sha3Gas) + words := toWordSize(stack.Back(1)) + return gas.Add(gas, words.Mul(words, params.Sha3WordGas)) } -func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } +func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, GasFastestStep) + words := toWordSize(stack.Back(2)) - wordGas, overflow := bigUint64(stack.Back(2)) - if overflow { - return 0, errGasUintOverflow - } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, words.Mul(words, params.CopyGas)) } -func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow { - return 0, errGasUintOverflow - } - - wordGas, overflow := bigUint64(stack.Back(3)) - if overflow { - return 0, errGasUintOverflow - } - - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { - return 0, errGasUintOverflow - } +func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, gt.ExtcodeCopy) + words := toWordSize(stack.Back(3)) - if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, words.Mul(words, params.CopyGas)) } -func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) } -func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) } -func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) } -func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize)) } -func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.Balance, nil +func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.Balance } -func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.ExtcodeSize, nil +func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.ExtcodeSize } -func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.SLoad, nil +func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.SLoad } -func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) - - var ( - gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas - overflow bool - ) - if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil +func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8) + gas := big.NewInt(expByteLen) + gas.Mul(gas, gt.ExpByte) + return gas.Add(gas, GasSlowStep) } -func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Set(gt.Calls) + + transfersValue := stack.Back(2).BitLen() > 0 var ( - gas = gt.Calls - transfersValue = stack.Back(2).BitLen() > 0 - address = common.BigToAddress(stack.Back(1)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) + address = common.BigToAddress(stack.Back(1)) + eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) ) if eip158 { - if evm.StateDB.Empty(address) && transfersValue { - gas += params.CallNewAccountGas + if env.StateDB.Empty(address) && transfersValue { + gas.Add(gas, params.CallNewAccountGas) } - } else if !evm.StateDB.Exist(address) { - gas += params.CallNewAccountGas + } else if !env.StateDB.Exist(address) { + gas.Add(gas, params.CallNewAccountGas) } if transfersValue { - gas += params.CallValueTransferGas - } - memoryGas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - var overflow bool - if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { - return 0, errGasUintOverflow + gas.Add(gas, params.CallValueTransferGas) } + gas.Add(gas, memoryGasCost(mem, memorySize)) - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) - if err != nil { - return 0, err - } + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) // Replace the stack item with the new gas calculation. This means that // either the original item is left on the stack or the item is replaced by: // (availableGas - gas) * 63 / 64 // We replace the stack item so that it's available when the opCall instruction is // called. This information is otherwise lost due to the dependency on *current* // available gas. - stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + stack.data[stack.len()-1] = cg - if gas, overflow = math.SafeAdd(gas, cg); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, cg) } -func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas := gt.Calls +func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Set(gt.Calls) if stack.Back(2).BitLen() > 0 { - gas += params.CallValueTransferGas - } - memoryGas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - var overflow bool - if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { - return 0, errGasUintOverflow + gas.Add(gas, params.CallValueTransferGas) } + gas.Add(gas, memoryGasCost(mem, memorySize)) - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) - if err != nil { - return 0, err - } + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) // Replace the stack item with the new gas calculation. This means that // either the original item is left on the stack or the item is replaced by: // (availableGas - gas) * 63 / 64 // We replace the stack item so that it's available when the opCall instruction is // called. This information is otherwise lost due to the dependency on *current* // available gas. - stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + stack.data[stack.len()-1] = cg - if gas, overflow = math.SafeAdd(gas, cg); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, cg) } -func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { return memoryGasCost(mem, memorySize) } -func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var gas uint64 +func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int) // EIP150 homestead gas reprice fork: - if evm.ChainConfig().IsEIP150(evm.BlockNumber) { - gas = gt.Suicide + if env.ChainConfig().IsEIP150(env.BlockNumber) { + gas.Set(gt.Suicide) var ( address = common.BigToAddress(stack.Back(0)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) + eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) ) if eip158 { // if empty and transfers value - if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).BitLen() > 0 { - gas += gt.CreateBySuicide + if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 { + gas.Add(gas, gt.CreateBySuicide) } - } else if !evm.StateDB.Exist(address) { - gas += gt.CreateBySuicide + } else if !env.StateDB.Exist(address) { + gas.Add(gas, gt.CreateBySuicide) } } - if !evm.StateDB.HasSuicided(contract.Address()) { - evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas)) + if !env.StateDB.HasSuicided(contract.Address()) { + env.StateDB.AddRefund(params.SuicideRefundGas) } - return gas, nil + return gas } -func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - var overflow bool - if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { - return 0, errGasUintOverflow - } +func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize)) - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) - if err != nil { - return 0, err - } + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) // Replace the stack item with the new gas calculation. This means that // either the original item is left on the stack or the item is replaced by: // (availableGas - gas) * 63 / 64 // We replace the stack item so that it's available when the opCall instruction is // called. - stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + stack.data[stack.len()-1] = cg - if gas, overflow = math.SafeAdd(gas, cg); overflow { - return 0, errGasUintOverflow - } - return gas, nil + return gas.Add(gas, cg) } -func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil +func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep } -func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil +func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep } -func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil +func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep } |