implement EIP2200's SSTORE and gas cost
This commit is contained in:
parent
c0c62b94b8
commit
61f340ae87
|
@ -208,6 +208,10 @@ proc isDeadAccount*(db: AccountStateDB, address: EthAddress): bool =
|
|||
else:
|
||||
result = true
|
||||
|
||||
proc getCommittedStorage*(db: AccountStateDB, address: EthAddress, slot: UInt256): UInt256 =
|
||||
discard
|
||||
# TODO: stub
|
||||
|
||||
proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
|
||||
proc getAccount*(db: ReadOnlyStateDB, address: EthAddress): Account {.borrow.}
|
||||
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
|
||||
|
@ -220,3 +224,4 @@ proc hasCodeOrNonce*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
|||
proc accountExists*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||
proc isDeadAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||
proc isEmptyAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||
proc getCommittedStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): UInt256 {.borrow.}
|
||||
|
|
|
@ -65,6 +65,8 @@ type
|
|||
case kind*: Op
|
||||
of Sstore:
|
||||
s_isStorageEmpty*: bool
|
||||
s_currentValue*: Uint256
|
||||
s_originalValue*: Uint256
|
||||
of Call, CallCode, DelegateCall, StaticCall:
|
||||
c_isNewAccount*: bool
|
||||
c_gasBalance*: GasInt
|
||||
|
@ -247,6 +249,34 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
|
|||
ClearRefundEIP2200 = FeeSchedule[RefundSclear]# clearing an originally existing storage slot
|
||||
|
||||
# Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||
if gasParams.s_currentValue == value: # noop (1)
|
||||
result.gasCost = NoopGasEIP2200
|
||||
return
|
||||
|
||||
if gasParams.s_originalValue == gasParams.s_currentValue:
|
||||
if gasParams.s_originalValue.isZero: # create slot (2.1.1)
|
||||
result.gasCost = InitGasEIP2200
|
||||
return
|
||||
|
||||
if value.isZero: # delete slot (2.1.2b)
|
||||
result.gasRefund = ClearRefundEIP2200
|
||||
|
||||
result.gasCost = CleanGasEIP2200 # write existing slot (2.1.2)
|
||||
return
|
||||
|
||||
if not gasParams.s_originalValue.isZero:
|
||||
if gasParams.s_currentValue.isZero: # recreate slot (2.2.1.1)
|
||||
result.gasRefund -= ClearRefundEIP2200
|
||||
if value.isZero: # delete slot (2.2.1.2)
|
||||
result.gasRefund += ClearRefundEIP2200
|
||||
|
||||
if gasParams.s_originalValue == value:
|
||||
if gasParams.s_originalValue.isZero: # reset to original inexistent slot (2.2.2.1)
|
||||
result.gasRefund = InitRefundEIP2200
|
||||
else: # reset to original existing slot (2.2.2.2)
|
||||
result.gasRefund = CleanRefundEIP2200
|
||||
|
||||
result.gasCost = DirtyGasEIP2200 # dirty update (2.2)
|
||||
|
||||
func `prefix gasLog0`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||
result = `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||
|
|
|
@ -933,4 +933,26 @@ op extCodeHash, inline = true:
|
|||
|
||||
op sstoreEIP2200, inline = false, slot, value:
|
||||
checkInStaticContext(computation)
|
||||
# TODO: stub
|
||||
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
|
||||
|
||||
if computation.gasMeter.gasRemaining < SentryGasEIP2200:
|
||||
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
|
||||
|
||||
let stateDB = computation.vmState.readOnlyStateDB
|
||||
let (currentValue, existing) = stateDB.getStorage(computation.msg.storageAddress, slot)
|
||||
|
||||
let
|
||||
gasParam = GasParams(kind: Op.Sstore,
|
||||
s_isStorageEmpty: currentValue.isZero,
|
||||
s_currentValue: currentValue,
|
||||
s_originalValue: stateDB.getCommittedStorage(computation.msg.storageAddress, slot)
|
||||
)
|
||||
(gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(value, gasParam)
|
||||
|
||||
computation.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {computation.msg.storageAddress}[{slot}] -> {value} ({currentValue})")
|
||||
|
||||
if gasRefund > 0:
|
||||
computation.gasMeter.refundGas(gasRefund)
|
||||
|
||||
computation.vmState.mutateStateDB:
|
||||
db.setStorage(computation.msg.storageAddress, slot, value)
|
||||
|
|
Loading…
Reference in New Issue