@@ -13,6 +13,7 @@ import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks
13
13
import io .iohk .ethereum .vm .BlockchainConfigForEvm .EtcForks .EtcFork
14
14
import io .iohk .ethereum .vm .BlockchainConfigForEvm .EthForks
15
15
import io .iohk .ethereum .vm .BlockchainConfigForEvm .EthForks .EthFork
16
+ import io .iohk .ethereum .vm .BlockchainConfigForEvm ._
16
17
17
18
// scalastyle:off magic.number
18
19
// scalastyle:off number.of.types
@@ -171,7 +172,7 @@ object OpCode {
171
172
* @param delta number of words to be popped from stack
172
173
* @param alpha number of words to be pushed to stack
173
174
*/
174
- abstract class OpCode (val code : Byte , val delta : Int , val alpha : Int , val constGasFn : FeeSchedule => BigInt )
175
+ abstract class OpCode (val code : Byte , val delta : Int , val alpha : Int , val baseGasFn : FeeSchedule => BigInt )
175
176
extends Product
176
177
with Serializable {
177
178
def this (code : Int , pop : Int , push : Int , constGasFn : FeeSchedule => BigInt ) = this (code.toByte, pop, push, constGasFn)
@@ -184,21 +185,50 @@ abstract class OpCode(val code: Byte, val delta: Int, val alpha: Int, val constG
184
185
else if (state.stack.size - delta + alpha > state.stack.maxSize)
185
186
state.withError(StackOverflow )
186
187
else {
187
- val constGas : BigInt = constGasFn(state.config.feeSchedule)
188
-
189
- val gas : BigInt = constGas + varGas(state)
188
+ val gas : BigInt = calcGas(state)
190
189
if (gas > state.gas)
191
190
state.copy(gas = 0 ).withError(OutOfGas )
192
191
else
193
192
exec(state).spendGas(gas)
194
193
}
195
194
195
+ protected def calcGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt =
196
+ baseGas(state) + varGas(state)
197
+
198
+ protected def baseGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt = baseGasFn(
199
+ state.config.feeSchedule
200
+ )
201
+
196
202
protected def varGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt
197
203
198
204
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ]
199
205
200
206
protected def availableInContext [W <: WorldStateProxy [W , S ], S <: Storage [S ]]: ProgramState [W , S ] => Boolean = _ =>
201
207
true
208
+
209
+ }
210
+
211
+ trait AddrAccessGas { self : OpCode =>
212
+
213
+ private def coldGasFn : FeeSchedule => BigInt = _.G_cold_account_access
214
+ private def warmGasFn : FeeSchedule => BigInt = _.G_warm_storage_read
215
+
216
+ override protected def baseGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt = {
217
+ val currentBlockNumber = state.env.blockHeader.number
218
+ val etcFork = state.config.blockchainConfig.etcForkForBlockNumber(currentBlockNumber)
219
+ val eip2929Enabled = isEip2929Enabled(etcFork)
220
+ if (eip2929Enabled) {
221
+ val addr = address(state)
222
+ if (state.accessedAddresses.contains(addr))
223
+ warmGasFn(state.config.feeSchedule)
224
+ else
225
+ coldGasFn(state.config.feeSchedule)
226
+ } else
227
+ baseGasFn(state.config.feeSchedule)
228
+ }
229
+
230
+ protected def address [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): Address
231
+
202
232
}
203
233
204
234
sealed trait ConstGas { self : OpCode =>
@@ -210,8 +240,8 @@ case object STOP extends OpCode(0x00, 0, 0, _.G_zero) with ConstGas {
210
240
state.withReturnData(ByteString .empty).halt
211
241
}
212
242
213
- sealed abstract class UnaryOp (code : Int , constGasFn : FeeSchedule => BigInt )(val f : UInt256 => UInt256 )
214
- extends OpCode (code, 1 , 1 , constGasFn )
243
+ sealed abstract class UnaryOp (code : Int , baseGasFn : FeeSchedule => BigInt )(val f : UInt256 => UInt256 )
244
+ extends OpCode (code, 1 , 1 , baseGasFn )
215
245
with ConstGas {
216
246
217
247
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
@@ -222,8 +252,8 @@ sealed abstract class UnaryOp(code: Int, constGasFn: FeeSchedule => BigInt)(val
222
252
}
223
253
}
224
254
225
- sealed abstract class BinaryOp (code : Int , constGasFn : FeeSchedule => BigInt )(val f : (UInt256 , UInt256 ) => UInt256 )
226
- extends OpCode (code.toByte, 2 , 1 , constGasFn ) {
255
+ sealed abstract class BinaryOp (code : Int , baseGasFn : FeeSchedule => BigInt )(val f : (UInt256 , UInt256 ) => UInt256 )
256
+ extends OpCode (code.toByte, 2 , 1 , baseGasFn ) {
227
257
228
258
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
229
259
val (Seq (a, b), stack1) = state.stack.pop(2 )
@@ -233,9 +263,9 @@ sealed abstract class BinaryOp(code: Int, constGasFn: FeeSchedule => BigInt)(val
233
263
}
234
264
}
235
265
236
- sealed abstract class TernaryOp (code : Int , constGasFn : FeeSchedule => BigInt )(
266
+ sealed abstract class TernaryOp (code : Int , baseGasFn : FeeSchedule => BigInt )(
237
267
val f : (UInt256 , UInt256 , UInt256 ) => UInt256
238
- ) extends OpCode (code.toByte, 3 , 1 , constGasFn ) {
268
+ ) extends OpCode (code.toByte, 3 , 1 , baseGasFn ) {
239
269
240
270
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
241
271
val (Seq (a, b, c), stack1) = state.stack.pop(3 )
@@ -365,7 +395,8 @@ case object BALANCE extends OpCode(0x31, 1, 1, _.G_balance) with ConstGas {
365
395
}
366
396
}
367
397
368
- case object EXTCODEHASH extends OpCode (0x3f , 1 , 1 , _.G_balance ) with ConstGas {
398
+ case object EXTCODEHASH extends OpCode (0x3f , 1 , 1 , _.G_balance ) with AddrAccessGas with ConstGas {
399
+
369
400
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
370
401
val (accountAddress, stack1) = state.stack.pop
371
402
val address = Address (accountAddress)
@@ -395,7 +426,12 @@ case object EXTCODEHASH extends OpCode(0x3f, 1, 1, _.G_balance) with ConstGas {
395
426
}
396
427
397
428
val stack2 = stack1.push(codeHash)
398
- state.withStack(stack2).step()
429
+ state.withStack(stack2).addAccessedAddress(address).step()
430
+ }
431
+
432
+ protected def address [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): Address = {
433
+ val (accountAddress, _) = state.stack.pop
434
+ Address (accountAddress)
399
435
}
400
436
}
401
437
@@ -452,29 +488,42 @@ case object CODECOPY extends OpCode(0x39, 3, 0, _.G_verylow) {
452
488
453
489
case object GASPRICE extends ConstOp (0x3a )(_.env.gasPrice)
454
490
455
- case object EXTCODESIZE extends OpCode (0x3b , 1 , 1 , _.G_extcode ) with ConstGas {
491
+ case object EXTCODESIZE extends OpCode (0x3b , 1 , 1 , _.G_extcode ) with AddrAccessGas with ConstGas {
456
492
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
457
- val (addr, stack1) = state.stack.pop
458
- val codeSize = state.world.getCode(Address (addr)).size
493
+ val (addrUint, stack1) = state.stack.pop
494
+ val addr = Address (addrUint)
495
+ val codeSize = state.world.getCode(addr).size
459
496
val stack2 = stack1.push(UInt256 (codeSize))
460
- state.withStack(stack2).step()
497
+ state.withStack(stack2).addAccessedAddress(addr).step()
498
+ }
499
+
500
+ protected def address [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): Address = {
501
+ val (accountAddress, _) = state.stack.pop
502
+ Address (accountAddress)
461
503
}
462
504
}
463
505
464
- case object EXTCODECOPY extends OpCode (0x3c , 4 , 0 , _.G_extcode ) {
506
+ case object EXTCODECOPY extends OpCode (0x3c , 4 , 0 , _.G_extcode ) with AddrAccessGas {
507
+
465
508
protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
466
509
val (Seq (address, memOffset, codeOffset, size), stack1) = state.stack.pop(4 )
467
- val codeCopy = OpCode .sliceBytes(state.world.getCode(Address (address)), codeOffset, size)
510
+ val addr = Address (address)
511
+ val codeCopy = OpCode .sliceBytes(state.world.getCode(addr), codeOffset, size)
468
512
val mem1 = state.memory.store(memOffset, codeCopy)
469
- state.withStack(stack1).withMemory(mem1).step()
513
+ state.withStack(stack1).withMemory(mem1).addAccessedAddress(addr). step()
470
514
}
471
515
472
- protected def varGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt = {
516
+ override protected def varGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt = {
473
517
val (Seq (_, memOffset, _, size), _) = state.stack.pop(4 )
474
518
val memCost = state.config.calcMemCost(state.memory.size, memOffset, size)
475
519
val copyCost = state.config.feeSchedule.G_copy * wordsForBytes(size)
476
520
memCost + copyCost
477
521
}
522
+
523
+ protected def address [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): Address = {
524
+ val (Seq (accountAddress, _, _, _), _) = state.stack.pop(4 )
525
+ Address (accountAddress)
526
+ }
478
527
}
479
528
480
529
case object RETURNDATASIZE extends ConstOp (0x3d )(_.returnData.size)
@@ -845,7 +894,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
845
894
846
895
// FIXME: to avoid calculating this twice, we could adjust state.gas prior to execution in OpCode#execute
847
896
// not sure how this would affect other opcodes [EC-243]
848
- val availableGas = state.gas - (constGasFn (state.config.feeSchedule) + varGas(state))
897
+ val availableGas = state.gas - (baseGasFn (state.config.feeSchedule) + varGas(state))
849
898
val startGas = state.config.gasCap(availableGas)
850
899
val (initCode, memory1) = state.memory.load(inOffset, inSize)
851
900
val world1 = state.world.increaseNonce(state.ownAddress)
@@ -885,6 +934,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
885
934
.withWorld(world2)
886
935
.withStack(resultStack)
887
936
.withReturnData(returnData)
937
+ .addAccessedAddress(newAddress)
888
938
.step()
889
939
890
940
case None =>
@@ -902,6 +952,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
902
952
.withMemory(memory1)
903
953
.withInternalTxs(internalTx +: result.internalTxs)
904
954
.withReturnData(ByteString .empty)
955
+ .addAccessedAddress(newAddress)
905
956
.step()
906
957
}
907
958
}
0 commit comments