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 f258a42d Add support for new custom opcode in DSL new 0e2faa42 Merge pull request #428 from atoulme/custom_opcode_support f258a42d is described below commit f258a42d33fa570bf94348099cc1751fd81edc58 Author: Antoine Toulme <anto...@lunar-ocean.com> AuthorDate: Sat Jul 16 10:06:55 2022 -0700 Add support for new custom opcode in DSL --- .../main/kotlin/org/apache/tuweni/evmdsl/Code.kt | 12 ++++-- .../org/apache/tuweni/evmdsl/Instructions.kt | 11 ++++++ .../kotlin/org/apache/tuweni/evmdsl/CodeTest.kt | 44 ++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 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 abe1db3e..1afd6655 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 @@ -51,6 +51,8 @@ class Code(val instructions: List<Instruction>) { var stackSize = 0 val visited = mutableSetOf<Int>() var index = 0 + val jumpDests = mutableSetOf<Int>() + val jumpSrcs = mutableMapOf<Int, Int>() while (visited.add(index)) { val currentInstruction = instructions.getOrNull(index) ?: break if (currentInstruction.stackItemsNeeded() > stackSize) { @@ -63,11 +65,15 @@ class Code(val instructions: List<Instruction>) { if (currentInstruction is Invalid) { return CodeValidationError(currentInstruction, index, Error.HIT_INVALID_OPCODE) } - // TODO cannot follow jumps right now. if (currentInstruction == Jump || currentInstruction == Jumpi) { - break + jumpSrcs.put(index, stackSize) + } + if (currentInstruction == JumpDest) { + jumpDests.add(index) + } + if (currentInstruction.end()) { + stackSize = 0 } - index++ } return null 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 04be3e10..3cc12ec5 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 @@ -31,6 +31,8 @@ interface Instruction { fun stackItemsConsumed(): Int fun stackItemsProduced(): Int + + fun end(): Boolean = false } data class InstructionModel(val opcode: Byte, val additionalBytesToRead: Int = 0, val creator: (code: Bytes, index: Int) -> Instruction) @@ -665,6 +667,7 @@ object Return : Instruction { override fun toString(): String = "RETURN" override fun stackItemsConsumed() = 2 override fun stackItemsProduced() = 0 + override fun end() = true } object DelegateCall : Instruction { @@ -696,6 +699,7 @@ object Revert : Instruction { override fun toString(): String = "REVERT" override fun stackItemsConsumed() = 2 override fun stackItemsProduced() = 0 + override fun end() = true } object SelfDestruct : Instruction { @@ -728,3 +732,10 @@ class Log(val logIndex: Int) : Instruction { override fun stackItemsConsumed() = logIndex + 2 override fun stackItemsProduced() = 0 } + +data class Custom(val bytes: Bytes, val str: String, val consumed: Int, val produced: Int) : Instruction { + override fun toBytes() = bytes + override fun toString() = str + override fun stackItemsConsumed() = consumed + override fun stackItemsProduced() = produced +} 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 dcdd6485..e1cc2c4b 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 @@ -17,6 +17,7 @@ package org.apache.tuweni.evmdsl import org.apache.tuweni.bytes.Bytes +import org.apache.tuweni.bytes.Bytes32 import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test @@ -114,4 +115,47 @@ class CodeTest { ) assertNull(code.validate()?.error) } + + @Test + fun testSomeWorkshopCode() { + val code = Code( + buildList { + this.add(Push(Bytes.fromHexString("0x00"))) + this.add(CallDataLoad) // load from position 0 + this.add(Custom(Bytes.fromHexString("0xf6"), "SHAREDSECRET", 1, 1)) + this.add(Push(Bytes.fromHexString("0x11"))) // push jump destination + this.add(Jumpi) // if custom returns 0, keep going, else go to jumpdest at byte 0x11 + this.add(Push(Bytes.fromHexString("0x00"))) // value + this.add(Push(Bytes.fromHexString("0x00"))) // location + this.add(Mstore) // store 0 in memory + this.add(Push(Bytes.fromHexString("0x01"))) // length + this.add(Push(Bytes.fromHexString("0x1f"))) // location + this.add(Return) // return 0 + this.add(JumpDest) + this.add(Push(Bytes.fromHexString("0x01"))) // value + this.add(Push(Bytes.fromHexString("0x00"))) // location + this.add(Mstore) // store 1 in memory + this.add(Push(Bytes.fromHexString("0x01"))) // length + this.add(Push(Bytes.fromHexString("0x1f"))) // location + this.add(Return) + } + ) + assertNull(code.validate()?.error) + println(code.toString()) + println(code.toBytes().toHexString()) + + // surround with instructions to deploy. + val deployment = Code( + buildList { + this.add(Push(Bytes32.rightPad(code.toBytes()))) // pad the code with zeros to create a word + this.add(Push(Bytes.fromHexString("0x00"))) // set the location of the memory to store + this.add(Mstore) + this.add(Push(Bytes.ofUnsignedInt(code.toBytes().size().toLong()))) // length + this.add(Push(Bytes.fromHexString("0x00"))) // location + this.add(Return) // return the code + } + ) + + println(deployment.toBytes().toHexString()) + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@tuweni.apache.org For additional commands, e-mail: commits-h...@tuweni.apache.org