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 69581922 Add code to validate EVM code
     new 7a25e760 Merge pull request #407 from atoulme/validate_code
69581922 is described below

commit 695819226130becfda4cdca428baf070436d22a6
Author: Antoine Toulme <anto...@lunar-ocean.com>
AuthorDate: Sat May 28 23:15:25 2022 -0700

    Add code to validate EVM code
---
 .../main/kotlin/org/apache/tuweni/evmdsl/Code.kt   |  34 +++
 .../org/apache/tuweni/evmdsl/Instructions.kt       | 239 ++++++++++++++-------
 .../kotlin/org/apache/tuweni/evmdsl/CodeTest.kt    |  45 ++++
 3 files changed, 243 insertions(+), 75 deletions(-)

diff --git a/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Code.kt 
b/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Code.kt
index c1b740d7..abe1db3e 100644
--- a/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Code.kt
+++ b/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Code.kt
@@ -47,6 +47,32 @@ class Code(val instructions: List<Instruction>) {
     }
   }
 
+  fun validate(): CodeValidationError? {
+    var stackSize = 0
+    val visited = mutableSetOf<Int>()
+    var index = 0
+    while (visited.add(index)) {
+      val currentInstruction = instructions.getOrNull(index) ?: break
+      if (currentInstruction.stackItemsNeeded() > stackSize) {
+        return CodeValidationError(currentInstruction, index, 
Error.STACK_UNDERFLOW)
+      }
+      stackSize += currentInstruction.stackItemsProduced()
+      if (stackSize > 1024) {
+        return CodeValidationError(currentInstruction, index, 
Error.STACK_OVERFLOW)
+      }
+      if (currentInstruction is Invalid) {
+        return CodeValidationError(currentInstruction, index, 
Error.HIT_INVALID_OPCODE)
+      }
+      // TODO cannot follow jumps right now.
+      if (currentInstruction == Jump || currentInstruction == Jumpi) {
+        break
+      }
+
+      index++
+    }
+    return null
+  }
+
   fun toBytes(): Bytes {
     return Bytes.wrap(instructions.map { it.toBytes() })
   }
@@ -55,3 +81,11 @@ class Code(val instructions: List<Instruction>) {
     return instructions.map { it.toString() }.joinToString("\n")
   }
 }
+
+enum class Error {
+  STACK_UNDERFLOW,
+  STACK_OVERFLOW,
+  HIT_INVALID_OPCODE
+}
+
+data class CodeValidationError(val instruction: Instruction, val index: Int, 
val error: Error)
diff --git a/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Instructions.kt 
b/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Instructions.kt
index 7a6287cd..04be3e10 100644
--- a/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Instructions.kt
+++ b/evm-dsl/src/main/kotlin/org/apache/tuweni/evmdsl/Instructions.kt
@@ -25,6 +25,12 @@ import org.apache.tuweni.bytes.Bytes
 interface Instruction {
 
   fun toBytes(): Bytes
+
+  fun stackItemsNeeded() = stackItemsConsumed()
+
+  fun stackItemsConsumed(): Int
+
+  fun stackItemsProduced(): Int
 }
 
 data class InstructionModel(val opcode: Byte, val additionalBytesToRead: Int = 
0, val creator: (code: Bytes, index: Int) -> Instruction)
@@ -173,469 +179,552 @@ class Push(val bytesToPush: Bytes) : Instruction {
   }
 
   override fun toBytes(): Bytes = Bytes.wrap(Bytes.of((0x60 + 
bytesToPush.size() - 1).toByte()), bytesToPush)
-
   override fun toString(): String = "PUSH ${bytesToPush.toHexString()}"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
-class Invalid(val invalidByte: kotlin.Byte) : Instruction {
-
+data class Invalid(val invalidByte: Byte) : Instruction {
   override fun toBytes(): Bytes = Bytes.of(invalidByte)
-
-  override fun toString(): String = "INVALID 0x${invalidByte.toString(16)}"
+  override fun toString(): String = "INVALID ${Bytes.of(invalidByte)}"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 0
 }
 
 object Stop : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x00)
-
   override fun toString(): String = "STOP"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 0
 }
 
 object Add : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x01)
-
   override fun toString(): String = "ADD"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Mul : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x02)
-
   override fun toString(): String = "MUL"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Sub : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x03)
-
   override fun toString(): String = "SUB"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Div : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x04)
   override fun toString(): String = "DIV"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object SDiv : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x05)
   override fun toString(): String = "SDIV"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Mod : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x06)
   override fun toString(): String = "MOD"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object SMod : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x07)
   override fun toString(): String = "SMOD"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object AddMod : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x08)
   override fun toString(): String = "ADDMOD"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object MulMod : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x09)
   override fun toString(): String = "MULMOD"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Lt : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x10)
   override fun toString(): String = "LT"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Gt : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x11)
   override fun toString(): String = "GT"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Slt : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x12)
   override fun toString(): String = "SLT"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Sgt : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0x13)
   override fun toString(): String = "SGT"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Exp : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x0a)
   override fun toString(): String = "EXP"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object SignExtend : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x0b)
-
   override fun toString(): String = "SIGNEXTEND"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Eq : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x14)
   override fun toString(): String = "EQ"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object IsZero : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0x15)
   override fun toString(): String = "ISZERO"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object And : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x16)
   override fun toString(): String = "AND"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Or : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x17)
   override fun toString(): String = "OR"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Xor : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x18)
   override fun toString(): String = "XOR"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Not : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x19)
   override fun toString(): String = "NOT"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object Byte : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x1a)
   override fun toString(): String = "BYTE"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Shl : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x1b)
   override fun toString(): String = "SHL"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Shr : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x1c)
   override fun toString(): String = "SHR"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Sar : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x1d)
-
   override fun toString(): String = "SAR"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Sha3 : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x20)
   override fun toString(): String = "SHA3"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Address : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x30)
   override fun toString(): String = "ADDRESS"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Balance : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x31)
   override fun toString(): String = "BALANCE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Origin : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x32)
   override fun toString(): String = "ORIGIN"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Caller : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x33)
   override fun toString(): String = "CALLER"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object CallValue : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x34)
   override fun toString(): String = "CALLVALUE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object CallDataLoad : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x35)
   override fun toString(): String = "CALLDATALOAD"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object CallDataSize : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x36)
   override fun toString(): String = "CALLDATASIZE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object CallDataCopy : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x37)
   override fun toString(): String = "CALLDATACOPY"
+  override fun stackItemsConsumed() = 3
+  override fun stackItemsProduced() = 0
 }
 
 object CodeSize : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x38)
   override fun toString(): String = "CODESIZE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object CodeCopy : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x39)
   override fun toString(): String = "CODECOPY"
+  override fun stackItemsConsumed() = 3
+  override fun stackItemsProduced() = 0
 }
 
 object GasPrice : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3a)
   override fun toString(): String = "GASPRICE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object ExtCodeSize : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3b)
   override fun toString(): String = "EXTCODESIZE"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object ExtCodeCopy : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3c)
   override fun toString(): String = "EXTCODECOPY"
+  override fun stackItemsConsumed() = 4
+  override fun stackItemsProduced() = 0
 }
 
 object ReturnDataSize : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3d)
   override fun toString(): String = "RETURNDATASIZE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object ReturnDataCopy : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3e)
   override fun toString(): String = "RETURNDATACOPY"
+  override fun stackItemsConsumed() = 3
+  override fun stackItemsProduced() = 0
 }
 
 object ExtCodeHash : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x3f)
   override fun toString(): String = "EXTCODEHASH"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object BlockHash : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x40)
   override fun toString(): String = "BLOCKHASH"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object Coinbase : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x41)
   override fun toString(): String = "COINBASE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Timestamp : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x42)
   override fun toString(): String = "TIMESTAMP"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Number : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x43)
   override fun toString(): String = "NUMBER"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Difficulty : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x44)
   override fun toString(): String = "DIFFICULTY"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object GasLimit : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x45)
   override fun toString(): String = "GASLIMIT"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object ChainId : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x46)
   override fun toString(): String = "CHAINID"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object SelfBalance : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x47)
   override fun toString(): String = "SELFBALANCE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Pop : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x50)
   override fun toString(): String = "POP"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 0
 }
 
 object Mload : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x51)
   override fun toString(): String = "MLOAD"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object Mstore : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x52)
   override fun toString(): String = "MSTORE"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 0
 }
 
 object Mstore8 : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x53)
   override fun toString(): String = "MSTORE8"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Sload : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x54)
   override fun toString(): String = "SLOAD"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 1
 }
 
 object Sstore : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x55)
   override fun toString(): String = "SSTORE"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 0
 }
 
 object Jump : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x56)
   override fun toString(): String = "JUMP"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 0
 }
 
 object Jumpi : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x57)
   override fun toString(): String = "JUMPI"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 1
 }
 
 object Pc : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x58)
   override fun toString(): String = "PC"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Msize : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x59)
   override fun toString(): String = "MSIZE"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object Gas : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0x5a)
   override fun toString(): String = "GAS"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 1
 }
 
 object JumpDest : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0x5b)
   override fun toString(): String = "JUMPDEST"
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 0
 }
 
 object Create : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xf0)
   override fun toString(): String = "CREATE"
+  override fun stackItemsConsumed() = 3
+  override fun stackItemsProduced() = 1
 }
 
 object Call : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xf1)
   override fun toString(): String = "CALL"
+  override fun stackItemsConsumed() = 7
+  override fun stackItemsProduced() = 1
 }
 
 object CallCode : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xf2)
   override fun toString(): String = "CALLCODE"
+  override fun stackItemsConsumed() = 7
+  override fun stackItemsProduced() = 1
 }
 
 object Return : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0xf3)
   override fun toString(): String = "RETURN"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 0
 }
 
 object DelegateCall : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0xf4)
   override fun toString(): String = "DELEGATECALL"
+  override fun stackItemsConsumed() = 7
+  override fun stackItemsProduced() = 1
 }
 
 object Create2 : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xf5)
   override fun toString(): String = "CREATE2"
+  override fun stackItemsConsumed() = 4
+  override fun stackItemsProduced() = 1
 }
 
 object StaticCall : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xfa)
   override fun toString(): String = "STATICCALL"
+  override fun stackItemsConsumed() = 7
+  override fun stackItemsProduced() = 1
 }
 
 object Revert : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xfd)
   override fun toString(): String = "REVERT"
+  override fun stackItemsConsumed() = 2
+  override fun stackItemsProduced() = 0
 }
 
 object SelfDestruct : Instruction {
 
   override fun toBytes(): Bytes = Bytes.of(0xff)
   override fun toString(): String = "SELFDESTRUCT"
+  override fun stackItemsConsumed() = 1
+  override fun stackItemsProduced() = 0
 }
 
 class Dup(val dupIndex: Int) : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x80 + dupIndex - 1)
   override fun toString(): String = "DUP$dupIndex"
+  override fun stackItemsNeeded() = dupIndex
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = dupIndex
 }
 
 class Swap(val swapIndex: Int) : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0x90 + swapIndex - 1)
   override fun toString(): String = "SWAP$swapIndex"
+  override fun stackItemsNeeded() = swapIndex
+  override fun stackItemsConsumed() = 0
+  override fun stackItemsProduced() = 0
 }
 
 class Log(val logIndex: Int) : Instruction {
-
   override fun toBytes(): Bytes = Bytes.of(0xa0 + logIndex)
   override fun toString(): String = "LOG$logIndex"
+  override fun stackItemsConsumed() = logIndex + 2
+  override fun stackItemsProduced() = 0
 }
diff --git a/evm-dsl/src/test/kotlin/org/apache/tuweni/evmdsl/CodeTest.kt 
b/evm-dsl/src/test/kotlin/org/apache/tuweni/evmdsl/CodeTest.kt
index 086c1434..31f5dfeb 100644
--- a/evm-dsl/src/test/kotlin/org/apache/tuweni/evmdsl/CodeTest.kt
+++ b/evm-dsl/src/test/kotlin/org/apache/tuweni/evmdsl/CodeTest.kt
@@ -53,4 +53,49 @@ class CodeTest {
     val reread = Code.read(code.toBytes())
     assertEquals(codeStr, reread.toString())
   }
+
+  @Test
+  fun testValidateUnderFlow() {
+    val code = Code(
+      buildList {
+        this.add(Push(Bytes.fromHexString("0x4567")))
+        this.add(Push(Bytes.fromHexString("0x456778")))
+        this.add(Call)
+      }
+    )
+    val err = code.validate()!!
+    assertEquals(2, err.index)
+    assertEquals(Error.STACK_UNDERFLOW, err.error)
+    assertEquals(Call, err.instruction)
+  }
+
+  @Test
+  fun testValidateInvalid() {
+    val code = Code(
+      buildList {
+        this.add(Push(Bytes.fromHexString("0x4567")))
+        this.add(Push(Bytes.fromHexString("0x456778")))
+        this.add(Invalid(0xfe.toByte()))
+        this.add(Push(Bytes.fromHexString("0x456778")))
+      }
+    )
+    val err = code.validate()!!
+    assertEquals(2, err.index)
+    assertEquals(Error.HIT_INVALID_OPCODE, err.error)
+    assertEquals(Invalid(0xfe.toByte()), err.instruction)
+  }
+
+  @Test
+  fun testValidateOverFlow() {
+    val code = Code(
+      buildList {
+        for (i in 0..1024) {
+          this.add(Push(Bytes.fromHexString("0x4567")))
+        }
+      }
+    )
+    val err = code.validate()!!
+    assertEquals(1024, err.index)
+    assertEquals(Error.STACK_OVERFLOW, err.error)
+  }
 }


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

Reply via email to