Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jwasinger committed Dec 8, 2021
1 parent f475377 commit ca01d7b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 136 deletions.
120 changes: 21 additions & 99 deletions core/vm/gas_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
trieUtils "github.com/ethereum/go-ethereum/trie/utils"
)

// memoryGasCost calculates the quadratic gas for memory expansion. It does so
Expand Down Expand Up @@ -64,7 +63,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
// EXTCODECOPY (stack position 3)
// RETURNDATACOPY (stack position 2)
func memoryCopierGas(stackpos int) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
// Gas for expanding the memory
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
Expand All @@ -87,82 +86,14 @@ func memoryCopierGas(stackpos int) gasFunc {
}
}

func makeGasPush(pushCount uint) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
var constantGas uint64 = 3 // TODO don't hardcode this
statelessGas := uint64(0)

if evm.Accesses != nil {
statelessGas = touchEachChunksAndChargeGas(pc, uint64(pushCount), contract.Address().Bytes()[:], nil, nil, 0, evm.Accesses)
}

return constantGas + statelessGas, nil
}
}

func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
usedGas := uint64(0)
slot := stack.Back(0)
if evm.Accesses != nil {
index := trieUtils.GetTreeKeyCodeSize(slot.Bytes())
usedGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)
}

return usedGas, nil
}

var (
gasCallDataCopy = memoryCopierGas(2)
gasCodeCopyStateful = memoryCopierGas(2)
gasExtCodeCopyStateful = memoryCopierGas(3)
gasReturnDataCopy = memoryCopierGas(2)
gasCallDataCopy = memoryCopierGas(2)
gasCodeCopy = memoryCopierGas(2)
gasExtCodeCopy = memoryCopierGas(3)
gasReturnDataCopy = memoryCopierGas(2)
)

func gasCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
var statelessGas uint64
gasMemoryCopying, err := gasCodeCopyStateful(evm, contract, stack, mem, pc, memorySize)
if err != nil {
return 0, err
}
if evm.Accesses != nil {
var (
codeOffset = stack.Back(1)
length = stack.Back(2)
)
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = 0xffffffffffffffff
}
statelessGas = touchEachChunksAndChargeGas(uint64CodeOffset, length.Uint64(), contract.Address().Bytes()[:], nil, nil, 0, evm.Accesses)
}

return gasMemoryCopying + statelessGas, nil
}

func gasExtCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc, memorySize uint64) (uint64, error) {
gasMemoryCopying, err := gasExtCodeCopyStateful(evm, contract, stack, mem, pc, memorySize)
if err != nil {
return 0, err
}
return gasMemoryCopying, nil
}

func gasSLoad(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc, memorySize uint64) (uint64, error) {
usedGas := uint64(0)

if evm.Accesses != nil {
where := stack.Back(0)
addr := contract.Address()
index := trieUtils.GetTreeKeyStorageSlot(addr[:], where)
usedGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)
}

return usedGas, nil
}

func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
// Apply the witness access costs, err is nil
accessGas, _ := gasSLoad(evm, contract, stack, mem, pc, memorySize)
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
y, x = stack.Back(1), stack.Back(0)
current = evm.StateDB.GetState(contract.Address(), x.Bytes32())
Expand All @@ -178,15 +109,14 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint6
// 3. From a non-zero to a non-zero (CHANGE)
switch {
case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0
return params.SstoreSetGas + accessGas, nil
return params.SstoreSetGas, nil
case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
evm.StateDB.AddRefund(params.SstoreRefundGas)
return params.SstoreClearGas + accessGas, nil
return params.SstoreClearGas, nil
default: // non 0 => non 0 (or 0 => 0)
return params.SstoreResetGas + accessGas, nil
return params.SstoreResetGas, nil
}
}

// The new gas metering is based on net gas costs (EIP-1283):
//
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
Expand Down Expand Up @@ -245,7 +175,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint6
// 2.2.2. If original value equals new value (this storage slot is reset):
// 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
// 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter.
func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
// If we fail the minimum gas availability invariant, fail (0)
if contract.Gas <= params.SstoreSentryGasEIP2200 {
return 0, errors.New("not enough gas for reentrancy sentry")
Expand Down Expand Up @@ -288,7 +218,7 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, p
}

func makeGasLog(n uint64) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc, memorySize uint64) (uint64, error) {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
Expand Down Expand Up @@ -317,7 +247,7 @@ func makeGasLog(n uint64) gasFunc {
}
}

func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc, memorySize uint64) (uint64, error) {
func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
Expand All @@ -338,7 +268,7 @@ func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc, memory
// pureMemoryGascost is used by several operations, which aside from their
// static cost have a dynamic cost which is solely based on the memory
// expansion
func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize)
}

Expand All @@ -351,7 +281,7 @@ var (
gasCreate = pureMemoryGascost
)

func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
Expand All @@ -369,7 +299,7 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint
return gas, nil
}

func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)

var (
Expand All @@ -382,7 +312,7 @@ func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc
return gas, nil
}

func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)

var (
Expand All @@ -395,20 +325,12 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc ui
return gas, nil
}

func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
gas uint64
transfersValue = !stack.Back(2).IsZero()
address = common.Address(stack.Back(1).Bytes20())
)
if evm.Accesses != nil {
// Charge witness costs
for i := trieUtils.VersionLeafKey; i <= trieUtils.CodeSizeLeafKey; i++ {
index := trieUtils.GetTreeKeyAccountLeaf(address[:], byte(i))
gas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)
}
}

if evm.chainRules.IsEIP158 {
if transfersValue && evm.StateDB.Empty(address) {
gas += params.CallNewAccountGas
Expand Down Expand Up @@ -438,7 +360,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64,
return gas, nil
}

func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
memoryGas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
Expand All @@ -463,7 +385,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uin
return gas, nil
}

func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
Expand All @@ -479,7 +401,7 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc
return gas, nil
}

func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
Expand All @@ -495,7 +417,7 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc u
return gas, nil
}

func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, pc uint64, memorySize uint64) (uint64, error) {
func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var gas uint64
// EIP150 homestead gas reprice fork:
if evm.chainRules.IsEIP150 {
Expand Down
4 changes: 3 additions & 1 deletion core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,13 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
uint64CodeOffset = 0xffffffffffffffff
}

var statelessGas uint64
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64())
if interpreter.evm.TxContext.Accesses != nil {
touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract, paddedCodeCopy, uint(len(paddedCodeCopy)) - uint(nonPaddedCopyLength), interpreter.evm.Accesses)
statelessGas = touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract, paddedCodeCopy, uint(len(paddedCodeCopy)) - uint(nonPaddedCopyLength), interpreter.evm.Accesses)
}
scope.Memory.Set(memOffset.Uint64(), uint64(len(paddedCodeCopy)), paddedCodeCopy)
scope.Contract.UseGas(statelessGas)
return nil, nil
}

Expand Down
Loading

0 comments on commit ca01d7b

Please sign in to comment.