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  }