mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
evmmax (placeholder commit message)
This commit is contained in:
parent
05148d972c
commit
e19b42b78b
12 changed files with 434 additions and 103 deletions
|
|
@ -25,12 +25,19 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
|
func memoryGasCost(pc uint64, scope *ScopeContext, mem *Memory, newMemSize uint64) (uint64, error) {
|
||||||
// only for the memory region that is expanded, not the total memory.
|
return evmmaxMemoryGasCost(pc, scope, mem, newMemSize, scope.modExtState.AllocSize())
|
||||||
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
}
|
||||||
if newMemSize == 0 {
|
|
||||||
|
// evmmaxMemory calculates the quadratic gas for memory expansion. It does so
|
||||||
|
// only for the memory region that is expanded, not the total memory. It uses
|
||||||
|
// the modified EVMMAX memory expansion rule: consider the size of memory to
|
||||||
|
// include EVM memory and the memory allocated by all active field contexts.
|
||||||
|
func evmmaxMemoryGasCost(pc uint64, scope *ScopeContext, mem *Memory, newMemSize uint64, newEVMMAXMemSize uint64) (uint64, error) {
|
||||||
|
if newMemSize == 0 && newEVMMAXMemSize == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The maximum that will fit in a uint64 is max_word_count - 1. Anything above
|
// The maximum that will fit in a uint64 is max_word_count - 1. Anything above
|
||||||
// that will result in an overflow. Additionally, a newMemSize which results in
|
// that will result in an overflow. Additionally, a newMemSize which results in
|
||||||
// a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to
|
// a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to
|
||||||
|
|
@ -40,11 +47,24 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
newMemSizeWords := toWordSize(newMemSize)
|
newMemSizeWords := toWordSize(newMemSize)
|
||||||
newMemSize = newMemSizeWords * 32
|
newMemSizePadded := newMemSizeWords * 32
|
||||||
|
|
||||||
if newMemSize > uint64(mem.Len()) {
|
curEVMMAXMemSize := scope.modExtState.AllocSize()
|
||||||
square := newMemSizeWords * newMemSizeWords
|
curEVMMAXMemSizePadded := toWordSize(curEVMMAXMemSize) * 32
|
||||||
linCoef := newMemSizeWords * params.MemoryGas
|
newEVMMAXMemSizePadded := toWordSize(newEVMMAXMemSize) * 32
|
||||||
|
|
||||||
|
// if newEVMMAXMemSize + newEVMMemSize > curEVMMAXMemSize + curEVMMemSize
|
||||||
|
if newMemSizePadded > uint64(mem.Len()) || newEVMMAXMemSizePadded > curEVMMAXMemSizePadded {
|
||||||
|
// if this is called by the invocation of SETUPX, the new evm memory is
|
||||||
|
// 0, but we still need it to compute the fee
|
||||||
|
if newMemSize <= uint64(mem.Len()) {
|
||||||
|
newMemSize = uint64(mem.Len())
|
||||||
|
}
|
||||||
|
// new effective mem size for the purpose of gas charging is the sum of
|
||||||
|
// evmmax memory and evm memory padded to a multiple of 32 bytes.
|
||||||
|
newEffectiveMemSizeWords := toWordSize(newEVMMAXMemSize + newMemSize)
|
||||||
|
square := newEffectiveMemSizeWords * newEffectiveMemSizeWords
|
||||||
|
linCoef := newEffectiveMemSizeWords * params.MemoryGas
|
||||||
quadCoef := square / params.QuadCoeffDiv
|
quadCoef := square / params.QuadCoeffDiv
|
||||||
newTotalFee := linCoef + quadCoef
|
newTotalFee := linCoef + quadCoef
|
||||||
|
|
||||||
|
|
@ -65,9 +85,9 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
||||||
// EXTCODECOPY (stack position 3)
|
// EXTCODECOPY (stack position 3)
|
||||||
// RETURNDATACOPY (stack position 2)
|
// RETURNDATACOPY (stack position 2)
|
||||||
func memoryCopierGas(stackpos int) gasFunc {
|
func memoryCopierGas(stackpos int) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
// Gas for expanding the memory
|
// Gas for expanding the memory
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -96,10 +116,10 @@ var (
|
||||||
gasReturnDataCopy = memoryCopierGas(2)
|
gasReturnDataCopy = memoryCopierGas(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
current = evm.StateDB.GetState(contract.Address(), x.Bytes32())
|
current = evm.StateDB.GetState(scope.Contract.Address(), x.Bytes32())
|
||||||
)
|
)
|
||||||
// The legacy gas metering only takes into consideration the current state
|
// The legacy gas metering only takes into consideration the current state
|
||||||
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
||||||
|
|
@ -139,7 +159,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
return params.NetSstoreNoopGas, nil
|
return params.NetSstoreNoopGas, nil
|
||||||
}
|
}
|
||||||
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
|
original := evm.StateDB.GetCommittedState(scope.Contract.Address(), x.Bytes32())
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return params.NetSstoreInitGas, nil
|
return params.NetSstoreInitGas, nil
|
||||||
|
|
@ -181,22 +201,22 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||||
// (2.2.2.) If original value equals new value (this storage slot is reset):
|
// (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.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.
|
// (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, memorySize uint64) (uint64, error) {
|
func gasSStoreEIP2200(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
// If we fail the minimum gas availability invariant, fail (0)
|
// If we fail the minimum gas availability invariant, fail (0)
|
||||||
if contract.Gas <= params.SstoreSentryGasEIP2200 {
|
if scope.Contract.Gas <= params.SstoreSentryGasEIP2200 {
|
||||||
return 0, errors.New("not enough gas for reentrancy sentry")
|
return 0, errors.New("not enough gas for reentrancy sentry")
|
||||||
}
|
}
|
||||||
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
current = evm.StateDB.GetState(contract.Address(), x.Bytes32())
|
current = evm.StateDB.GetState(scope.Contract.Address(), x.Bytes32())
|
||||||
)
|
)
|
||||||
value := common.Hash(y.Bytes32())
|
value := common.Hash(y.Bytes32())
|
||||||
|
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
return params.SloadGasEIP2200, nil
|
return params.SloadGasEIP2200, nil
|
||||||
}
|
}
|
||||||
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
|
original := evm.StateDB.GetCommittedState(scope.Contract.Address(), x.Bytes32())
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return params.SstoreSetGasEIP2200, nil
|
return params.SstoreSetGasEIP2200, nil
|
||||||
|
|
@ -224,13 +244,13 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeGasLog(n uint64) gasFunc {
|
func makeGasLog(n uint64) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -253,8 +273,8 @@ func makeGasLog(n uint64) gasFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasKeccak256(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -274,8 +294,8 @@ func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
|
||||||
// pureMemoryGascost is used by several operations, which aside from their
|
// pureMemoryGascost is used by several operations, which aside from their
|
||||||
// static cost have a dynamic cost which is solely based on the memory
|
// static cost have a dynamic cost which is solely based on the memory
|
||||||
// expansion
|
// expansion
|
||||||
func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func pureMemoryGascost(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return memoryGasCost(mem, memorySize)
|
return memoryGasCost(pc, scope, mem, memorySize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -287,8 +307,8 @@ var (
|
||||||
gasCreate = pureMemoryGascost
|
gasCreate = pureMemoryGascost
|
||||||
)
|
)
|
||||||
|
|
||||||
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCreate2(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -305,8 +325,8 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCreateEip3860(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -324,8 +344,8 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCreate2Eip3860(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +364,7 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExpFrontier(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -357,7 +377,7 @@ func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExpEIP158(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -370,7 +390,7 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
gas uint64
|
gas uint64
|
||||||
transfersValue = !stack.Back(2).IsZero()
|
transfersValue = !stack.Back(2).IsZero()
|
||||||
|
|
@ -386,7 +406,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
if transfersValue && !evm.chainRules.IsEIP4762 {
|
if transfersValue && !evm.chainRules.IsEIP4762 {
|
||||||
gas += params.CallValueTransferGas
|
gas += params.CallValueTransferGas
|
||||||
}
|
}
|
||||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
memoryGas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -396,13 +416,13 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.IsEIP4762 {
|
||||||
if transfersValue {
|
if transfersValue {
|
||||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address))
|
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(scope.Contract.Address(), address))
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, scope.Contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -413,8 +433,8 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCallCode(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
memoryGas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -432,13 +452,13 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
||||||
address := common.Address(stack.Back(1).Bytes20())
|
address := common.Address(stack.Back(1).Bytes20())
|
||||||
transfersValue := !stack.Back(2).IsZero()
|
transfersValue := !stack.Back(2).IsZero()
|
||||||
if transfersValue {
|
if transfersValue {
|
||||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address))
|
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(scope.Contract.Address(), address))
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, scope.Contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -448,12 +468,12 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasDelegateCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, scope.Contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -464,12 +484,12 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasStaticCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(pc, scope, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, scope.Contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -480,7 +500,7 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSelfdestruct(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
// EIP150 homestead gas reprice fork:
|
// EIP150 homestead gas reprice fork:
|
||||||
if evm.chainRules.IsEIP150 {
|
if evm.chainRules.IsEIP150 {
|
||||||
|
|
@ -489,7 +509,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
|
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
// if empty and transfers value
|
// if empty and transfers value
|
||||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(scope.Contract.Address()).Sign() != 0 {
|
||||||
gas += params.CreateBySelfdestructGas
|
gas += params.CreateBySelfdestructGas
|
||||||
}
|
}
|
||||||
} else if !evm.StateDB.Exist(address) {
|
} else if !evm.StateDB.Exist(address) {
|
||||||
|
|
@ -497,25 +517,149 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !evm.StateDB.HasSelfDestructed(contract.Address()) {
|
if !evm.StateDB.HasSelfDestructed(scope.Contract.Address()) {
|
||||||
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
|
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExtCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExtDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtDelegateCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
func gasExtStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtStaticCall(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// gasEOFCreate returns the gas-cost for EOF-Create. Hashing charge needs to be
|
// gasEOFCreate returns the gas-cost for EOF-Create. Hashing charge needs to be
|
||||||
// deducted in the opcode itself, since it depends on the immediate
|
// deducted in the opcode itself, since it depends on the immediate
|
||||||
func gasEOFCreate(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasEOFCreate(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gasSetupx(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
if !stack.Back(0).IsUint64() || !stack.Back(2).IsUint64() || !stack.Back(3).IsUint64() {
|
||||||
|
return 0, errors.New("one or more parameters overflows 64 bits")
|
||||||
|
}
|
||||||
|
|
||||||
|
modId := uint(stack.Back(0).Uint64())
|
||||||
|
if scope.modExtState.alloced[modId] != nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
modSize := stack.Back(2).Uint64()
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
feAllocCount := stack.Back(3).Uint64()
|
||||||
|
if feAllocCount > 256 {
|
||||||
|
return 0, fmt.Errorf("cannot allocate more than 256 field elements per modulus id")
|
||||||
|
}
|
||||||
|
paddedModSize := (modSize + 7) / 8
|
||||||
|
precompCost := uint64(params.SetupxPrecompCost[paddedModSize])
|
||||||
|
|
||||||
|
// the size in bytes of the field element heap that this call to SETUPX is
|
||||||
|
// allocating.
|
||||||
|
allocSize := paddedModSize * feAllocCount
|
||||||
|
|
||||||
|
// if the new evmmax memory alloc would exceed the maximum allowed, return an error
|
||||||
|
if scope.modExtState.AllocSize()+allocSize > uint64(params.MaxFEAllocSize) {
|
||||||
|
return 0, fmt.Errorf("call context evmmax allocation threshold exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// overflow error unchecked because we do not expand evm memory here,
|
||||||
|
// and the maximum call-context allocatable memory + reasonable evm memory limit
|
||||||
|
// will not overflow a uint64.
|
||||||
|
memCost, _ := evmmaxMemoryGasCost(pc, scope, mem, memorySize, allocSize)
|
||||||
|
return precompCost + memCost, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasStorex(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
if scope.modExtState.active == nil {
|
||||||
|
return 0, errors.New("no active mod state")
|
||||||
|
}
|
||||||
|
dst := stack.Back(0)
|
||||||
|
src := stack.Back(1)
|
||||||
|
count := stack.Back(2)
|
||||||
|
|
||||||
|
if !src.IsUint64() || int(src.Uint64()) >= mem.Len() {
|
||||||
|
return 0, errors.New("source index is out of bounds")
|
||||||
|
}
|
||||||
|
if !dst.IsUint64() || dst.Uint64() >= uint64(scope.modExtState.active.NumElems()) {
|
||||||
|
return 0, errors.New("destination of copy out of bounds")
|
||||||
|
}
|
||||||
|
if !count.IsUint64() || count.Uint64() > uint64(scope.modExtState.active.NumElems()) {
|
||||||
|
return 0, errors.New("count must be less than number of field elements in the active space")
|
||||||
|
}
|
||||||
|
storeSize := count.Uint64() * uint64(scope.modExtState.active.NumElems())
|
||||||
|
if src.Uint64()+storeSize > uint64(mem.Len()) {
|
||||||
|
return 0, errors.New("source of copy out of bounds of EVM memory")
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.modExtState.active.IsModulusBinary() {
|
||||||
|
return toWordSize(storeSize) * params.CopyGas, nil
|
||||||
|
} else {
|
||||||
|
return count.Uint64() * uint64(params.MulmodxCost[int(scope.modExtState.active.ElemSize()/8)-1]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasLoadx(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
if scope.modExtState.active == nil {
|
||||||
|
return 0, errors.New("no active mod state")
|
||||||
|
}
|
||||||
|
dst := stack.Back(0)
|
||||||
|
src := stack.Back(1)
|
||||||
|
count := stack.Back(2)
|
||||||
|
|
||||||
|
if !src.IsUint64() || uint(src.Uint64()) >= scope.modExtState.active.NumElems() {
|
||||||
|
return 0, errors.New("out of bounds copy source")
|
||||||
|
}
|
||||||
|
if !count.IsUint64() || uint(count.Uint64()) > scope.modExtState.active.NumElems() {
|
||||||
|
return 0, errors.New("count must be less than number of field elements")
|
||||||
|
}
|
||||||
|
if last, overflow := math.SafeAdd(src.Uint64(), count.Uint64()); overflow || last > uint64(scope.modExtState.active.NumElems()) {
|
||||||
|
return 0, errors.New("out of bounds copy source")
|
||||||
|
}
|
||||||
|
if !dst.IsUint64() {
|
||||||
|
return 0, errors.New("out of bounds destination")
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSize := count.Uint64() * uint64(scope.modExtState.active.ElemSize())
|
||||||
|
last, overflow := math.SafeAdd(dst.Uint64(), loadSize)
|
||||||
|
if overflow || last > uint64(mem.Len()) {
|
||||||
|
return 0, errors.New("out of bounds destination")
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.modExtState.active.IsModulusBinary() {
|
||||||
|
return toWordSize(loadSize) * params.CopyGas, nil
|
||||||
|
} else {
|
||||||
|
return count.Uint64() * uint64(params.MulmodxCost[int(scope.modExtState.active.ElemSize()/8)-1]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasEVMMAXArithOp(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
if scope.modExtState.active == nil {
|
||||||
|
return 0, errors.New("no active mod state")
|
||||||
|
}
|
||||||
|
_ = scope.Contract.Code[pc+7]
|
||||||
|
out := uint(scope.Contract.Code[pc+1])
|
||||||
|
out_stride := uint(scope.Contract.Code[pc+2])
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
// TODO: fill in gas costs with table lookup multiplied by count...
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -954,6 +954,62 @@ func makeLog(size int) executionFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opSetupx(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
id, modOffset, modSize, allocSize := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.pop(), scope.Stack.pop()
|
||||||
|
modulus := scope.Memory.GetCopy(modOffset.Uint64(), modSize.Uint64())
|
||||||
|
|
||||||
|
if err := scope.modExtState.AllocAndSetActive(uint(id.Uint64()), modulus, int(allocSize.Uint64())); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opLoadx(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
dest, source, count := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.pop()
|
||||||
|
destBuf := scope.Memory.GetPtr(dest.Uint64(), count.Uint64()*uint64(scope.modExtState.active.ElemSize()))
|
||||||
|
scope.modExtState.active.Load(destBuf, int(source.Uint64()), int(count.Uint64()))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opStorex(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
dest, source, count := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.pop()
|
||||||
|
srcBuf := scope.Memory.GetPtr(source.Uint64(), count.Uint64()*uint64(scope.modExtState.active.ElemSize()))
|
||||||
|
return nil, scope.modExtState.active.Store(uint(dest.Uint64()), uint(count.Uint64()), srcBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractEVMMAXImmediateInputs(pc uint64, code []byte) (out, outStride, x, xStride, y, yStride, count uint) {
|
||||||
|
_ = code[pc+7]
|
||||||
|
out = uint(code[pc+1])
|
||||||
|
outStride = uint(code[pc+2])
|
||||||
|
x = uint(code[pc+3])
|
||||||
|
xStride = uint(code[pc+4])
|
||||||
|
y = uint(code[pc+5])
|
||||||
|
yStride = uint(code[pc+6])
|
||||||
|
count = uint(code[pc+7])
|
||||||
|
return out, outStride, x, xStride, y, yStride, count
|
||||||
|
}
|
||||||
|
|
||||||
|
func opAddmodx(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
out, outStride, x, xStride, y, yStride, count := extractEVMMAXImmediateInputs(*pc, scope.Contract.Code)
|
||||||
|
*pc += 7
|
||||||
|
scope.modExtState.active.AddMod(out, outStride, x, xStride, y, yStride, count)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSubmodx(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
out, outStride, x, xStride, y, yStride, count := extractEVMMAXImmediateInputs(*pc, scope.Contract.Code)
|
||||||
|
*pc += 7
|
||||||
|
scope.modExtState.active.SubMod(out, outStride, x, xStride, y, yStride, count)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opMulmodx(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
out, outStride, x, xStride, y, yStride, count := extractEVMMAXImmediateInputs(*pc, scope.Contract.Code)
|
||||||
|
*pc += 7
|
||||||
|
scope.modExtState.active.MulMod(out, outStride, x, xStride, y, yStride, count)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// opPush1 is a specialized version of pushN
|
// opPush1 is a specialized version of pushN
|
||||||
func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
evmmax_arith "github.com/jwasinger/evmmax-arith"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config are the configuration options for the Interpreter
|
// Config are the configuration options for the Interpreter
|
||||||
|
|
@ -40,9 +40,49 @@ type Config struct {
|
||||||
// ScopeContext contains the things that are per-call, such as stack and memory,
|
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||||
// but not transients like pc and gas
|
// but not transients like pc and gas
|
||||||
type ScopeContext struct {
|
type ScopeContext struct {
|
||||||
Memory *Memory
|
Memory *Memory
|
||||||
Stack *Stack
|
Stack *Stack
|
||||||
Contract *Contract
|
Contract *Contract
|
||||||
|
modExtState fieldAllocs
|
||||||
|
}
|
||||||
|
|
||||||
|
// fieldAllocs represents the current set of field contexts that have been
|
||||||
|
// allocated in the current EVM call frame. It keeps track of an active
|
||||||
|
// context and the total allocated size in bytes of all field elements
|
||||||
|
// in all contexts in the current EVM call frame.
|
||||||
|
type fieldAllocs struct {
|
||||||
|
alloced map[uint]*evmmax_arith.FieldContext
|
||||||
|
active *evmmax_arith.FieldContext
|
||||||
|
allocedSize uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocAndSetActive takes an id (number between 0 and 255 inclusive), a
|
||||||
|
// big-endian modulus, and the number of field elements to allocate. Each
|
||||||
|
// field element occupies memory equivalent to the size of the modulus padded
|
||||||
|
// to the nearest multiple of 8 bytes.
|
||||||
|
func (f *fieldAllocs) AllocAndSetActive(id uint, modulus []byte, allocCount int) error {
|
||||||
|
fieldContext, err := evmmax_arith.NewFieldContext(modulus, allocCount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.alloced[id] = fieldContext
|
||||||
|
f.active = fieldContext
|
||||||
|
f.allocedSize += uint64(fieldContext.AllocedSize())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocSize returns the amount of EVMMAX-allocated memory (in bytes) in the current EVM call context
|
||||||
|
func (f *fieldAllocs) AllocSize() uint64 {
|
||||||
|
return f.allocedSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetActive sets a modulus as active in the current EVM call context. The
|
||||||
|
// modulus associated with id is assumed to have already been instantiated by
|
||||||
|
// a previous call to AllocAndSetActive
|
||||||
|
func (f *fieldAllocs) SetActive(id uint) error {
|
||||||
|
fieldContext := f.alloced[id]
|
||||||
|
f.active = fieldContext
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemoryData returns the underlying memory slice. Callers must not modify the contents
|
// MemoryData returns the underlying memory slice. Callers must not modify the contents
|
||||||
|
|
@ -109,6 +149,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
|
||||||
case evm.chainRules.IsVerkle:
|
case evm.chainRules.IsVerkle:
|
||||||
// TODO replace with proper instruction set when fork is specified
|
// TODO replace with proper instruction set when fork is specified
|
||||||
table = &verkleInstructionSet
|
table = &verkleInstructionSet
|
||||||
|
case evm.chainRules.IsEVMMAX:
|
||||||
|
table = &evmmaxInstructionSet
|
||||||
case evm.chainRules.IsCancun:
|
case evm.chainRules.IsCancun:
|
||||||
table = &cancunInstructionSet
|
table = &cancunInstructionSet
|
||||||
case evm.chainRules.IsShanghai:
|
case evm.chainRules.IsShanghai:
|
||||||
|
|
@ -183,9 +225,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
mem = NewMemory() // bound memory
|
mem = NewMemory() // bound memory
|
||||||
stack = newstack() // local stack
|
stack = newstack() // local stack
|
||||||
callContext = &ScopeContext{
|
callContext = &ScopeContext{
|
||||||
Memory: mem,
|
Memory: mem,
|
||||||
Stack: stack,
|
Stack: stack,
|
||||||
Contract: contract,
|
Contract: contract,
|
||||||
|
modExtState: fieldAllocs{alloced: make(map[uint]*evmmax_arith.FieldContext)},
|
||||||
}
|
}
|
||||||
// For optimisation reason we're using uint64 as the program counter.
|
// For optimisation reason we're using uint64 as the program counter.
|
||||||
// It's theoretically possible to go above 2^64. The YP defines the PC
|
// It's theoretically possible to go above 2^64. The YP defines the PC
|
||||||
|
|
@ -277,7 +320,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
// Consume the gas and return an error if not enough gas is available.
|
// Consume the gas and return an error if not enough gas is available.
|
||||||
// cost is explicitly set so that the capture state defer method can get the proper cost
|
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||||
var dynamicCost uint64
|
var dynamicCost uint64
|
||||||
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
|
dynamicCost, err = operation.dynamicGas(pc, in.evm, callContext, stack, mem, memorySize)
|
||||||
cost += dynamicCost // for tracing
|
cost += dynamicCost // for tracing
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
|
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
|
||||||
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
|
gasFunc func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, memory *Memory, evmMemorySize uint64) (uint64, error) // last parameters are the requested memory sizes as uint64
|
||||||
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
|
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
|
||||||
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
memorySizeFunc func(*Stack) (memSize uint64, overflow bool)
|
||||||
)
|
)
|
||||||
|
|
||||||
type operation struct {
|
type operation struct {
|
||||||
|
|
@ -59,6 +59,7 @@ var (
|
||||||
londonInstructionSet = newLondonInstructionSet()
|
londonInstructionSet = newLondonInstructionSet()
|
||||||
mergeInstructionSet = newMergeInstructionSet()
|
mergeInstructionSet = newMergeInstructionSet()
|
||||||
shanghaiInstructionSet = newShanghaiInstructionSet()
|
shanghaiInstructionSet = newShanghaiInstructionSet()
|
||||||
|
evmmaxInstructionSet = newEVMMAXInstructionSet()
|
||||||
cancunInstructionSet = newCancunInstructionSet()
|
cancunInstructionSet = newCancunInstructionSet()
|
||||||
verkleInstructionSet = newVerkleInstructionSet()
|
verkleInstructionSet = newVerkleInstructionSet()
|
||||||
pragueEOFInstructionSet = newPragueEOFInstructionSet()
|
pragueEOFInstructionSet = newPragueEOFInstructionSet()
|
||||||
|
|
@ -101,6 +102,49 @@ func newPragueEOFInstructionSet() JumpTable {
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newEVMMAXInstructionSet() JumpTable {
|
||||||
|
instructionSet := newCancunInstructionSet()
|
||||||
|
instructionSet[SETUPX] = &operation{
|
||||||
|
execute: opSetupx,
|
||||||
|
dynamicGas: gasSetupx,
|
||||||
|
minStack: minStack(4, 0),
|
||||||
|
maxStack: maxStack(4, 0),
|
||||||
|
}
|
||||||
|
instructionSet[LOADX] = &operation{
|
||||||
|
execute: opLoadx,
|
||||||
|
constantGas: GasQuickStep,
|
||||||
|
dynamicGas: gasLoadx,
|
||||||
|
minStack: minStack(3, 0),
|
||||||
|
maxStack: maxStack(3, 0),
|
||||||
|
}
|
||||||
|
instructionSet[STOREX] = &operation{
|
||||||
|
execute: opStorex,
|
||||||
|
constantGas: GasQuickStep,
|
||||||
|
dynamicGas: gasStorex,
|
||||||
|
minStack: minStack(3, 0),
|
||||||
|
maxStack: maxStack(3, 0),
|
||||||
|
}
|
||||||
|
instructionSet[ADDMODX] = &operation{
|
||||||
|
execute: opAddmodx,
|
||||||
|
dynamicGas: gasEVMMAXArithOp,
|
||||||
|
minStack: minStack(0, 0),
|
||||||
|
maxStack: maxStack(0, 0),
|
||||||
|
}
|
||||||
|
instructionSet[SUBMODX] = &operation{
|
||||||
|
execute: opSubmodx,
|
||||||
|
dynamicGas: gasEVMMAXArithOp,
|
||||||
|
minStack: minStack(0, 0),
|
||||||
|
maxStack: maxStack(0, 0),
|
||||||
|
}
|
||||||
|
instructionSet[MULMODX] = &operation{
|
||||||
|
execute: opMulmodx,
|
||||||
|
dynamicGas: gasEVMMAXArithOp,
|
||||||
|
minStack: minStack(0, 0),
|
||||||
|
maxStack: maxStack(0, 0),
|
||||||
|
}
|
||||||
|
return instructionSet
|
||||||
|
}
|
||||||
|
|
||||||
func newCancunInstructionSet() JumpTable {
|
func newCancunInstructionSet() JumpTable {
|
||||||
instructionSet := newShanghaiInstructionSet()
|
instructionSet := newShanghaiInstructionSet()
|
||||||
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -30,6 +29,8 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
|
||||||
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
|
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
|
||||||
case rules.IsPrague:
|
case rules.IsPrague:
|
||||||
return newCancunInstructionSet(), errors.New("prague-fork not defined yet")
|
return newCancunInstructionSet(), errors.New("prague-fork not defined yet")
|
||||||
|
case rules.IsEVMMAX:
|
||||||
|
return newEVMMAXInstructionSet(), nil
|
||||||
case rules.IsCancun:
|
case rules.IsCancun:
|
||||||
return newCancunInstructionSet(), nil
|
return newCancunInstructionSet(), nil
|
||||||
case rules.IsShanghai:
|
case rules.IsShanghai:
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,16 @@ const (
|
||||||
SWAP16
|
SWAP16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 0xc0 range - extended-width modular arithmetic ops.
|
||||||
|
const (
|
||||||
|
SETUPX OpCode = 0xc0 + iota
|
||||||
|
LOADX
|
||||||
|
STOREX
|
||||||
|
ADDMODX
|
||||||
|
SUBMODX
|
||||||
|
MULMODX
|
||||||
|
)
|
||||||
|
|
||||||
// 0xa0 range - logging ops.
|
// 0xa0 range - logging ops.
|
||||||
const (
|
const (
|
||||||
LOG0 OpCode = 0xa0 + iota
|
LOG0 OpCode = 0xa0 + iota
|
||||||
|
|
@ -407,6 +417,14 @@ var opCodeToString = [256]string{
|
||||||
SWAP15: "SWAP15",
|
SWAP15: "SWAP15",
|
||||||
SWAP16: "SWAP16",
|
SWAP16: "SWAP16",
|
||||||
|
|
||||||
|
// 0xc0 range - extended-range modular arithmetic ops
|
||||||
|
SETUPX: "SETUPX",
|
||||||
|
LOADX: "LOADX",
|
||||||
|
STOREX: "STOREX",
|
||||||
|
ADDMODX: "ADDMODX",
|
||||||
|
SUBMODX: "SUBMODX",
|
||||||
|
MULMODX: "MULMODX",
|
||||||
|
|
||||||
// 0xa0 range - logging ops.
|
// 0xa0 range - logging ops.
|
||||||
LOG0: "LOG0",
|
LOG0: "LOG0",
|
||||||
LOG1: "LOG1",
|
LOG1: "LOG1",
|
||||||
|
|
|
||||||
|
|
@ -26,23 +26,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
// If we fail the minimum gas availability invariant, fail (0)
|
// If we fail the minimum gas availability invariant, fail (0)
|
||||||
if contract.Gas <= params.SstoreSentryGasEIP2200 {
|
if scope.Contract.Gas <= params.SstoreSentryGasEIP2200 {
|
||||||
return 0, errors.New("not enough gas for reentrancy sentry")
|
return 0, errors.New("not enough gas for reentrancy sentry")
|
||||||
}
|
}
|
||||||
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.peek()
|
y, x = stack.Back(1), stack.peek()
|
||||||
slot = common.Hash(x.Bytes32())
|
slot = common.Hash(x.Bytes32())
|
||||||
current = evm.StateDB.GetState(contract.Address(), slot)
|
current = evm.StateDB.GetState(scope.Contract.Address(), slot)
|
||||||
cost = uint64(0)
|
cost = uint64(0)
|
||||||
)
|
)
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
if _, slotPresent := evm.StateDB.SlotInAccessList(scope.Contract.Address(), slot); !slotPresent {
|
||||||
cost = params.ColdSloadCostEIP2929
|
cost = params.ColdSloadCostEIP2929
|
||||||
// If the caller cannot afford the cost, this change will be rolled back
|
// If the caller cannot afford the cost, this change will be rolled back
|
||||||
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
evm.StateDB.AddSlotToAccessList(scope.Contract.Address(), slot)
|
||||||
}
|
}
|
||||||
value := common.Hash(y.Bytes32())
|
value := common.Hash(y.Bytes32())
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
||||||
// return params.SloadGasEIP2200, nil
|
// return params.SloadGasEIP2200, nil
|
||||||
return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
|
return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
|
||||||
}
|
}
|
||||||
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
|
original := evm.StateDB.GetCommittedState(scope.Contract.Address(), x.Bytes32())
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return cost + params.SstoreSetGasEIP2200, nil
|
return cost + params.SstoreSetGasEIP2200, nil
|
||||||
|
|
@ -95,14 +95,14 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
||||||
// whose storage is being read) is not yet in accessed_storage_keys,
|
// whose storage is being read) is not yet in accessed_storage_keys,
|
||||||
// charge 2100 gas and add the pair to accessed_storage_keys.
|
// charge 2100 gas and add the pair to accessed_storage_keys.
|
||||||
// If the pair is already in accessed_storage_keys, charge 100 gas.
|
// If the pair is already in accessed_storage_keys, charge 100 gas.
|
||||||
func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSLoadEIP2929(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
loc := stack.peek()
|
loc := stack.peek()
|
||||||
slot := common.Hash(loc.Bytes32())
|
slot := common.Hash(loc.Bytes32())
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
if _, slotPresent := evm.StateDB.SlotInAccessList(scope.Contract.Address(), slot); !slotPresent {
|
||||||
// If the caller cannot afford the cost, this change will be rolled back
|
// If the caller cannot afford the cost, this change will be rolled back
|
||||||
// If he does afford it, we can skip checking the same thing later on, during execution
|
// If he does afford it, we can skip checking the same thing later on, during execution
|
||||||
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
evm.StateDB.AddSlotToAccessList(scope.Contract.Address(), slot)
|
||||||
return params.ColdSloadCostEIP2929, nil
|
return params.ColdSloadCostEIP2929, nil
|
||||||
}
|
}
|
||||||
return params.WarmStorageReadCostEIP2929, nil
|
return params.WarmStorageReadCostEIP2929, nil
|
||||||
|
|
@ -113,9 +113,9 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
// > If the target is not in accessed_addresses,
|
// > If the target is not in accessed_addresses,
|
||||||
// > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses.
|
// > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses.
|
||||||
// > Otherwise, charge WARM_STORAGE_READ_COST gas.
|
// > Otherwise, charge WARM_STORAGE_READ_COST gas.
|
||||||
func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCodeCopyEIP2929(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
// memory expansion first (dynamic part of pre-2929 implementation)
|
// memory expansion first (dynamic part of pre-2929 implementation)
|
||||||
gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
|
gas, err := gasExtCodeCopy(pc, evm, scope, stack, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +140,7 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo
|
||||||
// - extcodehash,
|
// - extcodehash,
|
||||||
// - extcodesize,
|
// - extcodesize,
|
||||||
// - (ext) balance
|
// - (ext) balance
|
||||||
func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasEip2929AccountCheck(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
addr := common.Address(stack.peek().Bytes20())
|
addr := common.Address(stack.peek().Bytes20())
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
if !evm.StateDB.AddressInAccessList(addr) {
|
if !evm.StateDB.AddressInAccessList(addr) {
|
||||||
|
|
@ -153,8 +153,8 @@ func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Mem
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) gasFunc {
|
func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
addr := common.Address(stack.Back(addressPosition).Bytes20())
|
addr := common.Address(scope.Stack.Back(addressPosition).Bytes20())
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
warmAccess := evm.StateDB.AddressInAccessList(addr)
|
warmAccess := evm.StateDB.AddressInAccessList(addr)
|
||||||
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
|
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
|
||||||
|
|
@ -164,7 +164,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
||||||
evm.StateDB.AddAddressToAccessList(addr)
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
// Charge the remaining difference here already, to correctly calculate available
|
// Charge the remaining difference here already, to correctly calculate available
|
||||||
// gas for call
|
// gas for call
|
||||||
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
if !scope.Contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
return 0, ErrOutOfGas
|
return 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
||||||
// - transfer value
|
// - transfer value
|
||||||
// - memory expansion
|
// - memory expansion
|
||||||
// - 63/64ths rule
|
// - 63/64ths rule
|
||||||
gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
gas, err := oldCalculator(pc, evm, scope, stack, mem, memorySize)
|
||||||
if warmAccess || err != nil {
|
if warmAccess || err != nil {
|
||||||
return gas, err
|
return gas, err
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
||||||
// add it to the returned gas. By adding it to the return, it will be charged
|
// add it to the returned gas. By adding it to the return, it will be charged
|
||||||
// outside of this function, as part of the dynamic gas, and that will make it
|
// outside of this function, as part of the dynamic gas, and that will make it
|
||||||
// also become correctly reported to tracers.
|
// also become correctly reported to tracers.
|
||||||
contract.Gas += coldCost
|
scope.Contract.Gas += coldCost
|
||||||
|
|
||||||
var overflow bool
|
var overflow bool
|
||||||
if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
|
if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
|
||||||
|
|
@ -221,7 +221,7 @@ var (
|
||||||
|
|
||||||
// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529
|
// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529
|
||||||
func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
||||||
gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
gasFunc := func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
gas uint64
|
gas uint64
|
||||||
address = common.Address(stack.peek().Bytes20())
|
address = common.Address(stack.peek().Bytes20())
|
||||||
|
|
@ -232,10 +232,10 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
||||||
gas = params.ColdAccountAccessCostEIP2929
|
gas = params.ColdAccountAccessCostEIP2929
|
||||||
}
|
}
|
||||||
// if empty and transfers value
|
// if empty and transfers value
|
||||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(scope.Contract.Address()).Sign() != 0 {
|
||||||
gas += params.CreateBySelfdestructGas
|
gas += params.CreateBySelfdestructGas
|
||||||
}
|
}
|
||||||
if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) {
|
if refundsEnabled && !evm.StateDB.HasSelfDestructed(scope.Contract.Address()) {
|
||||||
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
|
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
|
|
|
||||||
|
|
@ -24,23 +24,23 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true)
|
gas := evm.AccessEvents.SlotGas(scope.Contract.Address(), stack.peek().Bytes32(), true)
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = params.WarmStorageReadCostEIP2929
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSLoad4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false)
|
gas := evm.AccessEvents.SlotGas(scope.Contract.Address(), stack.peek().Bytes32(), false)
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = params.WarmStorageReadCostEIP2929
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasBalance4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
address := stack.peek().Bytes20()
|
address := stack.peek().Bytes20()
|
||||||
gas := evm.AccessEvents.BasicDataGas(address, false)
|
gas := evm.AccessEvents.BasicDataGas(address, false)
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
|
|
@ -49,7 +49,7 @@ func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCodeSize4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
address := stack.peek().Bytes20()
|
address := stack.peek().Bytes20()
|
||||||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|
@ -61,7 +61,7 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCodeHash4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
address := stack.peek().Bytes20()
|
address := stack.peek().Bytes20()
|
||||||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|
@ -74,15 +74,15 @@ func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
|
func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
gas, err := oldCalculator(pc, evm, scope, stack, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile {
|
if _, isPrecompile := evm.precompile(scope.Contract.Address()); isPrecompile {
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
witnessGas := evm.AccessEvents.MessageCallGas(contract.Address())
|
witnessGas := evm.AccessEvents.MessageCallGas(scope.Contract.Address())
|
||||||
if witnessGas == 0 {
|
if witnessGas == 0 {
|
||||||
witnessGas = params.WarmStorageReadCostEIP2929
|
witnessGas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
|
|
@ -97,12 +97,12 @@ var (
|
||||||
gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall)
|
gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall)
|
||||||
)
|
)
|
||||||
|
|
||||||
func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSelfdestructEIP4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
beneficiaryAddr := common.Address(stack.peek().Bytes20())
|
beneficiaryAddr := common.Address(stack.peek().Bytes20())
|
||||||
if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile {
|
if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
contractAddr := contract.Address()
|
contractAddr := scope.Contract.Address()
|
||||||
statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false)
|
statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false)
|
||||||
if contractAddr != beneficiaryAddr {
|
if contractAddr != beneficiaryAddr {
|
||||||
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, false)
|
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, false)
|
||||||
|
|
@ -117,8 +117,8 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem
|
||||||
return statelessGas, nil
|
return statelessGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCodeCopyEip4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gas, err := gasCodeCopy(evm, contract, stack, mem, memorySize)
|
gas, err := gasCodeCopy(pc, evm, scope, stack, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -130,16 +130,16 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = gomath.MaxUint64
|
uint64CodeOffset = gomath.MaxUint64
|
||||||
}
|
}
|
||||||
_, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64())
|
_, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
if !contract.IsDeployment {
|
if !scope.Contract.IsDeployment {
|
||||||
gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
|
gas += evm.AccessEvents.CodeChunksRangeGas(scope.Contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(scope.Contract.Code)), false)
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCodeCopyEIP4762(pc uint64, evm *EVM, scope *ScopeContext, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
// memory expansion first (dynamic part of pre-2929 implementation)
|
// memory expansion first (dynamic part of pre-2929 implementation)
|
||||||
gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
|
gas, err := gasExtCodeCopy(pc, evm, scope, stack, mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -46,6 +46,7 @@ require (
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
github.com/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
||||||
|
github.com/jwasinger/evmmax-arith v0.0.0-20241121162715-6824561e983f
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52
|
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -336,6 +336,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
|
github.com/jwasinger/evmmax-arith v0.0.0-20241121162715-6824561e983f h1:o9wHIWVnSTqno+E6KoCes5bOgl8JU+S3YDk1jhH7If8=
|
||||||
|
github.com/jwasinger/evmmax-arith v0.0.0-20241121162715-6824561e983f/go.mod h1:nz1RE8DNCfQycJI4AqfOYbEC1+Uugxvv1ywAvJr5sOs=
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I=
|
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I=
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8=
|
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8=
|
||||||
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,7 @@ type ChainConfig struct {
|
||||||
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
|
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
|
||||||
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
||||||
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
||||||
|
EVMMAXTime *uint64 `json:"evmmaxTime,omitempty"` // EVMMAX switch time (nil = no fork, 0 = already on verkle)
|
||||||
|
|
||||||
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
||||||
// the network that triggers the consensus upgrade.
|
// the network that triggers the consensus upgrade.
|
||||||
|
|
@ -520,6 +521,11 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ChainConfig) IsEVMMAX(num *big.Int, time uint64) bool {
|
||||||
|
res := c.IsLondon(num) && isTimestampForked(c.EVMMAXTime, time)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// IsVerkle returns whether time is either equal to the Verkle fork time or greater.
|
// IsVerkle returns whether time is either equal to the Verkle fork time or greater.
|
||||||
func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
|
func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
|
||||||
|
|
@ -863,6 +869,7 @@ type Rules struct {
|
||||||
IsBerlin, IsLondon bool
|
IsBerlin, IsLondon bool
|
||||||
IsMerge, IsShanghai, IsCancun, IsPrague bool
|
IsMerge, IsShanghai, IsCancun, IsPrague bool
|
||||||
IsVerkle bool
|
IsVerkle bool
|
||||||
|
IsEVMMAX bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules ensures c's ChainID is not nil.
|
// Rules ensures c's ChainID is not nil.
|
||||||
|
|
@ -891,6 +898,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
||||||
IsShanghai: isMerge && c.IsShanghai(num, timestamp),
|
IsShanghai: isMerge && c.IsShanghai(num, timestamp),
|
||||||
IsCancun: isMerge && c.IsCancun(num, timestamp),
|
IsCancun: isMerge && c.IsCancun(num, timestamp),
|
||||||
IsPrague: isMerge && c.IsPrague(num, timestamp),
|
IsPrague: isMerge && c.IsPrague(num, timestamp),
|
||||||
|
IsEVMMAX: isMerge && c.IsEVMMAX(num, timestamp),
|
||||||
IsVerkle: isVerkle,
|
IsVerkle: isVerkle,
|
||||||
IsEIP4762: isVerkle,
|
IsEIP4762: isVerkle,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -210,3 +210,17 @@ var (
|
||||||
ConsolidationQueueAddress = common.HexToAddress("0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb")
|
ConsolidationQueueAddress = common.HexToAddress("0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb")
|
||||||
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
|
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EVMMAX constants
|
||||||
|
var (
|
||||||
|
SetupxPrecompCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
||||||
|
// mulmodx cost lookup table
|
||||||
|
MulmodxCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
||||||
|
// addmodx/submodx cost lookup table
|
||||||
|
AddOrSubCost = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
||||||
|
// the maximum size (in bytes) that can be allocated by all field contexts
|
||||||
|
// per EVM call frame
|
||||||
|
MaxFEAllocSize = 96 * 256
|
||||||
|
StorexBaseCost = 1
|
||||||
|
LoadxBaseCost = 1
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue