Skip to content

Commit c529171

Browse files
authored
fix: add sload witness when calculating dynamic gas (#1157)
* add sload witness when calculating dynamic gas * change sstore * tweaks * fix * move get sload witness only when in cold sload * remove a fake comment * tweak logs * nit
1 parent 048db62 commit c529171

File tree

3 files changed

+30
-12
lines changed

3 files changed

+30
-12
lines changed

core/vm/gas_table.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
100100
y, x = stack.Back(1), stack.Back(0)
101101
current = evm.StateDB.GetState(contract.Address(), x.Bytes32())
102102
)
103+
104+
// Try updating the witness of SSTORE at first to align with reth's witness implementation.
105+
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
106+
103107
// The legacy gas metering only takes into consideration the current state
104108
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
105109
// OR Constantinople is not active
@@ -137,7 +141,6 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
137141
if current == value { // noop (1)
138142
return params.NetSstoreNoopGas, nil
139143
}
140-
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
141144
if original == current {
142145
if original == (common.Hash{}) { // create slot (2.1.1)
143146
return params.NetSstoreInitGas, nil
@@ -178,21 +181,24 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
178181
// 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
179182
// 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter.
180183
func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
181-
// If we fail the minimum gas availability invariant, fail (0)
182-
if contract.Gas <= params.SstoreSentryGasEIP2200 {
183-
return 0, errors.New("not enough gas for reentrancy sentry")
184-
}
185184
// Gas sentry honoured, do the actual gas calculation based on the stored value
186185
var (
187186
y, x = stack.Back(1), stack.Back(0)
188187
current = evm.StateDB.GetState(contract.Address(), x.Bytes32())
189188
)
190189
value := common.Hash(y.Bytes32())
191190

191+
// Try updating the witness of SSTORE at first to align with reth's witness implementation.
192+
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
193+
194+
// If we fail the minimum gas availability invariant, fail (0)
195+
if contract.Gas <= params.SstoreSentryGasEIP2200 {
196+
return 0, errors.New("not enough gas for reentrancy sentry")
197+
}
198+
192199
if current == value { // noop (1)
193200
return params.SloadGasEIP2200, nil
194201
}
195-
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
196202
if original == current {
197203
if original == (common.Hash{}) { // create slot (2.1.1)
198204
return params.SstoreSetGasEIP2200, nil

core/vm/operations_acl.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,22 @@ import (
2727

2828
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
2929
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
30-
// If we fail the minimum gas availability invariant, fail (0)
31-
if contract.Gas <= params.SstoreSentryGasEIP2200 {
32-
return 0, errors.New("not enough gas for reentrancy sentry")
33-
}
3430
// Gas sentry honoured, do the actual gas calculation based on the stored value
3531
var (
3632
y, x = stack.Back(1), stack.peek()
3733
slot = common.Hash(x.Bytes32())
3834
current = evm.StateDB.GetState(contract.Address(), slot)
3935
cost = uint64(0)
4036
)
37+
38+
// Try updating the witness of SSTORE at first to align with reth's witness implementation.
39+
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
40+
41+
// If we fail the minimum gas availability invariant, fail (0)
42+
if contract.Gas <= params.SstoreSentryGasEIP2200 {
43+
return 0, errors.New("not enough gas for reentrancy sentry")
44+
}
45+
4146
// Check slot presence in the access list
4247
if addrPresent, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
4348
cost = params.ColdSloadCostEIP2929
@@ -57,7 +62,6 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
5762
// return params.SloadGasEIP2200, nil
5863
return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
5964
}
60-
original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32())
6165
if original == current {
6266
if original == (common.Hash{}) { // create slot (2.1.1)
6367
return cost + params.SstoreSetGasEIP2200, nil
@@ -109,6 +113,14 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
109113
// If the caller cannot afford the cost, this change will be rolled back
110114
// If he does afford it, we can skip checking the same thing later on, during execution
111115
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
116+
117+
// Try updating the witness of SLOAD to align with reth's witness implementation.
118+
// Another place that needs to change is when calculating the gas cost after Frontier and before EIP-2929.
119+
// Frontier gas cost simply uses params.SloadGasFrontier (i.e., 50 gas), so changing the gas cost there
120+
// might affect code cleanliness. Usually, this won't be a problem because EIP-2929 is enabled by default.
121+
// Thus, adding the SLOAD witness before EIP-2929 is left as a TODO here.
122+
evm.StateDB.GetCommittedState(contract.Address(), loc.Bytes32())
123+
112124
return params.ColdSloadCostEIP2929, nil
113125
}
114126
return params.WarmStorageReadCostEIP2929, nil

params/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
const (
2525
VersionMajor = 5 // Major version component of the current release
2626
VersionMinor = 8 // Minor version component of the current release
27-
VersionPatch = 29 // Patch version component of the current release
27+
VersionPatch = 30 // Patch version component of the current release
2828
VersionMeta = "mainnet" // Version metadata to append to the version string
2929
)
3030

0 commit comments

Comments
 (0)