From f7c9cc256731a198443c914810d99bfcb7b2b835 Mon Sep 17 00:00:00 2001 From: Green <40367733+greenlucid@users.noreply.github.com> Date: Wed, 20 Apr 2022 16:51:25 +0200 Subject: [PATCH] core: implement EIP 5022 --- core/vm/eips.go | 7 +++++++ core/vm/gas_table.go | 43 +++++++++++++++++++++++++++++++++++++++ params/protocol_params.go | 1 + 3 files changed, 51 insertions(+) diff --git a/core/vm/eips.go b/core/vm/eips.go index 4070a2db5342..de52a49506ef 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -25,6 +25,7 @@ import ( ) var activators = map[int]func(*JumpTable){ + 5022: enable5022, 3529: enable3529, 3198: enable3198, 2929: enable2929, @@ -109,6 +110,12 @@ func enable2200(jt *JumpTable) { jt[SSTORE].dynamicGas = gasSStoreEIP2200 } +// same as 2200, but different sstore zero -> non-zero pricing +func enable5022(jt *JumpTable) { + jt[SLOAD].constantGas = params.SloadGasEIP2200 + jt[SSTORE].dynamicGas = gasSStoreEIP5022 +} + // enable2929 enables "EIP-2929: Gas cost increases for state access opcodes" // https://eips.ethereum.org/EIPS/eip-2929 func enable2929(jt *JumpTable) { diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4c2cb3e5cf79..2cd5c63475ec 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -217,6 +217,49 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m return params.SloadGasEIP2200, nil // dirty update (2.2) } +// Flow is the same as EIP2200, but different zero -> non-zero pricing +func gasSStoreEIP5022(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") + } + // Gas sentry honoured, do the actual gas calculation based on the stored value + var ( + y, x = stack.Back(1), stack.Back(0) + current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) + ) + value := common.Hash(y.Bytes32()) + + if current == value { // noop (1) + return params.SloadGasEIP2200, nil + } + original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return params.SstoreSetGasEIP5022, nil + } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) + } + return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) + } else { // reset to original existing slot (2.2.2.2) + evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) + } + } + return params.SloadGasEIP2200, nil // dirty update (2.2) +} + func makeGasLog(n uint64) gasFunc { return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { requestedSize, overflow := stack.Back(1).Uint64WithOverflow() diff --git a/params/protocol_params.go b/params/protocol_params.go index 5f154597a7fa..49d7e4de6747 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -55,6 +55,7 @@ const ( SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed SstoreSetGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero + SstoreSetGasEIP5022 uint64 = 40000 // Once per SSTORE operation from clean zero to non-zero, after eip-5022 SstoreResetGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else SstoreClearsScheduleRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot