From 4ed9a49e9da6e39b8672ec8d235829bb21e71224 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 18 Mar 2024 17:04:29 +0100 Subject: [PATCH] core/vm: PAY opcode EIP-5920 --- core/vm/eips.go | 26 ++++++++++++++++++++++++++ core/vm/gas_table.go | 18 ++++++++++++++++++ core/vm/interpreter.go | 2 +- core/vm/opcodes.go | 3 +++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 9f06b2818f..19bd5b79ee 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -37,6 +37,7 @@ var activators = map[int]func(*JumpTable){ 1884: enable1884, 1344: enable1344, 1153: enable1153, + 5920: enable5920, } // EnableEIP enables the given EIP on the config. @@ -55,6 +56,7 @@ func ValidEip(eipNum int) bool { _, ok := activators[eipNum] return ok } + func ActivateableEips() []string { var nums []string for k := range activators { @@ -319,3 +321,27 @@ func enable6780(jt *JumpTable) { maxStack: maxStack(1, 0), } } + +func enable5920(jt *JumpTable) { + jt[PAY] = &operation{ + execute: opPay, + constantGas: params.WarmStorageReadCostEIP2929, + dynamicGas: gasPay, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + } +} + +func opPay(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } + var ( + addr = scope.Stack.pop() + amount = scope.Stack.pop() + ) + if interpreter.evm.Context.CanTransfer(interpreter.evm.StateDB, scope.Contract.Address(), &amount) { + interpreter.evm.Context.Transfer(interpreter.evm.StateDB, scope.Contract.Address(), addr.Bytes20(), &amount) + } + return nil, nil +} diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4b141d8f9a..fe253beec8 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -477,3 +477,21 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me } return gas, nil } + +func gasPay(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + addr = stack.peek().Bytes20() + transfersValue = !stack.Back(1).IsZero() + ) + gas, err := gasEip2929AccountCheck(evm, contract, stack, mem, memorySize) + if err != nil { + return 0, err + } + if transfersValue { + gas += params.CallValueTransferGas + if evm.StateDB.Empty(addr) { + gas += params.CallNewAccountGas + } + } + return gas, nil +} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1968289f4e..4989f2fde6 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -189,7 +189,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, ErrOutOfGas } if operation.dynamicGas != nil { - // All ops with a dynamic memory usage also has a dynamic gas cost. + // All ops with a dynamic memory usage also have a dynamic gas cost. var memorySize uint64 // calculate the new memory size and expand the memory to fit // the operation diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 2b9231fe1a..7c1f54705f 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -218,6 +218,7 @@ const ( DELEGATECALL OpCode = 0xf4 CREATE2 OpCode = 0xf5 + PAY OpCode = 0xf9 STATICCALL OpCode = 0xfa REVERT OpCode = 0xfd INVALID OpCode = 0xfe @@ -391,6 +392,7 @@ var opCodeToString = [256]string{ CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", CREATE2: "CREATE2", + PAY: "PAY", STATICCALL: "STATICCALL", REVERT: "REVERT", INVALID: "INVALID", @@ -554,6 +556,7 @@ var stringToOp = map[string]OpCode{ "REVERT": REVERT, "INVALID": INVALID, "SELFDESTRUCT": SELFDESTRUCT, + "PAY": PAY, } // StringToOp finds the opcode whose name is stored in `str`.