You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuweni.apache.org by to...@apache.org on 2022/01/09 08:39:45 UTC

[incubator-tuweni] branch main updated: Implement missing opcodes

This is an automated email from the ASF dual-hosted git repository.

toulmean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git


The following commit(s) were added to refs/heads/main by this push:
     new b60e463  Implement missing opcodes
     new 366a4b9  Merge pull request #354 from atoulme/implement_missing_opcodes
b60e463 is described below

commit b60e4633e96c203047f4e9304a2c4383a8e287d4
Author: Antoine Toulme <an...@lunar-ocean.com>
AuthorDate: Sat Jan 8 22:40:27 2022 -0800

    Implement missing opcodes
---
 .../apache/tuweni/evm/EthereumVirtualMachine.kt    |   4 +
 .../kotlin/org/apache/tuweni/evm/impl/EvmVmImpl.kt |   3 +-
 .../org/apache/tuweni/evm/impl/OpcodeRegistry.kt   |  12 +-
 .../org/apache/tuweni/evm/impl/berlin/OpCodes.kt   | 175 +++++++++++++--------
 .../org/apache/tuweni/evm/impl/istanbul/OpCodes.kt | 175 +++++++++++++--------
 5 files changed, 243 insertions(+), 126 deletions(-)

diff --git a/evm/src/main/kotlin/org/apache/tuweni/evm/EthereumVirtualMachine.kt b/evm/src/main/kotlin/org/apache/tuweni/evm/EthereumVirtualMachine.kt
index 2db6f7c..b9e3d33 100644
--- a/evm/src/main/kotlin/org/apache/tuweni/evm/EthereumVirtualMachine.kt
+++ b/evm/src/main/kotlin/org/apache/tuweni/evm/EthereumVirtualMachine.kt
@@ -495,6 +495,10 @@ val opcodes = mapOf<Byte, String>(
   Pair(0x39, "codecopy"),
   Pair(0x3a, "gasPrice"),
   Pair(0x3b, "extcodesize"),
+  Pair(0x3c, "extcodecopy"),
+  Pair(0x3d, "returndatasize"),
+  Pair(0x3e, "returndatacopy"),
+  Pair(0x3f, "extcodehash"),
   Pair(0x40, "blockhash"),
   Pair(0x41, "coinbase"),
   Pair(0x42, "timestamp"),
diff --git a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/EvmVmImpl.kt b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/EvmVmImpl.kt
index 2c1cdfa..7e1fd3d 100644
--- a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/EvmVmImpl.kt
+++ b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/EvmVmImpl.kt
@@ -76,7 +76,8 @@ class EvmVmImpl : EvmVm {
       }
       val currentOpcodeByte = code.get(current)
       current++
-      val result = opcode.execute(gasManager, hostContext, stack, msg, code, current, memory)
+      // TODO implement call and pass result
+      val result = opcode.execute(gasManager, hostContext, stack, msg, code, current, memory, null)
       logger.trace(
         ">> OPCODE: ${opcodes[currentOpcodeByte] ?: currentOpcodeByte.toString(16)} " +
           "gas: ${gasManager.gasLeft()} cost: ${gasManager.lastGasCost()}"
diff --git a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/OpcodeRegistry.kt b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/OpcodeRegistry.kt
index ba63e57..8a00580 100644
--- a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/OpcodeRegistry.kt
+++ b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/OpcodeRegistry.kt
@@ -68,6 +68,7 @@ import org.apache.tuweni.evm.impl.berlin.pc
 import org.apache.tuweni.evm.impl.berlin.pop
 import org.apache.tuweni.evm.impl.berlin.push
 import org.apache.tuweni.evm.impl.berlin.retuRn
+import org.apache.tuweni.evm.impl.berlin.returndatacopy
 import org.apache.tuweni.evm.impl.berlin.sdiv
 import org.apache.tuweni.evm.impl.berlin.selfdestruct
 import org.apache.tuweni.evm.impl.berlin.sgt
@@ -82,6 +83,8 @@ import org.apache.tuweni.evm.impl.berlin.sub
 import org.apache.tuweni.evm.impl.berlin.swap
 import org.apache.tuweni.evm.impl.berlin.timestamp
 import org.apache.tuweni.evm.impl.berlin.xor
+import org.apache.tuweni.evm.impl.berlin.extcodecopy
+import org.apache.tuweni.evm.impl.berlin.returndatasize
 
 fun interface Opcode {
   fun execute(
@@ -91,7 +94,8 @@ fun interface Opcode {
     msg: EVMMessage,
     code: Bytes,
     currentIndex: Int,
-    memory: Memory
+    memory: Memory,
+    callResult: Result?,
   ): Result?
 }
 
@@ -139,6 +143,9 @@ class OpcodeRegistry(val opcodes: Map<HardFork, Map<Byte, Opcode>>) {
       berlinOpcodes[0x39] = codecopy
       berlinOpcodes[0x3a] = gasPrice
       berlinOpcodes[0x3b] = extcodesize
+      berlinOpcodes[0x3c] = extcodecopy
+      berlinOpcodes[0x3d] = returndatasize
+      berlinOpcodes[0x3e] = returndatacopy
       berlinOpcodes[0x3f] = extcodehash
 
       berlinOpcodes[0x40] = blockhash
@@ -214,6 +221,9 @@ class OpcodeRegistry(val opcodes: Map<HardFork, Map<Byte, Opcode>>) {
       istanbulOpcodes[0x39] = org.apache.tuweni.evm.impl.istanbul.codecopy
       istanbulOpcodes[0x3a] = org.apache.tuweni.evm.impl.istanbul.gasPrice
       istanbulOpcodes[0x3b] = org.apache.tuweni.evm.impl.istanbul.extcodesize
+      istanbulOpcodes[0x3c] = org.apache.tuweni.evm.impl.istanbul.extcodecopy
+      istanbulOpcodes[0x3d] = org.apache.tuweni.evm.impl.istanbul.returndatasize
+      istanbulOpcodes[0x3e] = org.apache.tuweni.evm.impl.istanbul.returndatacopy
       istanbulOpcodes[0x3f] = org.apache.tuweni.evm.impl.istanbul.extcodehash
       istanbulOpcodes[0x40] = org.apache.tuweni.evm.impl.istanbul.blockhash
       istanbulOpcodes[0x41] = org.apache.tuweni.evm.impl.istanbul.coinbase
diff --git a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/berlin/OpCodes.kt b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/berlin/OpCodes.kt
index a3aee99..0a443a1 100644
--- a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/berlin/OpCodes.kt
+++ b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/berlin/OpCodes.kt
@@ -27,7 +27,7 @@ import org.apache.tuweni.evm.impl.Result
 import org.apache.tuweni.units.bigints.UInt256
 import org.apache.tuweni.units.ethereum.Gas
 
-val add = Opcode { gasManager, _, stack, _, _, _, _ ->
+val add = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -39,7 +39,7 @@ val add = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val addmod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val addmod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(8L)
   val operand1 = stack.pop()
   val operand2 = stack.pop()
@@ -52,7 +52,7 @@ val addmod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val not = Opcode { gasManager, _, stack, _, _, _, _ ->
+val not = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   if (null == item) {
@@ -63,7 +63,7 @@ val not = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val eq = Opcode { gasManager, _, stack, _, _, _, _ ->
+val eq = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -79,7 +79,7 @@ val eq = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val lt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val lt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -95,7 +95,7 @@ val lt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val slt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val slt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -111,7 +111,7 @@ val slt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val gt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val gt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -127,7 +127,7 @@ val gt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val sgt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sgt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -143,7 +143,7 @@ val sgt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val isZero = Opcode { gasManager, _, stack, _, _, _, _ ->
+val isZero = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   if (null == item) {
@@ -154,7 +154,7 @@ val isZero = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val and = Opcode { gasManager, _, stack, _, _, _, _ ->
+val and = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -166,13 +166,13 @@ val and = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val pop = Opcode { gasManager, _, stack, _, _, _, _ ->
+val pop = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(2L)
   stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   Result()
 }
 
-val or = Opcode { gasManager, _, stack, _, _, _, _ ->
+val or = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -184,7 +184,7 @@ val or = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val xor = Opcode { gasManager, _, stack, _, _, _, _ ->
+val xor = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -196,7 +196,7 @@ val xor = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val byte = Opcode { gasManager, _, stack, _, _, _, _ ->
+val byte = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val offset = stack.pop()
   val stackElement = stack.pop()
@@ -212,7 +212,7 @@ val byte = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mul = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mul = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -224,7 +224,7 @@ val mul = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -236,7 +236,7 @@ val mod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val smod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val smod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -248,7 +248,7 @@ val smod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mulmod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mulmod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(8L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -265,7 +265,7 @@ val mulmod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val sub = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sub = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -277,7 +277,7 @@ val sub = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val exp = Opcode { gasManager, _, stack, _, _, _, _ ->
+val exp = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   val number = stack.pop()
   val power = stack.pop()
   if (null == number || null == power) {
@@ -296,7 +296,7 @@ val exp = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val div = Opcode { gasManager, _, stack, _, _, _, _ ->
+val div = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -309,7 +309,7 @@ val div = Opcode { gasManager, _, stack, _, _, _, _ ->
 }
 
 fun push(length: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, code, currentIndex, _ ->
+  return Opcode { gasManager, _, stack, _, code, currentIndex, _, _ ->
     gasManager.add(3)
     val minLength = Math.min(length, code.size() - currentIndex)
     stack.push(Bytes32.leftPad(code.slice(currentIndex, minLength)))
@@ -318,7 +318,7 @@ fun push(length: Int): Opcode {
 }
 
 fun dup(index: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, _, _, _ ->
+  return Opcode { gasManager, _, stack, _, _, _, _, _ ->
     gasManager.add(3)
     val value = stack.get(index - 1) ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
     stack.push(value)
@@ -327,7 +327,7 @@ fun dup(index: Int): Opcode {
 }
 
 fun swap(index: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, _, _, _ ->
+  return Opcode { gasManager, _, stack, _, _, _, _, _ ->
     gasManager.add(3L)
     val eltN = stack.get(index) ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
     val elt0 = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -337,7 +337,7 @@ fun swap(index: Int): Opcode {
   }
 }
 
-val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   runBlocking {
     val key = stack.pop()
     val value = stack.pop()
@@ -375,7 +375,7 @@ val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   val key = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
 
   val address = msg.destination
@@ -388,16 +388,16 @@ val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   Result()
 }
 
-val stop = Opcode { gasManager, _, _, _, _, _, _ ->
+val stop = Opcode { gasManager, _, _, _, _, _, _, _ ->
   gasManager.add(0L)
   Result(EVMExecutionStatusCode.SUCCESS)
 }
 
-val invalid = Opcode { _, _, _, _, _, _, _ ->
+val invalid = Opcode { _, _, _, _, _, _, _, _ ->
   Result(EVMExecutionStatusCode.INVALID_INSTRUCTION)
 }
 
-val retuRn = Opcode { gasManager, _, stack, _, _, _, memory ->
+val retuRn = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val length = stack.pop()
   if (null == location || null == length) {
@@ -410,31 +410,31 @@ val retuRn = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result(EVMExecutionStatusCode.SUCCESS, output = output)
 }
 
-val address = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val address = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.destination))
   Result()
 }
 
-val origin = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val origin = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.sender))
   Result()
 }
 
-val caller = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val caller = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.sender))
   Result()
 }
 
-val callvalue = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val callvalue = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.value))
   Result()
 }
 
-val balance = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val balance = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
 
   val address = stack.pop()?.slice(12, 20)?.let { Address.fromBytes(it) }
     ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -451,49 +451,49 @@ val balance = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
   Result()
 }
 
-val pc = Opcode { gasManager, _, stack, _, _, currentIndex, _ ->
+val pc = Opcode { gasManager, _, stack, _, _, currentIndex, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(currentIndex.toLong() - 1))
   Result()
 }
 
-val gasPrice = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val gasPrice = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(hostContext.getGasPrice()))
   Result()
 }
 
-val gas = Opcode { gasManager, _, stack, _, _, _, _ ->
+val gas = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(gasManager.gasLeft().toLong()))
   Result()
 }
 
-val coinbase = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val coinbase = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(hostContext.getCoinbase()))
   Result()
 }
 
-val gasLimit = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val gasLimit = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(hostContext.getGasLimit()))
   Result()
 }
 
-val difficulty = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val difficulty = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(hostContext.getDifficulty())
   Result()
 }
 
-val number = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val number = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(hostContext.getBlockNumber()))
   Result()
 }
 
-val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(20)
   val number = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   if (!number.fitsLong() || number.toLong() < hostContext.getBlockNumber() - 256) {
@@ -504,13 +504,13 @@ val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
   Result()
 }
 
-val codesize = Opcode { gasManager, _, stack, _, code, _, _ ->
+val codesize = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(code.size().toLong()))
   Result()
 }
 
-val timestamp = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val timestamp = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(hostContext.timestamp())
   Result()
@@ -525,7 +525,7 @@ fun memoryCost(length: UInt256): Gas {
   return Gas.valueOf(3).multiply(len).add(base)
 }
 
-val codecopy = Opcode { gasManager, _, stack, _, code, _, memory ->
+val codecopy = Opcode { gasManager, _, stack, _, code, _, memory, _ ->
   val memOffset = stack.pop()
   val sourceOffset = stack.pop()
   val length = stack.pop()
@@ -545,7 +545,58 @@ val codecopy = Opcode { gasManager, _, stack, _, code, _, memory ->
   Result()
 }
 
-val mstore = Opcode { gasManager, _, stack, _, _, _, memory ->
+val extcodecopy = Opcode { gasManager, hostContext, stack, _, _, _, memory, _ ->
+  val address = stack.pop()
+  val memOffset = stack.pop()
+  val sourceOffset = stack.pop()
+  val length = stack.pop()
+  if (null == address || null == memOffset || null == sourceOffset || null == length) {
+    return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
+  }
+  val numWords: UInt256 = length.divideCeil(Bytes32.SIZE.toLong())
+  val copyCost = Gas.valueOf(3).multiply(Gas.valueOf(numWords)).add(Gas.valueOf(3))
+  val pre = org.apache.tuweni.evm.impl.istanbul.memoryCost(memory.size())
+  val post: Gas = org.apache.tuweni.evm.impl.istanbul.memoryCost(memory.newSize(memOffset, length))
+  val memoryCost = post.subtract(pre)
+
+  gasManager.add(copyCost.add(memoryCost))
+
+  runBlocking {
+    val code = hostContext.getCode(Address.fromBytes(address.slice(12, 20)))
+    memory.write(memOffset, sourceOffset, length, code)
+  }
+
+  Result()
+}
+
+val returndatasize = Opcode { gasManager, _, stack, _, _, _, _, callResult ->
+  gasManager.add(3)
+  stack.push(UInt256.valueOf(callResult?.output?.size()?.toLong() ?: 0L))
+  Result()
+}
+
+val returndatacopy = Opcode { gasManager, _, stack, _, _, _, memory, callResult ->
+  val memOffset = stack.pop()
+  val sourceOffset = stack.pop()
+  val length = stack.pop()
+  val returnData = callResult?.output ?: Bytes.EMPTY
+  if (null == memOffset || null == sourceOffset || null == length) {
+    return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
+  }
+  val numWords: UInt256 = length.divideCeil(Bytes32.SIZE.toLong())
+  val copyCost = Gas.valueOf(3).multiply(Gas.valueOf(numWords)).add(Gas.valueOf(3))
+  val pre = org.apache.tuweni.evm.impl.istanbul.memoryCost(memory.size())
+  val post = org.apache.tuweni.evm.impl.istanbul.memoryCost(memory.newSize(memOffset, length))
+  val memoryCost = post.subtract(pre)
+
+  gasManager.add(copyCost.add(memoryCost))
+
+  memory.write(memOffset, sourceOffset, length, returnData)
+
+  Result()
+}
+
+val mstore = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val value = stack.pop()
   if (null == location || null == value) {
@@ -560,7 +611,7 @@ val mstore = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory ->
+val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val value = stack.pop()
   if (null == location || null == value) {
@@ -575,7 +626,7 @@ val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val mload = Opcode { gasManager, _, stack, _, _, _, memory ->
+val mload = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   val pre = memoryCost(memory.size())
   val post: Gas = memoryCost(memory.newSize(location, UInt256.valueOf(32)))
@@ -586,7 +637,7 @@ val mload = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   gasManager.add(700)
   runBlocking {
     stack.push(UInt256.valueOf(hostContext.getCode(msg.destination).size().toLong()))
@@ -594,7 +645,7 @@ val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   gasManager.add(700)
   runBlocking {
     stack.push(Hash.keccak256(hostContext.getCode(msg.destination)))
@@ -602,19 +653,19 @@ val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val msize = Opcode { gasManager, _, stack, _, _, _, memory ->
+val msize = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   gasManager.add(2)
   stack.push(memory.allocatedBytes())
   Result()
 }
 
-val calldatasize = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val calldatasize = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(msg.inputData.size().toLong()))
   Result()
 }
 
-val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory ->
+val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory, _ ->
   val memOffset = stack.pop()
   val sourceOffset = stack.pop()
   val length = stack.pop()
@@ -634,7 +685,7 @@ val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory ->
   Result()
 }
 
-val calldataload = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val calldataload = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(3)
   val start = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   var set = false
@@ -657,7 +708,7 @@ val calldataload = Opcode { gasManager, _, stack, msg, _, _, _ ->
   Result()
 }
 
-val sha3 = Opcode { gasManager, _, stack, _, _, _, memory ->
+val sha3 = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val from = stack.pop()
   val length = stack.pop()
   if (null == from || null == length) {
@@ -691,7 +742,7 @@ fun computeValidJumpDestinations(code: Bytes): Set<Int> {
   return destinations
 }
 
-val jump = Opcode { gasManager, _, stack, _, code, _, _ ->
+val jump = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(8)
   val jumpDest = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   if (!jumpDest.fitsInt() || jumpDest.intValue() >= code.size()) {
@@ -704,7 +755,7 @@ val jump = Opcode { gasManager, _, stack, _, code, _, _ ->
   Result(newCodePosition = jumpDest.intValue())
 }
 
-val jumpi = Opcode { gasManager, _, stack, _, code, _, _ ->
+val jumpi = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(10)
   val jumpDest = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   val condition = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -721,13 +772,13 @@ val jumpi = Opcode { gasManager, _, stack, _, code, _, _ ->
   Result(newCodePosition = jumpDest.intValue())
 }
 
-val jumpdest = Opcode { gasManager, _, _, _, _, _, _ ->
+val jumpdest = Opcode { gasManager, _, _, _, _, _, _, _ ->
   gasManager.add(1)
   Result()
 }
 
 fun log(topics: Int): Opcode {
-  return Opcode { gasManager, hostContext, stack, msg, _, _, memory ->
+  return Opcode { gasManager, hostContext, stack, msg, _, _, memory, _ ->
     val location = stack.pop()
     val length = stack.pop()
     if (null == location || null == length) {
@@ -764,7 +815,7 @@ fun log(topics: Int): Opcode {
   }
 }
 
-val sdiv = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sdiv = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -776,7 +827,7 @@ val sdiv = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val signextend = Opcode { gasManager, _, stack, _, _, _, _ ->
+val signextend = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -801,7 +852,7 @@ val signextend = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val selfdestruct = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val selfdestruct = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   val recipientAddress = stack.pop()?.slice(12, 20)?.let { Address.fromBytes(it) } ?: return@Opcode Result(
     EVMExecutionStatusCode.STACK_UNDERFLOW
   )
diff --git a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/istanbul/OpCodes.kt b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/istanbul/OpCodes.kt
index 6c60a69..6fd0c01 100644
--- a/evm/src/main/kotlin/org/apache/tuweni/evm/impl/istanbul/OpCodes.kt
+++ b/evm/src/main/kotlin/org/apache/tuweni/evm/impl/istanbul/OpCodes.kt
@@ -27,7 +27,7 @@ import org.apache.tuweni.evm.impl.Result
 import org.apache.tuweni.units.bigints.UInt256
 import org.apache.tuweni.units.ethereum.Gas
 
-val add = Opcode { gasManager, _, stack, _, _, _, _ ->
+val add = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -39,7 +39,7 @@ val add = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val addmod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val addmod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(8L)
   val operand1 = stack.pop()
   val operand2 = stack.pop()
@@ -52,7 +52,7 @@ val addmod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val not = Opcode { gasManager, _, stack, _, _, _, _ ->
+val not = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   if (null == item) {
@@ -63,7 +63,7 @@ val not = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val eq = Opcode { gasManager, _, stack, _, _, _, _ ->
+val eq = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -79,7 +79,7 @@ val eq = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val lt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val lt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -95,7 +95,7 @@ val lt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val slt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val slt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -111,7 +111,7 @@ val slt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val gt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val gt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -127,7 +127,7 @@ val gt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val sgt = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sgt = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -143,7 +143,7 @@ val sgt = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val isZero = Opcode { gasManager, _, stack, _, _, _, _ ->
+val isZero = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   if (null == item) {
@@ -154,7 +154,7 @@ val isZero = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val and = Opcode { gasManager, _, stack, _, _, _, _ ->
+val and = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -166,13 +166,13 @@ val and = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val pop = Opcode { gasManager, _, stack, _, _, _, _ ->
+val pop = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(2L)
   stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   Result()
 }
 
-val or = Opcode { gasManager, _, stack, _, _, _, _ ->
+val or = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -184,7 +184,7 @@ val or = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val xor = Opcode { gasManager, _, stack, _, _, _, _ ->
+val xor = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -196,7 +196,7 @@ val xor = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val byte = Opcode { gasManager, _, stack, _, _, _, _ ->
+val byte = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val offset = stack.pop()
   val stackElement = stack.pop()
@@ -212,7 +212,7 @@ val byte = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mul = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mul = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -224,7 +224,7 @@ val mul = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -236,7 +236,7 @@ val mod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val smod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val smod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -248,7 +248,7 @@ val smod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val mulmod = Opcode { gasManager, _, stack, _, _, _, _ ->
+val mulmod = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(8L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -265,7 +265,7 @@ val mulmod = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val sub = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sub = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(3L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -277,7 +277,7 @@ val sub = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val exp = Opcode { gasManager, _, stack, _, _, _, _ ->
+val exp = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   val number = stack.pop()
   val power = stack.pop()
   if (null == number || null == power) {
@@ -296,7 +296,7 @@ val exp = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val div = Opcode { gasManager, _, stack, _, _, _, _ ->
+val div = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -309,7 +309,7 @@ val div = Opcode { gasManager, _, stack, _, _, _, _ ->
 }
 
 fun push(length: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, code, currentIndex, _ ->
+  return Opcode { gasManager, _, stack, _, code, currentIndex, _, _ ->
     gasManager.add(3)
     val minLength = Math.min(length, code.size() - currentIndex)
     stack.push(Bytes32.leftPad(code.slice(currentIndex, minLength)))
@@ -318,7 +318,7 @@ fun push(length: Int): Opcode {
 }
 
 fun dup(index: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, _, _, _ ->
+  return Opcode { gasManager, _, stack, _, _, _, _, _ ->
     gasManager.add(3)
     val value = stack.get(index - 1) ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
     stack.push(value)
@@ -327,7 +327,7 @@ fun dup(index: Int): Opcode {
 }
 
 fun swap(index: Int): Opcode {
-  return Opcode { gasManager, _, stack, _, _, _, _ ->
+  return Opcode { gasManager, _, stack, _, _, _, _, _ ->
     gasManager.add(3L)
     val eltN = stack.get(index) ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
     val elt0 = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -337,7 +337,7 @@ fun swap(index: Int): Opcode {
   }
 }
 
-val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   runBlocking {
     val key = stack.pop()
     val value = stack.pop()
@@ -375,7 +375,7 @@ val sstore = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   val key = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
 
   val address = msg.destination
@@ -387,15 +387,15 @@ val sload = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   Result()
 }
 
-val stop = Opcode { _, _, _, _, _, _, _ ->
+val stop = Opcode { _, _, _, _, _, _, _, _ ->
   Result(EVMExecutionStatusCode.SUCCESS)
 }
 
-val invalid = Opcode { _, _, _, _, _, _, _ ->
+val invalid = Opcode { _, _, _, _, _, _, _, _ ->
   Result(EVMExecutionStatusCode.INVALID_INSTRUCTION)
 }
 
-val retuRn = Opcode { gasManager, _, stack, _, _, _, memory ->
+val retuRn = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val length = stack.pop()
   if (null == location || null == length) {
@@ -408,31 +408,31 @@ val retuRn = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result(EVMExecutionStatusCode.SUCCESS, output = output)
 }
 
-val address = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val address = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.destination))
   Result()
 }
 
-val origin = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val origin = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.sender))
   Result()
 }
 
-val caller = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val caller = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.sender))
   Result()
 }
 
-val callvalue = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val callvalue = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(msg.value))
   Result()
 }
 
-val balance = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val balance = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
 
   val address = stack.pop()?.slice(12, 20)?.let { Address.fromBytes(it) }
     ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -444,49 +444,49 @@ val balance = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
   Result()
 }
 
-val pc = Opcode { gasManager, _, stack, _, _, currentIndex, _ ->
+val pc = Opcode { gasManager, _, stack, _, _, currentIndex, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(currentIndex.toLong() - 1))
   Result()
 }
 
-val gasPrice = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val gasPrice = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(hostContext.getGasPrice()))
   Result()
 }
 
-val gas = Opcode { gasManager, _, stack, _, _, _, _ ->
+val gas = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(gasManager.gasLeft().toLong()))
   Result()
 }
 
-val coinbase = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val coinbase = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(Bytes32.leftPad(hostContext.getCoinbase()))
   Result()
 }
 
-val gasLimit = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val gasLimit = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(hostContext.getGasLimit()))
   Result()
 }
 
-val difficulty = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val difficulty = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(hostContext.getDifficulty())
   Result()
 }
 
-val number = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val number = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(hostContext.getBlockNumber()))
   Result()
 }
 
-val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(20)
   val number = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   if (!number.fitsLong() || number.toLong() < hostContext.getBlockNumber() - 256) {
@@ -497,13 +497,13 @@ val blockhash = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
   Result()
 }
 
-val codesize = Opcode { gasManager, _, stack, _, code, _, _ ->
+val codesize = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(code.size().toLong()))
   Result()
 }
 
-val timestamp = Opcode { gasManager, hostContext, stack, _, _, _, _ ->
+val timestamp = Opcode { gasManager, hostContext, stack, _, _, _, _, _ ->
   gasManager.add(2)
   stack.push(hostContext.timestamp())
   Result()
@@ -518,7 +518,7 @@ fun memoryCost(length: UInt256): Gas {
   return Gas.valueOf(3).multiply(len).add(base)
 }
 
-val codecopy = Opcode { gasManager, _, stack, _, code, _, memory ->
+val codecopy = Opcode { gasManager, _, stack, _, code, _, memory, _ ->
   val memOffset = stack.pop()
   val sourceOffset = stack.pop()
   val length = stack.pop()
@@ -538,7 +538,58 @@ val codecopy = Opcode { gasManager, _, stack, _, code, _, memory ->
   Result()
 }
 
-val mstore = Opcode { gasManager, _, stack, _, _, _, memory ->
+val extcodecopy = Opcode { gasManager, hostContext, stack, _, _, _, memory, _ ->
+  val address = stack.pop()
+  val memOffset = stack.pop()
+  val sourceOffset = stack.pop()
+  val length = stack.pop()
+  if (null == address || null == memOffset || null == sourceOffset || null == length) {
+    return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
+  }
+  val numWords: UInt256 = length.divideCeil(Bytes32.SIZE.toLong())
+  val copyCost = Gas.valueOf(3).multiply(Gas.valueOf(numWords)).add(Gas.valueOf(3))
+  val pre = memoryCost(memory.size())
+  val post: Gas = memoryCost(memory.newSize(memOffset, length))
+  val memoryCost = post.subtract(pre)
+
+  gasManager.add(copyCost.add(memoryCost))
+
+  runBlocking {
+    val code = hostContext.getCode(Address.fromBytes(address.slice(12, 20)))
+    memory.write(memOffset, sourceOffset, length, code)
+  }
+
+  Result()
+}
+
+val returndatasize = Opcode { gasManager, _, stack, _, _, _, _, callResult ->
+  gasManager.add(3)
+  stack.push(UInt256.valueOf(callResult?.output?.size()?.toLong() ?: 0L))
+  Result()
+}
+
+val returndatacopy = Opcode { gasManager, _, stack, _, _, _, memory, callResult ->
+  val memOffset = stack.pop()
+  val sourceOffset = stack.pop()
+  val length = stack.pop()
+  val returnData = callResult?.output ?: Bytes.EMPTY
+  if (null == memOffset || null == sourceOffset || null == length) {
+    return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
+  }
+  val numWords: UInt256 = length.divideCeil(Bytes32.SIZE.toLong())
+  val copyCost = Gas.valueOf(3).multiply(Gas.valueOf(numWords)).add(Gas.valueOf(3))
+  val pre = memoryCost(memory.size())
+  val post = memoryCost(memory.newSize(memOffset, length))
+  val memoryCost = post.subtract(pre)
+
+  gasManager.add(copyCost.add(memoryCost))
+
+  memory.write(memOffset, sourceOffset, length, returnData)
+
+  Result()
+}
+
+val mstore = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val value = stack.pop()
   if (null == location || null == value) {
@@ -553,7 +604,7 @@ val mstore = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory ->
+val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop()
   val value = stack.pop()
   if (null == location || null == value) {
@@ -568,7 +619,7 @@ val mstore8 = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val mload = Opcode { gasManager, _, stack, _, _, _, memory ->
+val mload = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val location = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   val pre = memoryCost(memory.size())
   val post: Gas = memoryCost(memory.newSize(location, UInt256.valueOf(32)))
@@ -579,7 +630,7 @@ val mload = Opcode { gasManager, _, stack, _, _, _, memory ->
   Result()
 }
 
-val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   gasManager.add(700)
   runBlocking {
     stack.push(UInt256.valueOf(hostContext.getCode(msg.destination).size().toLong()))
@@ -587,7 +638,7 @@ val extcodesize = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   gasManager.add(700)
   runBlocking {
     stack.push(Hash.keccak256(hostContext.getCode(msg.destination)))
@@ -595,19 +646,19 @@ val extcodehash = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
   }
 }
 
-val msize = Opcode { gasManager, _, stack, _, _, _, memory ->
+val msize = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   gasManager.add(2)
   stack.push(memory.allocatedBytes())
   Result()
 }
 
-val calldatasize = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val calldatasize = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(2)
   stack.push(UInt256.valueOf(msg.inputData.size().toLong()))
   Result()
 }
 
-val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory ->
+val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory, _ ->
   val memOffset = stack.pop()
   val sourceOffset = stack.pop()
   val length = stack.pop()
@@ -627,7 +678,7 @@ val calldatacopy = Opcode { gasManager, _, stack, msg, _, _, memory ->
   Result()
 }
 
-val calldataload = Opcode { gasManager, _, stack, msg, _, _, _ ->
+val calldataload = Opcode { gasManager, _, stack, msg, _, _, _, _ ->
   gasManager.add(3)
   val start = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   var set = false
@@ -650,7 +701,7 @@ val calldataload = Opcode { gasManager, _, stack, msg, _, _, _ ->
   Result()
 }
 
-val sha3 = Opcode { gasManager, _, stack, _, _, _, memory ->
+val sha3 = Opcode { gasManager, _, stack, _, _, _, memory, _ ->
   val from = stack.pop()
   val length = stack.pop()
   if (null == from || null == length) {
@@ -684,7 +735,7 @@ fun computeValidJumpDestinations(code: Bytes): Set<Int> {
   return destinations
 }
 
-val jump = Opcode { gasManager, _, stack, _, code, _, _ ->
+val jump = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(8)
   val jumpDest = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   if (!jumpDest.fitsInt() || jumpDest.intValue() >= code.size()) {
@@ -697,7 +748,7 @@ val jump = Opcode { gasManager, _, stack, _, code, _, _ ->
   Result(newCodePosition = jumpDest.intValue())
 }
 
-val jumpi = Opcode { gasManager, _, stack, _, code, _, _ ->
+val jumpi = Opcode { gasManager, _, stack, _, code, _, _, _ ->
   gasManager.add(10)
   val jumpDest = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
   val condition = stack.pop() ?: return@Opcode Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
@@ -714,13 +765,13 @@ val jumpi = Opcode { gasManager, _, stack, _, code, _, _ ->
   Result(newCodePosition = jumpDest.intValue())
 }
 
-val jumpdest = Opcode { gasManager, _, _, _, _, _, _ ->
+val jumpdest = Opcode { gasManager, _, _, _, _, _, _, _ ->
   gasManager.add(1)
   Result()
 }
 
 fun log(topics: Int): Opcode {
-  return Opcode { gasManager, hostContext, stack, msg, _, _, memory ->
+  return Opcode { gasManager, hostContext, stack, msg, _, _, memory, _ ->
     val location = stack.pop()
     val length = stack.pop()
     if (null == location || null == length) {
@@ -757,7 +808,7 @@ fun log(topics: Int): Opcode {
   }
 }
 
-val sdiv = Opcode { gasManager, _, stack, _, _, _, _ ->
+val sdiv = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -769,7 +820,7 @@ val sdiv = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val signextend = Opcode { gasManager, _, stack, _, _, _, _ ->
+val signextend = Opcode { gasManager, _, stack, _, _, _, _, _ ->
   gasManager.add(5L)
   val item = stack.pop()
   val item2 = stack.pop()
@@ -794,7 +845,7 @@ val signextend = Opcode { gasManager, _, stack, _, _, _, _ ->
   }
 }
 
-val selfdestruct = Opcode { gasManager, hostContext, stack, msg, _, _, _ ->
+val selfdestruct = Opcode { gasManager, hostContext, stack, msg, _, _, _, _ ->
   val recipientAddress = stack.pop()?.slice(12, 20)?.let { Address.fromBytes(it) } ?: return@Opcode Result(
     EVMExecutionStatusCode.STACK_UNDERFLOW
   )

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tuweni.apache.org
For additional commands, e-mail: commits-help@tuweni.apache.org