Skip to content

Commit d7ff884

Browse files
[ETCM-912] SSTORE gas changes
1 parent f649a47 commit d7ff884

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

src/main/scala/io/iohk/ethereum/vm/OpCode.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,12 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) {
726726
0
727727
}
728728
val updatedStorage = state.storage.store(offset, newValue)
729-
state.withStack(stack1).withStorage(updatedStorage).refundGas(refund).step()
729+
state
730+
.addAccessedStorageKey(state.ownAddress, offset)
731+
.withStack(stack1)
732+
.withStorage(updatedStorage)
733+
.refundGas(refund)
734+
.step()
730735
}
731736

732737
protected def varGas[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): BigInt = {
@@ -740,7 +745,7 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) {
740745
val eip2200Enabled = isEip2200Enabled(etcFork, ethFork)
741746
val eip1283Enabled = isEip1283Enabled(ethFork)
742747

743-
if (eip2200Enabled && state.gas <= state.config.feeSchedule.G_callstipend) {
748+
val originalCharge: BigInt = if (eip2200Enabled && state.gas <= state.config.feeSchedule.G_callstipend) {
744749
state.config.feeSchedule.G_callstipend + 1 // Out of gas error
745750
} else if (eip2200Enabled || eip1283Enabled) {
746751
if (currentValue == newValue.toBigInt) { // no-op
@@ -763,6 +768,8 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) {
763768
else
764769
state.config.feeSchedule.G_sreset
765770
}
771+
772+
originalCharge + OpCode.storageAccessCost(state, state.ownAddress, offset)(_ => 0, _.G_cold_account_access, _ => 0)
766773
}
767774

768775
override protected def availableInContext[W <: WorldStateProxy[W, S], S <: Storage[S]]

src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,11 @@ class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc
462462
val data = stateOut.storage.load(offset)
463463
data shouldEqual value.toBigInt
464464

465-
stateOut shouldEqual stateIn.withStack(stateOut.stack).withStorage(stateOut.storage).step()
465+
stateOut shouldEqual stateIn
466+
.addAccessedStorageKey(stateIn.ownAddress, offset)
467+
.withStack(stateOut.stack)
468+
.withStorage(stateOut.storage)
469+
.step()
466470
}
467471
}
468472
}

src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpecPostEip2929.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.iohk.ethereum.vm
22

33
import org.scalacheck.Arbitrary
4+
import org.scalacheck.Gen
45
import org.scalatest.funsuite.AnyFunSuite
56
import org.scalatest.matchers.should.Matchers
67
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
@@ -196,4 +197,51 @@ class OpCodeGasSpecPostEip2929 extends AnyFunSuite with OpCodeTesting with Match
196197
}
197198
}
198199
}
200+
201+
test(SSTORE) { op =>
202+
val storage = MockStorage.Empty.store(Zero, One)
203+
val table = Table[UInt256, UInt256, Boolean, BigInt, BigInt](
204+
("offset", "value", "alreadyAccessed", "startGas", "expectedGasConsumption"),
205+
(0, 1, true, G_callstipend + 1, G_sload),
206+
(0, 1, false, G_sload + G_cold_account_access, G_sload + G_cold_account_access),
207+
(0, 0, true, G_callstipend + 1, G_sload),
208+
(0, 0, false, G_sload + G_cold_account_access, G_sload + G_cold_account_access),
209+
(1, 0, true, G_callstipend + 1, G_sload),
210+
(1, 0, false, G_sload + G_cold_account_access, G_sload + G_cold_account_access),
211+
(1, 1, true, G_sset, G_sset),
212+
(1, 1, false, G_sset + G_cold_account_access, G_sset + G_cold_account_access)
213+
)
214+
215+
forAll(table) { (offset, value, alreadyAccessed, startGas, expectedGasConsumption) =>
216+
val stackIn = Stack.empty().push(value).push(offset)
217+
val stateIn = getProgramStateGen(
218+
blockNumberGen = getUInt256Gen(Fixtures.MagnetoBlockNumber),
219+
evmConfig = config
220+
).sample.get.withStack(stackIn).withStorage(storage).copy(gas = startGas)
221+
222+
val stateOut =
223+
if (alreadyAccessed) op.execute(stateIn.addAccessedStorageKey(stateIn.ownAddress, offset))
224+
else op.execute(stateIn)
225+
verifyGas(expectedGasConsumption, stateIn, stateOut, allowOOG = false)
226+
}
227+
228+
// test G_sreset
229+
forAll(Arbitrary.arbitrary[Boolean]) { alreadyAccessed =>
230+
val offset = 0
231+
val value = 0
232+
val expectedGasConsumption = if (alreadyAccessed) G_sreset else G_sreset + G_cold_account_access
233+
234+
val stackIn = Stack.empty().push(value).push(offset)
235+
val stateIn = getProgramStateGen(
236+
blockNumberGen = getUInt256Gen(Fixtures.MagnetoBlockNumber),
237+
evmConfig = config,
238+
storageGen = Gen.const(storage)
239+
).sample.get.withStack(stackIn).copy(gas = expectedGasConsumption)
240+
241+
val stateOut =
242+
if (alreadyAccessed) op.execute(stateIn.addAccessedStorageKey(stateIn.ownAddress, offset))
243+
else op.execute(stateIn)
244+
verifyGas(expectedGasConsumption, stateIn, stateOut, allowOOG = false)
245+
}
246+
}
199247
}

0 commit comments

Comments
 (0)