diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index fe7c34759c..cc1cdcee39 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -100,6 +100,10 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi y, x = stack.Back(1), stack.Back(0) current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) ) + + // Try updating the witness of SSTORE at first to align with reth's witness implementation. + original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) + // 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) // OR Constantinople is not active @@ -137,7 +141,6 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi if current == value { // noop (1) return params.NetSstoreNoopGas, nil } - original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) if original == current { if original == (common.Hash{}) { // create slot (2.1.1) return params.NetSstoreInitGas, nil @@ -178,10 +181,6 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi // 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. func gasSStoreEIP2200(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) @@ -189,10 +188,17 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m ) value := common.Hash(y.Bytes32()) + // Try updating the witness of SSTORE at first to align with reth's witness implementation. + original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) + + // 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") + } + 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.SstoreSetGasEIP2200, nil diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index d9a8b44102..0a53d62ada 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -27,10 +27,6 @@ import ( func makeGasSStoreFunc(clearingRefund uint64) gasFunc { return func(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.peek() @@ -38,6 +34,15 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { current = evm.StateDB.GetState(contract.Address(), slot) cost = uint64(0) ) + + // Try updating the witness of SSTORE at first to align with reth's witness implementation. + original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) + + // 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") + } + // Check slot presence in the access list if addrPresent, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { cost = params.ColdSloadCostEIP2929 @@ -57,7 +62,6 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { // return params.SloadGasEIP2200, nil return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS } - original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) if original == current { if original == (common.Hash{}) { // create slot (2.1.1) return cost + params.SstoreSetGasEIP2200, nil @@ -109,6 +113,14 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me // 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 evm.StateDB.AddSlotToAccessList(contract.Address(), slot) + + // Try updating the witness of SLOAD to align with reth's witness implementation. + // Another place that needs to change is when calculating the gas cost after Frontier and before EIP-2929. + // Frontier gas cost simply uses params.SloadGasFrontier (i.e., 50 gas), so changing the gas cost there + // might affect code cleanliness. Usually, this won't be a problem because EIP-2929 is enabled by default. + // Thus, adding the SLOAD witness before EIP-2929 is left as a TODO here. + evm.StateDB.GetCommittedState(contract.Address(), loc.Bytes32()) + return params.ColdSloadCostEIP2929, nil } return params.WarmStorageReadCostEIP2929, nil diff --git a/params/version.go b/params/version.go index d3e1cbbc50..2a7eb3c126 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 29 // Patch version component of the current release + VersionPatch = 30 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string )