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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]