diff --git a/nix/overlay.nix b/nix/overlay.nix index c8949f6c37..ce9a0bebc5 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -14,7 +14,7 @@ rev: final: prev: { # ourselves instead. mantis-extvm-pb = builtins.fetchGit { url = "https://github.com/input-output-hk/mantis-extvm-pb"; - rev = "8f52caba70afc95ce669e9d61f773468db54557e"; + rev = "ae19e1fd9d3c0deba63c894be128d67e9519fe1f"; }; writeBashChecked = final.writers.makeScriptWriter { diff --git a/src/main/protobuf/extvm b/src/main/protobuf/extvm index 8f52caba70..ae19e1fd9d 160000 --- a/src/main/protobuf/extvm +++ b/src/main/protobuf/extvm @@ -1 +1 @@ -Subproject commit 8f52caba70afc95ce669e9d61f773468db54557e +Subproject commit ae19e1fd9d3c0deba63c894be128d67e9519fe1f diff --git a/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala b/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala index 002f5748e9..debdcda7c4 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala @@ -105,6 +105,17 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag resultMsg: msg.CallResult ): ProgramResult[W, S] = { val updatedWorld = applyAccountChanges[W, S](world, resultMsg) + + val accessedResultTuple = resultMsg.accessList + .map { accessList => + val addresses: Set[Address] = accessList.addresses.map(a => a: Address).toSet + val locations: Set[(Address, BigInt)] = accessList.storageLocations.map { loc => + (loc.address: Address, loc.storageLocation: BigInt) + }.toSet + (addresses, locations) + } + .getOrElse((Set.empty[Address], Set.empty[(Address, BigInt)])) + ProgramResult( resultMsg.returnData, resultMsg.gasRemaining, @@ -114,9 +125,8 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag Nil, resultMsg.gasRefund, if (resultMsg.error) Some(OutOfGas) else None, - // FIXME handle accessed addresses and storage in extVM - Set.empty, - Set.empty + accessedResultTuple._1, + accessedResultTuple._2 ) } @@ -155,6 +165,23 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag case _ => Config.Empty } + val txType = + if (ctx.warmAddresses.isEmpty && ctx.warmStorage.isEmpty) msg.CallContext.TxType.LEGACY + else msg.CallContext.TxType.ACCESSLIST + + val extraData = txType match { + case msg.CallContext.TxType.LEGACY => msg.CallContext.ExtraData.Empty + case msg.CallContext.TxType.ACCESSLIST => + msg.CallContext.ExtraData.AccessList( + msg + .AccessListData() + .withAddresses(ctx.warmAddresses.toSeq.map(_.bytes)) + .withStorageLocations( + ctx.warmStorage.toSeq.map(x => msg.StorageEntry(address = x._1, storageLocation = x._2)) + ) + ) + } + msg.CallContext( callerAddr = ctx.callerAddr, recipientAddr = ctx.recipientAddr.map(_.bytes).getOrElse(ByteString.empty): ByteString, @@ -163,7 +190,9 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag gasPrice = ctx.gasPrice, gasProvided = ctx.startGas, blockHeader = Some(blockHeader), - config = config + config = config, + txType = txType, + extraData = extraData ) } @@ -178,6 +207,7 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag constantinopleBlockNumber = blockchainConfig.constantinopleBlockNumber, petersburgBlockNumber = blockchainConfig.petersburgBlockNumber, istanbulBlockNumber = blockchainConfig.istanbulBlockNumber, + berlinBlockNumber = blockchainConfig.berlinBlockNumber, maxCodeSize = blockchainConfig.maxCodeSize.map(bigintToGByteString).getOrElse(ByteString()), accountStartNonce = blockchainConfig.accountStartNonce, chainId = ByteString(blockchainConfig.chainId) diff --git a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala index 91a6c9d1e3..857f52a52e 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala @@ -24,6 +24,8 @@ import com.typesafe.config.ConfigFactory import io.iohk.ethereum.domain.Address import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.extvm.Implicits._ +import io.iohk.ethereum.extvm.msg.AccessListData +import io.iohk.ethereum.extvm.msg.StorageEntry import io.iohk.ethereum.utils._ import io.iohk.ethereum.vm.BlockchainConfigForEvm import io.iohk.ethereum.vm.EvmConfig @@ -106,6 +108,7 @@ class VMServer(messageHandler: MessageHandler) extends Logger { messageHandler.close() } + // scalastyle:off method.length private def constructContextFromMsg(contextMsg: msg.CallContext): ProgramContext[World, Storage] = { import ByteString.{empty => irrelevant} // used for irrelevant BlockHeader fields @@ -136,6 +139,10 @@ class VMServer(messageHandler: MessageHandler) extends Logger { val recipientAddr: Option[Address] = Option(contextMsg.recipientAddr).filterNot(_.isEmpty).map(bytes => Address(bytes: ByteString)) + val (warmAddresses: Set[Address], warmStorage: Set[(Address, BigInt)]) = contextMsg.extraData.accessList + .map(extractWarmAccessList) + .getOrElse((Set.empty[Address], Set.empty[(Address, BigInt)])) + ProgramContext( callerAddr = contextMsg.callerAddr, originAddr = contextMsg.callerAddr, @@ -152,11 +159,19 @@ class VMServer(messageHandler: MessageHandler) extends Logger { initialAddressesToDelete = Set(), evmConfig = vmConfig, originalWorld = world, - // TODO ETCM-1202 use access list from CallContext - warmAddresses = Set.empty, - warmStorage = Set.empty + warmAddresses = warmAddresses, + warmStorage = warmStorage ) } + // scalastyle:on method.length + + private def extractWarmAccessList(ald: AccessListData): (Set[Address], Set[(Address, BigInt)]) = { + val warmAddresses: Set[Address] = ald.addresses.toSet.map((bs: GByteString) => Address(bs: ByteString)) + val warmStorage: Set[(Address, BigInt)] = ald.storageLocations.toSet.map { (se: StorageEntry) => + (Address(se.address: ByteString), se.storageLocation: BigInt) + } + (warmAddresses, warmStorage) + } private def buildResultMsg(result: ProgramResult[World, Storage]): msg.CallResult = { diff --git a/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala index 217428a4bd..ea1b3fdc79 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala @@ -170,6 +170,7 @@ class VMClientSpec extends AnyFlatSpec with Matchers with MockFactory { constantinopleBlockNumber = forkBlockNumbers.constantinopleBlockNumber, petersburgBlockNumber = forkBlockNumbers.petersburgBlockNumber, istanbulBlockNumber = forkBlockNumbers.istanbulBlockNumber, + berlinBlockNumber = forkBlockNumbers.berlinBlockNumber, maxCodeSize = blockchainConfig.maxCodeSize.get, accountStartNonce = blockchainConfig.accountStartNonce, chainId = ByteString(blockchainConfig.chainId) diff --git a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala index 32198e8d63..7336800ce7 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala @@ -122,7 +122,7 @@ class VMServerSpec extends AnyFlatSpec with Matchers with MockFactory { chainId = ByteString(blockchainConfig.chainId) ) val ethereumConfigMsg: Hello.Config.EthereumConfig = msg.Hello.Config.EthereumConfig(ethereumConfig) - val helloMsg: Hello = msg.Hello(version = "2.1", config = ethereumConfigMsg) + val helloMsg: Hello = msg.Hello(version = "2.2", config = ethereumConfigMsg) val messageHandler: MessageHandler = mock[MessageHandler] val vmServer = new VMServer(messageHandler)