Skip to content

Commit 8873d39

Browse files
strauss-mAurélien Richez
andauthored
[ETCM-1165] use tx1 accesslist in evm (#1119)
* compute initial access list price * keep initial warm status in context * fix tests * add ticket number in todo * move magneto comment up in fee schedule * formatAll Co-authored-by: Aurélien Richez <aurelien.richez@iohk.io>
1 parent d21071a commit 8873d39

18 files changed

+82
-22
lines changed

src/main/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidator.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ object StdSignedTransactionValidator extends SignedTransactionValidator {
117117
)(implicit blockchainConfig: BlockchainConfig): Either[SignedTransactionError, SignedTransactionValid] = {
118118
import stx.tx
119119
val config = EvmConfig.forBlock(blockHeaderNumber, blockchainConfig)
120-
val txIntrinsicGas = config.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit)
120+
val txIntrinsicGas =
121+
config.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit, Transaction.accessList(tx))
121122
if (stx.tx.gasLimit >= txIntrinsicGas) Right(SignedTransactionValid)
122123
else Left(TransactionNotEnoughGasForIntrinsicError(stx.tx.gasLimit, txIntrinsicGas))
123124
}

src/main/scala/io/iohk/ethereum/domain/Transaction.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ object Transaction {
3535
case tx: TransactionWithAccessList => tx.copy(gasLimit = gl)
3636
}
3737

38+
def accessList(tx: Transaction): List[AccessListItem] =
39+
tx match {
40+
case transaction: TransactionWithAccessList => transaction.accessList
41+
case LegacyTransaction(nonce, gasPrice, gasLimit, receivingAddress, value, payload) => Nil
42+
}
43+
3844
implicit class TransactionTypeValidator(val transactionType: Byte) extends AnyVal {
3945
def isValidTransactionType: Boolean = transactionType >= MinAllowedType && transactionType <= MaxAllowedType
4046
}
@@ -70,6 +76,7 @@ case class LegacyTransaction(
7076
value: BigInt,
7177
payload: ByteString
7278
) extends Transaction {
79+
7380
override def toString: String =
7481
s"LegacyTransaction {" +
7582
s"nonce: $nonce " +

src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import scala.util.Failure
1616
import scala.util.Success
1717
import scala.util.Try
1818

19+
import io.iohk.ethereum.domain.AccessListItem
1920
import io.iohk.ethereum.ledger.InMemoryWorldStateProxy
2021
import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage
2122
import io.iohk.ethereum.utils.BlockchainConfig

src/main/scala/io/iohk/ethereum/extvm/VMServer.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ class VMServer(messageHandler: MessageHandler) extends Logger {
151151
world = world,
152152
initialAddressesToDelete = Set(),
153153
evmConfig = vmConfig,
154-
originalWorld = world
154+
originalWorld = world,
155+
// TODO ETCM-1202 use access list from CallContext
156+
warmAddresses = Set.empty,
157+
warmStorage = Set.empty
155158
)
156159
}
157160

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import akka.util.ByteString
44

55
import io.iohk.ethereum
66

7+
import io.iohk.ethereum.domain.AccessListItem
8+
import io.iohk.ethereum.domain.TransactionWithAccessList
79
import io.iohk.ethereum.domain.UInt256
810
import io.iohk.ethereum.utils.BlockchainConfig
911
import io.iohk.ethereum.vm
@@ -196,12 +198,20 @@ case class EvmConfig(
196198

197199
/** Calculates transaction intrinsic gas. See YP section 6.2
198200
*/
199-
def calcTransactionIntrinsicGas(txData: ByteString, isContractCreation: Boolean): BigInt = {
201+
def calcTransactionIntrinsicGas(
202+
txData: ByteString,
203+
isContractCreation: Boolean,
204+
accessList: Seq[AccessListItem]
205+
): BigInt = {
200206
val txDataZero = txData.count(_ == 0)
201207
val txDataNonZero = txData.length - txDataZero
202208

209+
val accessListPrice =
210+
accessList.size * G_access_list_address +
211+
accessList.map(_.storageKeys.size).sum * G_access_list_storage
212+
203213
txDataZero * G_txdatazero +
204-
txDataNonZero * G_txdatanonzero +
214+
txDataNonZero * G_txdatanonzero + accessListPrice +
205215
(if (isContractCreation) G_txcreate else 0) +
206216
G_transaction
207217
}
@@ -262,9 +272,13 @@ object FeeSchedule {
262272
override val G_copy = 3
263273
override val G_blockhash = 20
264274
override val G_extcode = 20
275+
276+
// note: the access list and cold/warm access do not exist until magneto hard fork
265277
override val G_cold_sload = 2100
266278
override val G_cold_account_access = 2600
267279
override val G_warm_storage_read = 100
280+
override val G_access_list_address = 2400
281+
override val G_access_list_storage = 1900
268282
}
269283

270284
class HomesteadFeeSchedule extends FrontierFeeSchedule {
@@ -300,6 +314,8 @@ object FeeSchedule {
300314
class MagnetoFeeSchedule extends PhoenixFeeSchedule {
301315
override val G_sload: BigInt = G_warm_storage_read
302316
override val G_sreset: BigInt = 5000 - G_cold_sload
317+
override val G_access_list_address: BigInt = 2400
318+
override val G_access_list_storage: BigInt = 1900
303319
}
304320
}
305321

@@ -342,4 +358,6 @@ trait FeeSchedule {
342358
val G_cold_sload: BigInt
343359
val G_cold_account_access: BigInt
344360
val G_warm_storage_read: BigInt
361+
val G_access_list_address: BigInt
362+
val G_access_list_storage: BigInt
345363
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,9 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
973973
world = world1,
974974
initialAddressesToDelete = state.addressesToDelete,
975975
evmConfig = state.config,
976-
originalWorld = state.originalWorld
976+
originalWorld = state.originalWorld,
977+
warmAddresses = state.accessedAddresses,
978+
warmStorage = state.accessedStorageKeys
977979
)
978980

979981
val ((result, newAddress), stack2) = this match {
@@ -1079,7 +1081,9 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de
10791081
initialAddressesToDelete = state.addressesToDelete,
10801082
evmConfig = state.config,
10811083
staticCtx = static,
1082-
originalWorld = state.originalWorld
1084+
originalWorld = state.originalWorld,
1085+
warmAddresses = state.accessedAddresses,
1086+
warmStorage = state.accessedStorageKeys
10831087
)
10841088

10851089
val result = state.vm.call(context, owner)

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ object ProgramContext {
1212
world: W,
1313
evmConfig: EvmConfig
1414
): ProgramContext[W, S] = {
15-
1615
import stx.tx
17-
val gasLimit = tx.gasLimit - evmConfig.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit)
16+
val accessList = Transaction.accessList(tx)
17+
val gasLimit =
18+
tx.gasLimit - evmConfig.calcTransactionIntrinsicGas(tx.payload, tx.isContractInit, accessList)
1819

1920
ProgramContext(
2021
callerAddr = senderAddress,
@@ -31,7 +32,9 @@ object ProgramContext {
3132
world = world,
3233
initialAddressesToDelete = Set(),
3334
evmConfig = evmConfig,
34-
originalWorld = world
35+
originalWorld = world,
36+
warmAddresses = accessList.map(_.address).toSet,
37+
warmStorage = accessList.flatMap(i => i.storageKeys.map((i.address, _))).toSet
3538
)
3639
}
3740
}
@@ -81,5 +84,7 @@ case class ProgramContext[W <: WorldStateProxy[W, S], S <: Storage[S]](
8184
initialAddressesToDelete: Set[Address],
8285
evmConfig: EvmConfig,
8386
staticCtx: Boolean = false,
84-
originalWorld: W
87+
originalWorld: W,
88+
warmAddresses: Set[Address],
89+
warmStorage: Set[(Address, BigInt)]
8590
)

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

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

33
import akka.util.ByteString
44

5+
import io.iohk.ethereum.domain.AccessListItem
56
import io.iohk.ethereum.domain.Address
67
import io.iohk.ethereum.domain.TxLogEntry
78
import io.iohk.ethereum.domain.UInt256
@@ -23,8 +24,8 @@ object ProgramState {
2324
accessedAddresses = PrecompiledContracts.getContracts(context).keySet ++ Set(
2425
context.originAddr,
2526
context.recipientAddr.getOrElse(context.callerAddr)
26-
),
27-
accessedStorageKeys = Set.empty
27+
) ++ context.warmAddresses,
28+
accessedStorageKeys = context.warmStorage
2829
)
2930
}
3031

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import akka.util.ByteString
44

55
import scala.annotation.tailrec
66

7+
import io.iohk.ethereum.domain.AccessListItem
78
import io.iohk.ethereum.domain.Address
89
import io.iohk.ethereum.domain.UInt256
910
import io.iohk.ethereum.utils.Logger
@@ -63,7 +64,10 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
6364
/** Contract creation - Λ function in YP
6465
* salt is used to create contract by CREATE2 opcode. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md
6566
*/
66-
private[vm] def create(context: PC, salt: Option[UInt256] = None): (PR, Address) =
67+
private[vm] def create(
68+
context: PC,
69+
salt: Option[UInt256] = None
70+
): (PR, Address) =
6771
if (!isValidCall(context))
6872
(invalidCallResult(context), Address(0))
6973
else {

src/test/scala/io/iohk/ethereum/consensus/validators/std/StdSignedLegacyTransactionValidatorSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class StdSignedLegacyTransactionValidatorSpec extends AnyFlatSpec with Matchers
200200
it should "report as invalid a tx with too low gas limit for intrinsic gas" in {
201201
val txIntrinsicGas = EvmConfig
202202
.forBlock(blockHeaderAfterHomestead.number, blockchainConfig)
203-
.calcTransactionIntrinsicGas(txAfterHomestead.payload, txAfterHomestead.isContractInit)
203+
.calcTransactionIntrinsicGas(txAfterHomestead.payload, txAfterHomestead.isContractInit, Nil)
204204
val txWithInvalidGasLimit = txAfterHomestead.copy(gasLimit = txIntrinsicGas / 2)
205205
val signedTxWithInvalidGasLimit = signedTxAfterHomestead.copy(tx = txWithInvalidGasLimit)
206206
validateStx(signedTxWithInvalidGasLimit, fromBeforeHomestead = false) match {

0 commit comments

Comments
 (0)