@@ -13,6 +13,7 @@ import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks
1313import io .iohk .ethereum .vm .BlockchainConfigForEvm .EtcForks .EtcFork
1414import io .iohk .ethereum .vm .BlockchainConfigForEvm .EthForks
1515import io .iohk .ethereum .vm .BlockchainConfigForEvm .EthForks .EthFork
16+ import io .iohk .ethereum .vm .BlockchainConfigForEvm ._
1617
1718// scalastyle:off magic.number
1819// scalastyle:off number.of.types
@@ -171,7 +172,7 @@ object OpCode {
171172 * @param delta number of words to be popped from stack
172173 * @param alpha number of words to be pushed to stack
173174 */
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 )
175176 extends Product
176177 with Serializable {
177178 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
184185 else if (state.stack.size - delta + alpha > state.stack.maxSize)
185186 state.withError(StackOverflow )
186187 else {
187- val constGas : BigInt = constGasFn(state.config.feeSchedule)
188-
189- val gas : BigInt = constGas + varGas(state)
188+ val gas : BigInt = calcGas(state)
190189 if (gas > state.gas)
191190 state.copy(gas = 0 ).withError(OutOfGas )
192191 else
193192 exec(state).spendGas(gas)
194193 }
195194
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+
196202 protected def varGas [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): BigInt
197203
198204 protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ]
199205
200206 protected def availableInContext [W <: WorldStateProxy [W , S ], S <: Storage [S ]]: ProgramState [W , S ] => Boolean = _ =>
201207 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+
202232}
203233
204234sealed trait ConstGas { self : OpCode =>
@@ -210,8 +240,8 @@ case object STOP extends OpCode(0x00, 0, 0, _.G_zero) with ConstGas {
210240 state.withReturnData(ByteString .empty).halt
211241}
212242
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 )
215245 with ConstGas {
216246
217247 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
222252 }
223253}
224254
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 ) {
227257
228258 protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
229259 val (Seq (a, b), stack1) = state.stack.pop(2 )
@@ -233,9 +263,9 @@ sealed abstract class BinaryOp(code: Int, constGasFn: FeeSchedule => BigInt)(val
233263 }
234264}
235265
236- sealed abstract class TernaryOp (code : Int , constGasFn : FeeSchedule => BigInt )(
266+ sealed abstract class TernaryOp (code : Int , baseGasFn : FeeSchedule => BigInt )(
237267 val f : (UInt256 , UInt256 , UInt256 ) => UInt256
238- ) extends OpCode (code.toByte, 3 , 1 , constGasFn ) {
268+ ) extends OpCode (code.toByte, 3 , 1 , baseGasFn ) {
239269
240270 protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
241271 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 {
365395 }
366396}
367397
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+
369400 protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
370401 val (accountAddress, stack1) = state.stack.pop
371402 val address = Address (accountAddress)
@@ -395,7 +426,12 @@ case object EXTCODEHASH extends OpCode(0x3f, 1, 1, _.G_balance) with ConstGas {
395426 }
396427
397428 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)
399435 }
400436}
401437
@@ -452,29 +488,42 @@ case object CODECOPY extends OpCode(0x39, 3, 0, _.G_verylow) {
452488
453489case object GASPRICE extends ConstOp (0x3a )(_.env.gasPrice)
454490
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 {
456492 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
459496 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)
461503 }
462504}
463505
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+
465508 protected def exec [W <: WorldStateProxy [W , S ], S <: Storage [S ]](state : ProgramState [W , S ]): ProgramState [W , S ] = {
466509 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)
468512 val mem1 = state.memory.store(memOffset, codeCopy)
469- state.withStack(stack1).withMemory(mem1).step()
513+ state.withStack(stack1).withMemory(mem1).addAccessedAddress(addr). step()
470514 }
471515
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 = {
473517 val (Seq (_, memOffset, _, size), _) = state.stack.pop(4 )
474518 val memCost = state.config.calcMemCost(state.memory.size, memOffset, size)
475519 val copyCost = state.config.feeSchedule.G_copy * wordsForBytes(size)
476520 memCost + copyCost
477521 }
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+ }
478527}
479528
480529case object RETURNDATASIZE extends ConstOp (0x3d )(_.returnData.size)
@@ -845,7 +894,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
845894
846895 // FIXME: to avoid calculating this twice, we could adjust state.gas prior to execution in OpCode#execute
847896 // 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))
849898 val startGas = state.config.gasCap(availableGas)
850899 val (initCode, memory1) = state.memory.load(inOffset, inSize)
851900 val world1 = state.world.increaseNonce(state.ownAddress)
@@ -885,6 +934,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
885934 .withWorld(world2)
886935 .withStack(resultStack)
887936 .withReturnData(returnData)
937+ .addAccessedAddress(newAddress)
888938 .step()
889939
890940 case None =>
@@ -902,6 +952,7 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
902952 .withMemory(memory1)
903953 .withInternalTxs(internalTx +: result.internalTxs)
904954 .withReturnData(ByteString .empty)
955+ .addAccessedAddress(newAddress)
905956 .step()
906957 }
907958 }
0 commit comments