@@ -24,91 +24,75 @@ import (
2424 "github.com/ethereum/go-ethereum/params"
2525)
2626
27- const (
28- ColdAccountAccessCostEIP2929 = uint64 (2600 ) // COLD_ACCOUNT_ACCESS_COST
29- ColdSloadCostEIP2929 = uint64 (2100 ) // COLD_SLOAD_COST
30- WarmStorageReadCostEIP2929 = uint64 (100 ) // WARM_STORAGE_READ_COST
31- )
32-
33- // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929
34- //
35- // When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys.
36- // If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys.
37- // Additionally, modify the parameters defined in EIP 2200 as follows:
38- //
39- // Parameter Old value New value
40- // SLOAD_GAS 800 = WARM_STORAGE_READ_COST
41- // SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST
42- //
43- //The other parameters defined in EIP 2200 are unchanged.
44- // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified
45- func gasSStoreEIP2929 (evm * EVM , contract * Contract , stack * Stack , mem * Memory , memorySize uint64 ) (uint64 , error ) {
46- // If we fail the minimum gas availability invariant, fail (0)
47- if contract .Gas <= params .SstoreSentryGasEIP2200 {
48- return 0 , errors .New ("not enough gas for reentrancy sentry" )
49- }
50- // Gas sentry honoured, do the actual gas calculation based on the stored value
51- var (
52- y , x = stack .Back (1 ), stack .peek ()
53- slot = common .Hash (x .Bytes32 ())
54- current = evm .StateDB .GetState (contract .Address (), slot )
55- cost = uint64 (0 )
56- )
57- // Check slot presence in the access list
58- if addrPresent , slotPresent := evm .StateDB .SlotInAccessList (contract .Address (), slot ); ! slotPresent {
59- cost = ColdSloadCostEIP2929
60- // If the caller cannot afford the cost, this change will be rolled back
61- evm .StateDB .AddSlotToAccessList (contract .Address (), slot )
62- if ! addrPresent {
63- // Once we're done with YOLOv2 and schedule this for mainnet, might
64- // be good to remove this panic here, which is just really a
65- // canary to have during testing
66- panic ("impossible case: address was not present in access list during sstore op" )
27+ func makeGasSStoreFunc (clearingRefund uint64 ) gasFunc {
28+ return func (evm * EVM , contract * Contract , stack * Stack , mem * Memory , memorySize uint64 ) (uint64 , error ) {
29+ // If we fail the minimum gas availability invariant, fail (0)
30+ if contract .Gas <= params .SstoreSentryGasEIP2200 {
31+ return 0 , errors .New ("not enough gas for reentrancy sentry" )
6732 }
68- }
69- value := common .Hash (y .Bytes32 ())
33+ // Gas sentry honoured, do the actual gas calculation based on the stored value
34+ var (
35+ y , x = stack .Back (1 ), stack .peek ()
36+ slot = common .Hash (x .Bytes32 ())
37+ current = evm .StateDB .GetState (contract .Address (), slot )
38+ cost = uint64 (0 )
39+ )
40+ // Check slot presence in the access list
41+ if addrPresent , slotPresent := evm .StateDB .SlotInAccessList (contract .Address (), slot ); ! slotPresent {
42+ cost = params .ColdSloadCostEIP2929
43+ // If the caller cannot afford the cost, this change will be rolled back
44+ evm .StateDB .AddSlotToAccessList (contract .Address (), slot )
45+ if ! addrPresent {
46+ // Once we're done with YOLOv2 and schedule this for mainnet, might
47+ // be good to remove this panic here, which is just really a
48+ // canary to have during testing
49+ panic ("impossible case: address was not present in access list during sstore op" )
50+ }
51+ }
52+ value := common .Hash (y .Bytes32 ())
7053
71- if current == value { // noop (1)
72- // EIP 2200 original clause:
73- // return params.SloadGasEIP2200, nil
74- return cost + WarmStorageReadCostEIP2929 , nil // SLOAD_GAS
75- }
76- original := evm .StateDB .GetCommittedState (contract .Address (), x .Bytes32 ())
77- if original == current {
78- if original == (common.Hash {}) { // create slot (2.1.1)
79- return cost + params .SstoreSetGasEIP2200 , nil
54+ if current == value { // noop (1)
55+ // EIP 2200 original clause:
56+ // return params.SloadGasEIP2200, nil
57+ return cost + params .WarmStorageReadCostEIP2929 , nil // SLOAD_GAS
8058 }
81- if value == (common.Hash {}) { // delete slot (2.1.2b)
82- evm .StateDB .AddRefund (params .SstoreClearsScheduleRefundEIP2200 )
59+ original := evm .StateDB .GetCommittedState (contract .Address (), x .Bytes32 ())
60+ if original == current {
61+ if original == (common.Hash {}) { // create slot (2.1.1)
62+ return cost + params .SstoreSetGasEIP2200 , nil
63+ }
64+ if value == (common.Hash {}) { // delete slot (2.1.2b)
65+ evm .StateDB .AddRefund (clearingRefund )
66+ }
67+ // EIP-2200 original clause:
68+ // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
69+ return cost + (params .SstoreResetGasEIP2200 - params .ColdSloadCostEIP2929 ), nil // write existing slot (2.1.2)
8370 }
84- // EIP-2200 original clause:
85- // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
86- return cost + (params .SstoreResetGasEIP2200 - ColdSloadCostEIP2929 ), nil // write existing slot (2.1.2)
87- }
88- if original != (common.Hash {}) {
89- if current == (common.Hash {}) { // recreate slot (2.2.1.1)
90- evm .StateDB .SubRefund (params .SstoreClearsScheduleRefundEIP2200 )
91- } else if value == (common.Hash {}) { // delete slot (2.2.1.2)
92- evm .StateDB .AddRefund (params .SstoreClearsScheduleRefundEIP2200 )
71+ if original != (common.Hash {}) {
72+ if current == (common.Hash {}) { // recreate slot (2.2.1.1)
73+ evm .StateDB .SubRefund (clearingRefund )
74+ } else if value == (common.Hash {}) { // delete slot (2.2.1.2)
75+ evm .StateDB .AddRefund (clearingRefund )
76+ }
9377 }
94- }
95- if original == value {
96- if original == (common. Hash {}) { // reset to original inexistent slot (2.2.2.1)
97- // EIP 2200 Original clause:
98- // evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200 )
99- evm . StateDB . AddRefund ( params . SstoreSetGasEIP2200 - WarmStorageReadCostEIP2929 )
100- } else { // reset to original existing slot (2.2.2.2)
101- // EIP 2200 Original clause:
102- // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200 )
103- // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST)
104- // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST
105- // Final: (5000 - COLD_SLOAD_COST ) - WARM_STORAGE_READ_COST
106- evm . StateDB . AddRefund (( params . SstoreResetGasEIP2200 - ColdSloadCostEIP2929 ) - WarmStorageReadCostEIP2929 )
78+ if original == value {
79+ if original == (common. Hash {}) { // reset to original inexistent slot (2.2.2.1)
80+ // EIP 2200 Original clause:
81+ //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
82+ evm .StateDB .AddRefund (params .SstoreSetGasEIP2200 - params .WarmStorageReadCostEIP2929 )
83+ } else { // reset to original existing slot (2.2.2.2 )
84+ // EIP 2200 Original clause:
85+ // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
86+ // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST )
87+ // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST
88+ // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST
89+ evm . StateDB . AddRefund (( params . SstoreResetGasEIP2200 - params . ColdSloadCostEIP2929 ) - params . WarmStorageReadCostEIP2929 )
90+ }
10791 }
92+ // EIP-2200 original clause:
93+ //return params.SloadGasEIP2200, nil // dirty update (2.2)
94+ return cost + params .WarmStorageReadCostEIP2929 , nil // dirty update (2.2)
10895 }
109- // EIP-2200 original clause:
110- //return params.SloadGasEIP2200, nil // dirty update (2.2)
111- return cost + WarmStorageReadCostEIP2929 , nil // dirty update (2.2)
11296}
11397
11498// gasSLoadEIP2929 calculates dynamic gas for SLOAD according to EIP-2929
@@ -124,9 +108,9 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
124108 // If the caller cannot afford the cost, this change will be rolled back
125109 // If he does afford it, we can skip checking the same thing later on, during execution
126110 evm .StateDB .AddSlotToAccessList (contract .Address (), slot )
127- return ColdSloadCostEIP2929 , nil
111+ return params . ColdSloadCostEIP2929 , nil
128112 }
129- return WarmStorageReadCostEIP2929 , nil
113+ return params . WarmStorageReadCostEIP2929 , nil
130114}
131115
132116// gasExtCodeCopyEIP2929 implements extcodecopy according to EIP-2929
@@ -146,7 +130,7 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo
146130 evm .StateDB .AddAddressToAccessList (addr )
147131 var overflow bool
148132 // We charge (cold-warm), since 'warm' is already charged as constantGas
149- if gas , overflow = math .SafeAdd (gas , ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929 ); overflow {
133+ if gas , overflow = math .SafeAdd (gas , params . ColdAccountAccessCostEIP2929 - params . WarmStorageReadCostEIP2929 ); overflow {
150134 return 0 , ErrGasUintOverflow
151135 }
152136 return gas , nil
@@ -168,7 +152,7 @@ func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Mem
168152 // If the caller cannot afford the cost, this change will be rolled back
169153 evm .StateDB .AddAddressToAccessList (addr )
170154 // The warm storage read cost is already charged as constantGas
171- return ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929 , nil
155+ return params . ColdAccountAccessCostEIP2929 - params . WarmStorageReadCostEIP2929 , nil
172156 }
173157 return 0 , nil
174158}
@@ -180,7 +164,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
180164 warmAccess := evm .StateDB .AddressInAccessList (addr )
181165 // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
182166 // the cost to charge for cold access, if any, is Cold - Warm
183- coldCost := ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929
167+ coldCost := params . ColdAccountAccessCostEIP2929 - params . WarmStorageReadCostEIP2929
184168 if ! warmAccess {
185169 evm .StateDB .AddAddressToAccessList (addr )
186170 // Charge the remaining difference here already, to correctly calculate available
@@ -212,25 +196,49 @@ var (
212196 gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929 (gasDelegateCall )
213197 gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929 (gasStaticCall )
214198 gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929 (gasCallCode )
199+ gasSelfdestructEIP2929 = makeSelfdestructGasFn (true )
200+ // gasSelfdestructEIP3529 implements the changes in EIP-2539 (no refunds)
201+ gasSelfdestructEIP3529 = makeSelfdestructGasFn (false )
202+
203+ // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929
204+ //
205+ // When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys.
206+ // If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys.
207+ // Additionally, modify the parameters defined in EIP 2200 as follows:
208+ //
209+ // Parameter Old value New value
210+ // SLOAD_GAS 800 = WARM_STORAGE_READ_COST
211+ // SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST
212+ //
213+ //The other parameters defined in EIP 2200 are unchanged.
214+ // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified
215+ gasSStoreEIP2929 = makeGasSStoreFunc (params .SstoreClearsScheduleRefundEIP2200 )
216+
217+ // gasSStoreEIP2539 implements gas cost for SSTORE according to EPI-2539
218+ // Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800)
219+ gasSStoreEIP3529 = makeGasSStoreFunc (params .SstoreClearsScheduleRefundEIP3529 )
215220)
216221
217- func gasSelfdestructEIP2929 (evm * EVM , contract * Contract , stack * Stack , mem * Memory , memorySize uint64 ) (uint64 , error ) {
218- var (
219- gas uint64
220- address = common .Address (stack .peek ().Bytes20 ())
221- )
222- if ! evm .StateDB .AddressInAccessList (address ) {
223- // If the caller cannot afford the cost, this change will be rolled back
224- evm .StateDB .AddAddressToAccessList (address )
225- gas = ColdAccountAccessCostEIP2929
226- }
227- // if empty and transfers value
228- if evm .StateDB .Empty (address ) && evm .StateDB .GetBalance (contract .Address ()).Sign () != 0 {
229- gas += params .CreateBySelfdestructGas
230- }
231- if ! evm .StateDB .HasSuicided (contract .Address ()) {
232- evm .StateDB .AddRefund (params .SelfdestructRefundGas )
222+ // makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-2539
223+ func makeSelfdestructGasFn (refundsEnabled bool ) gasFunc {
224+ gasFunc := func (evm * EVM , contract * Contract , stack * Stack , mem * Memory , memorySize uint64 ) (uint64 , error ) {
225+ var (
226+ gas uint64
227+ address = common .Address (stack .peek ().Bytes20 ())
228+ )
229+ if ! evm .StateDB .AddressInAccessList (address ) {
230+ // If the caller cannot afford the cost, this change will be rolled back
231+ evm .StateDB .AddAddressToAccessList (address )
232+ gas = params .ColdAccountAccessCostEIP2929
233+ }
234+ // if empty and transfers value
235+ if evm .StateDB .Empty (address ) && evm .StateDB .GetBalance (contract .Address ()).Sign () != 0 {
236+ gas += params .CreateBySelfdestructGas
237+ }
238+ if refundsEnabled && ! evm .StateDB .HasSuicided (contract .Address ()) {
239+ evm .StateDB .AddRefund (params .SelfdestructRefundGas )
240+ }
241+ return gas , nil
233242 }
234- return gas , nil
235-
243+ return gasFunc
236244}
0 commit comments