diff --git a/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java index a79c32fa..3d221e68 100644 --- a/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java @@ -3,7 +3,9 @@ package org.ethereum.serpent; import org.antlr.v4.runtime.tree.ParseTree; import org.ethereum.util.ByteUtil; import org.ethereum.vm.OpCode; +import org.spongycastle.util.Arrays; import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.encoders.Hex; import java.io.ByteArrayOutputStream; import java.math.BigInteger; @@ -51,12 +53,14 @@ public class SerpentCompiler { if (lexa.equals("asm]")){ skiping = false; lexaList.remove(i); - lexa = lexaList.get(i); + --i; + continue; } if (lexa.equals("[asm")){ skiping = true; lexaList.remove(i); + --i; continue; } @@ -140,6 +144,29 @@ public class SerpentCompiler { } + public static byte[] encodeMachineCodeForVMRun(byte[] code){ + if (code == null || code.length == 0) throw new RuntimeException("code can't be empty code: " + code); + + int numBytes = ByteUtil.numBytes(code.length + ""); + byte[] lenBytes = BigInteger.valueOf(code.length).toByteArray(); + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < lenBytes.length; ++i){ + + sb.append(Hex.toHexString(lenBytes, i, 1)).append(" "); + } + + // calc real code start position (after the init header) + int pos = 10 + numBytes * 2; + + // @push_len @len PUSH1 @src_start PUSH1 0 CODECOPY @push_len @len 0 PUSH1 0 RETURN + String header = String.format("[asm %s %s PUSH1 %d PUSH1 0 CODECOPY %s %s PUSH1 0 RETURN asm]", + "PUSH" + numBytes, sb.toString(), pos , "PUSH" + numBytes, sb.toString()); + + byte[] headerMachine = compileAssemblyToMachine(header); + + return Arrays.concatenate(headerMachine, code); + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java index 2865598b..ccc79588 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -54,7 +54,7 @@ public enum OpCode { CALLDATASIZE(0x36), CALLDATACOPY(0x37), CODESIZE(0x38), - CODECOPY(0x39), + CODECOPY(0x39), // [len src_start target_start CODECOPY] GASPRICE(0x3a), /** diff --git a/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java b/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java new file mode 100644 index 00000000..06930a14 --- /dev/null +++ b/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java @@ -0,0 +1,32 @@ +package org.ethereum.serpent; + +import org.ethereum.gui.GUIUtils; +import org.junit.Assert; +import org.junit.Test; +import org.spongycastle.util.encoders.Hex; + +/** + * www.ethereumJ.com + * User: Roman Mandeleil + * Created on: 28/05/2014 20:05 + */ + + +public class MachineCompileTest { + + + @Test // + public void test1(){ + + String code = "a=2"; + String expected = "6005600c60003960056000f26002600054"; + String asm = SerpentCompiler.compile(code); + byte[] machineCode = SerpentCompiler.compileAssemblyToMachine(asm); + byte[] vmReadyCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode); + + System.out.println(GUIUtils.getHexStyledText(vmReadyCode)); + String result = Hex.toHexString(vmReadyCode); + + Assert.assertEquals(expected, result); + } +} diff --git a/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java b/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java index 7f530843..a8030ba6 100644 --- a/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java @@ -275,7 +275,7 @@ public class SerpentCompileTest { @Test // expression test 10 public void test15(){ - String code = "a = not ( 1 + 2 * 9 | 8 == 2)"; + String code = "a = !( 1 + 2 * 9 | 8 == 2)"; String expected = "2 8 EQ 9 2 MUL 1 ADD OR NOT 0 MSTORE"; SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class, @@ -1245,15 +1245,30 @@ public class SerpentCompileTest { } +/* + todo: more to implement +# 1) send(1, 2, 3) +# 2) create(1, 2, 3, 4) +# 3) x = sha3(v) +# 4) x = byte(y,z) +# 5) v = getch(x,i) +# 6) setch(x,i,v) + +# 7) a=array(30) +# 8) x = bytes(n) + + + */ + /** * * todo: return(1) testing - * return (1,2) testing + * todo: return (1,2) testing * todo: msg.data testing - * todo: contract.storage testing + * todo: contract.storage get/set testing * todo: [asm asm] testing * todo: suicide(1) testing - * todo: stop test + * todo: stop testing * * */