mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
add costs from eip. check for modOffset + modSize overflow in setupx gas cost calculation
This commit is contained in:
parent
ce284116bc
commit
08bd16adff
3 changed files with 37 additions and 28 deletions
|
|
@ -19,6 +19,7 @@ package vm
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
|
@ -540,28 +541,40 @@ func gasEOFCreate(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPowerOfTwo(val *big.Int) bool {
|
||||||
|
if val.Bit(val.BitLen()-1) == 1 && new(big.Int).SetBit(val, val.BitLen()-1, 0).Cmp(big.NewInt(0)) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func gasSetupx(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
func gasSetupx(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
||||||
if !scope.Stack.Back(0).IsUint64() || !scope.Stack.Back(2).IsUint64() || !scope.Stack.Back(3).IsUint64() {
|
if !scope.Stack.Back(0).IsUint64() || !scope.Stack.Back(2).IsUint64() || !scope.Stack.Back(3).IsUint64() {
|
||||||
return 0, errors.New("one or more parameters overflows 64 bits")
|
return 0, errors.New("one or more parameters overflows 64 bits")
|
||||||
}
|
}
|
||||||
|
|
||||||
modId := uint(scope.Stack.Back(0).Uint64())
|
modId := uint(scope.Stack.Back(0).Uint64())
|
||||||
|
|
||||||
if scope.modExtState.alloced[modId] != nil {
|
if scope.modExtState.alloced[modId] != nil {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modOffset := scope.Stack.Back(1).Uint64()
|
||||||
modSize := scope.Stack.Back(2).Uint64()
|
modSize := scope.Stack.Back(2).Uint64()
|
||||||
if modSize > 96 {
|
if modSize > 96 {
|
||||||
// TODO: ensure returning error here consumes all evm call context gas
|
|
||||||
return 0, fmt.Errorf("modulus cannot exceed 768 bits in width")
|
return 0, fmt.Errorf("modulus cannot exceed 768 bits in width")
|
||||||
}
|
}
|
||||||
|
_, overflow := math.SafeAdd(modOffset, modSize)
|
||||||
|
if overflow {
|
||||||
|
return 0, fmt.Errorf("modulus offset + size overflows uint64.")
|
||||||
|
}
|
||||||
|
|
||||||
feAllocCount := scope.Stack.Back(3).Uint64()
|
feAllocCount := scope.Stack.Back(3).Uint64()
|
||||||
if feAllocCount > 256 {
|
if feAllocCount > 256 {
|
||||||
return 0, fmt.Errorf("cannot allocate more than 256 field elements per modulus id")
|
return 0, fmt.Errorf("cannot allocate more than 256 field elements per modulus id")
|
||||||
}
|
}
|
||||||
paddedModSize := (modSize + 7) / 8
|
paddedModSize := (modSize + 7) / 8
|
||||||
precompCost := uint64(params.SetupxPrecompCost[paddedModSize])
|
precompCost := params.SetmodxOddModulusCost[paddedModSize]
|
||||||
|
|
||||||
// the size in bytes of the field element heap that this call to SETUPX is
|
// the size in bytes of the field element heap that this call to SETUPX is
|
||||||
// allocating.
|
// allocating.
|
||||||
|
|
@ -576,8 +589,12 @@ func gasSetupx(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uin
|
||||||
// and the maximum call-context allocatable memory + reasonable evm memory limit
|
// and the maximum call-context allocatable memory + reasonable evm memory limit
|
||||||
// will not overflow a uint64.
|
// will not overflow a uint64.
|
||||||
memCost, _ := evmmaxMemoryGasCost(pc, scope, memorySize, allocSize)
|
memCost, _ := evmmaxMemoryGasCost(pc, scope, memorySize, allocSize)
|
||||||
|
modBytes := scope.Memory.GetPtr(modOffset, modSize)
|
||||||
|
if !isPowerOfTwo(new(big.Int).SetBytes(modBytes)) {
|
||||||
return precompCost + memCost, nil
|
return precompCost + memCost, nil
|
||||||
}
|
}
|
||||||
|
return memCost, nil
|
||||||
|
}
|
||||||
|
|
||||||
func gasStorex(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
func gasStorex(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
||||||
if scope.modExtState.active == nil {
|
if scope.modExtState.active == nil {
|
||||||
|
|
@ -642,24 +659,16 @@ func gasLoadx(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasEVMMAXArithOp(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
func makeEVMMAXArithGasFunc(opCosts []uint64) gasFunc {
|
||||||
|
return func(pc uint64, evm *EVM, scope *ScopeContext, memorySize uint64) (uint64, error) {
|
||||||
if scope.modExtState.active == nil {
|
if scope.modExtState.active == nil {
|
||||||
return 0, errors.New("no active mod state")
|
return 0, errors.New("no active field context")
|
||||||
}
|
}
|
||||||
_ = scope.Contract.Code[pc+7]
|
out, outStride, x, xStride, y, yStride, count := extractEVMMAXImmediateInputs(pc, scope.Contract.Code)
|
||||||
out := uint(scope.Contract.Code[pc+1])
|
maxOffset := max(x+xStride*count, y+yStride*count, out+outStride*count)
|
||||||
out_stride := uint(scope.Contract.Code[pc+2])
|
if count == 0 || outStride == 0 || maxOffset > scope.modExtState.active.NumElems() {
|
||||||
x := uint(scope.Contract.Code[pc+3])
|
|
||||||
x_stride := uint(scope.Contract.Code[pc+4])
|
|
||||||
y := uint(scope.Contract.Code[pc+5])
|
|
||||||
y_stride := uint(scope.Contract.Code[pc+6])
|
|
||||||
count := uint(scope.Contract.Code[pc+7])
|
|
||||||
|
|
||||||
maxOffset := max(x+x_stride*count, y+y_stride*count, out+out_stride*count)
|
|
||||||
// TODO: might not need to assert count == 0 ?
|
|
||||||
if count == 0 || out_stride == 0 || maxOffset > scope.modExtState.active.NumElems() {
|
|
||||||
return 0, errors.New("bad parameters")
|
return 0, errors.New("bad parameters")
|
||||||
}
|
}
|
||||||
// TODO: fill in gas costs with table lookup multiplied by count...
|
return uint64(count) * opCosts[len(scope.modExtState.active.Modulus)-1], nil
|
||||||
return 1, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,19 +126,19 @@ func newEVMMAXInstructionSet() JumpTable {
|
||||||
}
|
}
|
||||||
instructionSet[ADDMODX] = &operation{
|
instructionSet[ADDMODX] = &operation{
|
||||||
execute: opAddmodx,
|
execute: opAddmodx,
|
||||||
dynamicGas: gasEVMMAXArithOp,
|
dynamicGas: makeEVMMAXArithGasFunc(params.AddOrSubCost),
|
||||||
minStack: minStack(0, 0),
|
minStack: minStack(0, 0),
|
||||||
maxStack: maxStack(0, 0),
|
maxStack: maxStack(0, 0),
|
||||||
}
|
}
|
||||||
instructionSet[SUBMODX] = &operation{
|
instructionSet[SUBMODX] = &operation{
|
||||||
execute: opSubmodx,
|
execute: opSubmodx,
|
||||||
dynamicGas: gasEVMMAXArithOp,
|
dynamicGas: makeEVMMAXArithGasFunc(params.AddOrSubCost),
|
||||||
minStack: minStack(0, 0),
|
minStack: minStack(0, 0),
|
||||||
maxStack: maxStack(0, 0),
|
maxStack: maxStack(0, 0),
|
||||||
}
|
}
|
||||||
instructionSet[MULMODX] = &operation{
|
instructionSet[MULMODX] = &operation{
|
||||||
execute: opMulmodx,
|
execute: opMulmodx,
|
||||||
dynamicGas: gasEVMMAXArithOp,
|
dynamicGas: makeEVMMAXArithGasFunc(params.MulmodxCost),
|
||||||
minStack: minStack(0, 0),
|
minStack: minStack(0, 0),
|
||||||
maxStack: maxStack(0, 0),
|
maxStack: maxStack(0, 0),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -213,11 +213,11 @@ var (
|
||||||
|
|
||||||
// EVMMAX constants
|
// EVMMAX constants
|
||||||
var (
|
var (
|
||||||
SetupxPrecompCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
SetmodxOddModulusCost = []uint64{23, 26, 29, 32, 36, 39, 42, 45, 48, 51, 54, 58}
|
||||||
// mulmodx cost lookup table
|
// mulmodx cost lookup table
|
||||||
MulmodxCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
MulmodxCost = []uint64{1, 1, 1, 2, 2, 3, 4, 5, 7, 8, 10, 12}
|
||||||
// addmodx/submodx cost lookup table
|
// addmodx/submodx cost lookup table
|
||||||
AddOrSubCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
AddOrSubCost = []uint64{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2}
|
||||||
// the maximum size (in bytes) that can be allocated by all field contexts
|
// the maximum size (in bytes) that can be allocated by all field contexts
|
||||||
// per EVM call frame
|
// per EVM call frame
|
||||||
MaxFEAllocSize = 96 * 256
|
MaxFEAllocSize = 96 * 256
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue