Skip to content

Commit

Permalink
fix: value transfer gas charge before 1/64th + warm costs for precomp…
Browse files Browse the repository at this point in the history
… + system contracts

Signed-off-by: Guillaume Ballet <[email protected]>
  • Loading branch information
gballet committed Oct 22, 2024
1 parent bcc8795 commit f855ec5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 25 deletions.
11 changes: 7 additions & 4 deletions core/state/access_witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,15 @@ func (aw *AccessWitness) TouchAndChargeMessageCall(addr []byte, availableGas uin
}

func (aw *AccessWitness) TouchAndChargeValueTransfer(callerAddr, targetAddr []byte, availableGas uint64) uint64 {
chargedGas1, _ := aw.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, availableGas)
chargedGas2, _ := aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, availableGas-chargedGas1)
if chargedGas1+chargedGas2 == 0 {
_, wanted1 := aw.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, availableGas)
if wanted1 > availableGas {
return wanted1
}
_, wanted2 := aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, availableGas-wanted1)
if wanted1+wanted2 == 0 {
return params.WarmStorageReadCostEIP2929
}
return chargedGas1 + chargedGas2
return wanted1 + wanted2
}

// TouchAndChargeContractCreateCheck charges access costs before
Expand Down
11 changes: 0 additions & 11 deletions core/vm/gas_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,17 +403,6 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
return 0, ErrGasUintOverflow
}

if evm.chainRules.IsEIP4762 {
// If value is transferred, it is charged before 1/64th
// is subtracted from the available gas pool.
if transfersValue {
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeValueTransfer(contract.Address().Bytes()[:], address.Bytes()[:], contract.Gas-gas))
if overflow {
return 0, ErrGasUintOverflow
}
}
}

evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
Expand Down
39 changes: 29 additions & 10 deletions core/vm/operations_verkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,48 @@ func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,

func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
target := common.Address(stack.Back(1).Bytes20())

_, isPrecompile := evm.precompile(target)
isSystemContract := evm.isSystemContract(target)
if isPrecompile || isSystemContract {
return params.WarmStorageReadCostEIP2929, nil
var (
target = common.Address(stack.Back(1).Bytes20())
transfersValue = !stack.Back(2).IsZero()
witnessGas uint64
_, isPrecompile = evm.precompile(target)
isSystemContract = evm.isSystemContract(target)
)

// If value is transferred, it is charged before 1/64th
// is subtracted from the available gas pool.
if transfersValue {
wantedValueTransferWitnessGas := evm.Accesses.TouchAndChargeValueTransfer(contract.Address().Bytes()[:], target[:], contract.Gas)
if wantedValueTransferWitnessGas > contract.Gas {
return wantedValueTransferWitnessGas, nil
}
witnessGas = wantedValueTransferWitnessGas
} else if isPrecompile || isSystemContract {
witnessGas = params.WarmStorageReadCostEIP2929
}

// The charging for the value transfer is done BEFORE subtracting
// the 1/64th gas, as this is considered part of the CALL instruction.
// (so before we get to this point)
// But the message call is part of the subcall, for which only 63/64th
// of the gas should be available.
wantedWitnessGas := evm.Accesses.TouchAndChargeMessageCall(target.Bytes(), contract.Gas)
if wantedWitnessGas > contract.Gas {
return wantedWitnessGas, nil
wantedMessageCallWitnessGas := evm.Accesses.TouchAndChargeMessageCall(target.Bytes(), contract.Gas-witnessGas)
var overflow bool
if witnessGas, overflow = math.SafeAdd(witnessGas, wantedMessageCallWitnessGas); overflow {
return 0, ErrGasUintOverflow
}
if witnessGas > contract.Gas {
return witnessGas, nil
}

gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
if err != nil {
return 0, err
}
return wantedWitnessGas + gas, nil
if gas, overflow = math.SafeAdd(gas, witnessGas); overflow {
return 0, ErrGasUintOverflow
}
return gas, nil
}
}

Expand Down

0 comments on commit f855ec5

Please sign in to comment.