core/vm, params: make 2200 in line with spec (#21605)

This commit is contained in:
Martin Holst Swende 2020-09-28 14:14:45 +02:00 committed by GitHub
parent a90e645ccd
commit 0ddd4612b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 25 deletions

@ -163,18 +163,18 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
} }
// 0. If *gasleft* is less than or equal to 2300, fail the current call. // 0. If *gasleft* is less than or equal to 2300, fail the current call.
// 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS gas is deducted. // 1. If current value equals new value (this is a no-op), SLOAD_GAS is deducted.
// 2. If current value does not equal new value: // 2. If current value does not equal new value:
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context): // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context):
// 2.1.1. If original value is 0, SSTORE_INIT_GAS gas is deducted. // 2.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted.
// 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter. // 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter.
// 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses: // 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses:
// 2.2.1. If original value is not 0: // 2.2.1. If original value is not 0:
// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEAR_REFUND gas from refund counter. We can prove that refund counter will never go below 0. // 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter.
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEAR_REFUND gas to refund counter. // 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE gas to refund counter.
// 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_INIT_REFUND 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_CLEAN_REFUND 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(evm *EVM, contract *Contract, 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 contract.Gas <= params.SstoreSentryGasEIP2200 {
@ -188,33 +188,33 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
value := common.Hash(y.Bytes32()) value := common.Hash(y.Bytes32())
if current == value { // noop (1) if current == value { // noop (1)
return params.SstoreNoopGasEIP2200, nil return params.SloadGasEIP2200, nil
} }
original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32())) original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(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.SstoreInitGasEIP2200, nil return params.SstoreSetGasEIP2200, nil
} }
if value == (common.Hash{}) { // delete slot (2.1.2b) if value == (common.Hash{}) { // delete slot (2.1.2b)
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200) evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
} }
return params.SstoreCleanGasEIP2200, nil // write existing slot (2.1.2) return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
} }
if original != (common.Hash{}) { if original != (common.Hash{}) {
if current == (common.Hash{}) { // recreate slot (2.2.1.1) if current == (common.Hash{}) { // recreate slot (2.2.1.1)
evm.StateDB.SubRefund(params.SstoreClearRefundEIP2200) evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200)
} else if value == (common.Hash{}) { // delete slot (2.2.1.2) } else if value == (common.Hash{}) { // delete slot (2.2.1.2)
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200) evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
} }
} }
if original == value { if original == value {
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200) evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
} else { // reset to original existing slot (2.2.2.2) } else { // reset to original existing slot (2.2.2.2)
evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200) evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
} }
} }
return params.SstoreDirtyGasEIP2200, nil // dirty update (2.2) return params.SloadGasEIP2200, nil // dirty update (2.2)
} }
func makeGasLog(n uint64) gasFunc { func makeGasLog(n uint64) gasFunc {

@ -52,14 +52,10 @@ const (
NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value
NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value
SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
SstoreNoopGasEIP2200 uint64 = 800 // Once per SSTORE operation if the value doesn't change. SstoreSetGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
SstoreDirtyGasEIP2200 uint64 = 800 // Once per SSTORE operation if a dirty value is changed. SstoreResetGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
SstoreInitGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero SstoreClearsScheduleRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
SstoreInitRefundEIP2200 uint64 = 19200 // Once per SSTORE operation for resetting to the original zero value
SstoreCleanGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
SstoreCleanRefundEIP2200 uint64 = 4200 // Once per SSTORE operation for resetting to the original non-zero value
SstoreClearRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
JumpdestGas uint64 = 1 // Once per JUMPDEST operation. JumpdestGas uint64 = 1 // Once per JUMPDEST operation.
EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.