Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ object StdSignedTransactionValidator extends SignedTransactionValidator {
)(implicit blockchainConfig: BlockchainConfig): Either[SignedTransactionError, SignedTransactionValid] = {
import stx.tx
val config = EvmConfig.forBlock(blockHeaderNumber, blockchainConfig)
val txIntrinsicGas = config.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit)
val txIntrinsicGas =
config.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit, Transaction.accessList(tx))
if (stx.tx.gasLimit >= txIntrinsicGas) Right(SignedTransactionValid)
else Left(TransactionNotEnoughGasForIntrinsicError(stx.tx.gasLimit, txIntrinsicGas))
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/scala/io/iohk/ethereum/domain/Transaction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ object Transaction {
case tx: TransactionWithAccessList => tx.copy(gasLimit = gl)
}

def accessList(tx: Transaction): List[AccessListItem] =
tx match {
case transaction: TransactionWithAccessList => transaction.accessList
case LegacyTransaction(nonce, gasPrice, gasLimit, receivingAddress, value, payload) => Nil
}

implicit class TransactionTypeValidator(val transactionType: Byte) extends AnyVal {
def isValidTransactionType: Boolean = transactionType >= MinAllowedType && transactionType <= MaxAllowedType
}
Expand Down Expand Up @@ -70,6 +76,7 @@ case class LegacyTransaction(
value: BigInt,
payload: ByteString
) extends Transaction {

override def toString: String =
s"LegacyTransaction {" +
s"nonce: $nonce " +
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import scala.util.Failure
import scala.util.Success
import scala.util.Try

import io.iohk.ethereum.domain.AccessListItem
import io.iohk.ethereum.ledger.InMemoryWorldStateProxy
import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage
import io.iohk.ethereum.utils.BlockchainConfig
Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/io/iohk/ethereum/extvm/VMServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ class VMServer(messageHandler: MessageHandler) extends Logger {
world = world,
initialAddressesToDelete = Set(),
evmConfig = vmConfig,
originalWorld = world
originalWorld = world,
// TODO ETCM-1202 use access list from CallContext
warmAddresses = Set.empty,
warmStorage = Set.empty
)
}

Expand Down
22 changes: 20 additions & 2 deletions src/main/scala/io/iohk/ethereum/vm/EvmConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import akka.util.ByteString

import io.iohk.ethereum

import io.iohk.ethereum.domain.AccessListItem
import io.iohk.ethereum.domain.TransactionWithAccessList
import io.iohk.ethereum.domain.UInt256
import io.iohk.ethereum.utils.BlockchainConfig
import io.iohk.ethereum.vm
Expand Down Expand Up @@ -196,12 +198,20 @@ case class EvmConfig(

/** Calculates transaction intrinsic gas. See YP section 6.2
*/
def calcTransactionIntrinsicGas(txData: ByteString, isContractCreation: Boolean): BigInt = {
def calcTransactionIntrinsicGas(
txData: ByteString,
isContractCreation: Boolean,
accessList: Seq[AccessListItem]
): BigInt = {
val txDataZero = txData.count(_ == 0)
val txDataNonZero = txData.length - txDataZero

val accessListPrice =
accessList.size * G_access_list_address +
accessList.map(_.storageKeys.size).sum * G_access_list_storage

txDataZero * G_txdatazero +
txDataNonZero * G_txdatanonzero +
txDataNonZero * G_txdatanonzero + accessListPrice +
(if (isContractCreation) G_txcreate else 0) +
G_transaction
}
Expand Down Expand Up @@ -262,9 +272,13 @@ object FeeSchedule {
override val G_copy = 3
override val G_blockhash = 20
override val G_extcode = 20

// note: the access list and cold/warm access do not exist until magneto hard fork
override val G_cold_sload = 2100
override val G_cold_account_access = 2600
override val G_warm_storage_read = 100
override val G_access_list_address = 2400
override val G_access_list_storage = 1900
}

class HomesteadFeeSchedule extends FrontierFeeSchedule {
Expand Down Expand Up @@ -300,6 +314,8 @@ object FeeSchedule {
class MagnetoFeeSchedule extends PhoenixFeeSchedule {
override val G_sload: BigInt = G_warm_storage_read
override val G_sreset: BigInt = 5000 - G_cold_sload
override val G_access_list_address: BigInt = 2400
override val G_access_list_storage: BigInt = 1900
}
}

Expand Down Expand Up @@ -342,4 +358,6 @@ trait FeeSchedule {
val G_cold_sload: BigInt
val G_cold_account_access: BigInt
val G_warm_storage_read: BigInt
val G_access_list_address: BigInt
val G_access_list_storage: BigInt
}
8 changes: 6 additions & 2 deletions src/main/scala/io/iohk/ethereum/vm/OpCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,9 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
world = world1,
initialAddressesToDelete = state.addressesToDelete,
evmConfig = state.config,
originalWorld = state.originalWorld
originalWorld = state.originalWorld,
warmAddresses = state.accessedAddresses,
warmStorage = state.accessedStorageKeys
)

val ((result, newAddress), stack2) = this match {
Expand Down Expand Up @@ -1079,7 +1081,9 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de
initialAddressesToDelete = state.addressesToDelete,
evmConfig = state.config,
staticCtx = static,
originalWorld = state.originalWorld
originalWorld = state.originalWorld,
warmAddresses = state.accessedAddresses,
warmStorage = state.accessedStorageKeys
)

val result = state.vm.call(context, owner)
Expand Down
13 changes: 9 additions & 4 deletions src/main/scala/io/iohk/ethereum/vm/ProgramContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ object ProgramContext {
world: W,
evmConfig: EvmConfig
): ProgramContext[W, S] = {

import stx.tx
val gasLimit = tx.gasLimit - evmConfig.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit)
val accessList = Transaction.accessList(tx)
val gasLimit =
tx.gasLimit - evmConfig.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit, accessList)

ProgramContext(
callerAddr = senderAddress,
Expand All @@ -31,7 +32,9 @@ object ProgramContext {
world = world,
initialAddressesToDelete = Set(),
evmConfig = evmConfig,
originalWorld = world
originalWorld = world,
warmAddresses = accessList.map(_.address).toSet,
warmStorage = accessList.flatMap(i => i.storageKeys.map((i.address, _))).toSet
)
}
}
Expand Down Expand Up @@ -81,5 +84,7 @@ case class ProgramContext[W <: WorldStateProxy[W, S], S <: Storage[S]](
initialAddressesToDelete: Set[Address],
evmConfig: EvmConfig,
staticCtx: Boolean = false,
originalWorld: W
originalWorld: W,
warmAddresses: Set[Address],
warmStorage: Set[(Address, BigInt)]
)
5 changes: 3 additions & 2 deletions src/main/scala/io/iohk/ethereum/vm/ProgramState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.iohk.ethereum.vm

import akka.util.ByteString

import io.iohk.ethereum.domain.AccessListItem
import io.iohk.ethereum.domain.Address
import io.iohk.ethereum.domain.TxLogEntry
import io.iohk.ethereum.domain.UInt256
Expand All @@ -23,8 +24,8 @@ object ProgramState {
accessedAddresses = PrecompiledContracts.getContracts(context).keySet ++ Set(
context.originAddr,
context.recipientAddr.getOrElse(context.callerAddr)
),
accessedStorageKeys = Set.empty
) ++ context.warmAddresses,
accessedStorageKeys = context.warmStorage
)
}

Expand Down
6 changes: 5 additions & 1 deletion src/main/scala/io/iohk/ethereum/vm/VM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import akka.util.ByteString

import scala.annotation.tailrec

import io.iohk.ethereum.domain.AccessListItem
import io.iohk.ethereum.domain.Address
import io.iohk.ethereum.domain.UInt256
import io.iohk.ethereum.utils.Logger
Expand Down Expand Up @@ -63,7 +64,10 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
/** Contract creation - Λ function in YP
* salt is used to create contract by CREATE2 opcode. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md
*/
private[vm] def create(context: PC, salt: Option[UInt256] = None): (PR, Address) =
private[vm] def create(
context: PC,
salt: Option[UInt256] = None
): (PR, Address) =
if (!isValidCall(context))
(invalidCallResult(context), Address(0))
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class StdSignedLegacyTransactionValidatorSpec extends AnyFlatSpec with Matchers
it should "report as invalid a tx with too low gas limit for intrinsic gas" in {
val txIntrinsicGas = EvmConfig
.forBlock(blockHeaderAfterHomestead.number, blockchainConfig)
.calcTransactionIntrinsicGas(txAfterHomestead.payload, txAfterHomestead.isContractInit)
.calcTransactionIntrinsicGas(txAfterHomestead.payload, txAfterHomestead.isContractInit, Nil)
val txWithInvalidGasLimit = txAfterHomestead.copy(gasLimit = txIntrinsicGas / 2)
val signedTxWithInvalidGasLimit = signedTxAfterHomestead.copy(tx = txWithInvalidGasLimit)
validateStx(signedTxWithInvalidGasLimit, fromBeforeHomestead = false) match {
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/io/iohk/ethereum/vm/CallOpFixture.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) {
world = worldWithExtAccount,
initialAddressesToDelete = Set(),
evmConfig = config,
originalWorld = worldWithExtAccount
originalWorld = worldWithExtAccount,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

case class ExecuteCall(
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/io/iohk/ethereum/vm/CreateOpcodeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty
world = initWorld,
initialAddressesToDelete = Set(),
evmConfig = config,
originalWorld = initWorld
originalWorld = initWorld,
warmAddresses = Set.empty,
warmStorage = Set.empty
)
}

Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/io/iohk/ethereum/vm/Generators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ object Generators extends ObjectGenerators {
world = world,
initialAddressesToDelete = Set(),
evmConfig = evmConfig,
originalWorld = world
originalWorld = world,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

env = ExecEnv(context, code, ownerAddr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,9 @@ trait OpCodeGasSpecPostEip2929 extends AnyFunSuite with OpCodeTesting with Match
world = defaultWorld,
initialAddressesToDelete = Set(),
evmConfig = config,
originalWorld = defaultWorld
originalWorld = defaultWorld,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

val env = ExecEnv(context, ByteString(Hex.decode(code)), context.originAddr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ class PrecompiledContractsSpec
world = world,
initialAddressesToDelete = Set(),
evmConfig = EvmConfig.PostEIP161ConfigBuilder(blockchainConfig),
originalWorld = world
originalWorld = world,
warmAddresses = Set.empty,
warmStorage = Set.empty
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ trait TestSetup {
world = world,
initialAddressesToDelete = Set(),
evmConfig = eipToCheck.config,
originalWorld = world
originalWorld = world,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

def prepareProgramState(
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/io/iohk/ethereum/vm/ShiftingOpCodeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ class ShiftingOpCodeSpec extends AnyWordSpec with Matchers with ScalaCheckProper
world = world,
initialAddressesToDelete = Set(),
evmConfig = config,
originalWorld = world
originalWorld = world,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

def prepareProgramState(
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/io/iohk/ethereum/vm/VMSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers {
world = world,
initialAddressesToDelete = Set(),
evmConfig = evmConfig,
originalWorld = world
originalWorld = world,
warmAddresses = Set.empty,
warmStorage = Set.empty
)

def recipientAddr: Option[Address]
Expand Down