gas_table.go 8.9 KB

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