From d3cafc273103ab9015d51bd02ae6a961ac9bdfc8 Mon Sep 17 00:00:00 2001 From: nicksavers Date: Mon, 5 May 2014 19:09:32 +0200 Subject: [PATCH] Document and clean RLP and some others --- .../main/java/org/ethereum/net/Command.java | 2 +- .../org/ethereum/net/MessageDeserializer.java | 2 +- .../org/ethereum/net/client/ClientPeer.java | 5 - .../net/client/EthereumProtocolHandler.java | 1 - .../ethereum/net/message/BlocksMessage.java | 1 - .../main/java/org/ethereum/net/rlp/RLP.java | 826 +++++++----------- .../java/org/ethereum/net/rlp/RLPList.java | 8 +- .../java/org/ethereum/net/vo/PeerData.java | 6 +- .../src/main/java/org/ethereum/vm/OpCode.java | 159 ++++ 9 files changed, 473 insertions(+), 537 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java diff --git a/ethereumj-core/src/main/java/org/ethereum/net/Command.java b/ethereumj-core/src/main/java/org/ethereum/net/Command.java index 188185aa..ac9edfe7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/Command.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/Command.java @@ -30,7 +30,7 @@ public enum Command { private Command(int cmd) { this.cmd = cmd; } - + public static Command fromInt(int i) { Command type = intToTypeMap.get(Integer.valueOf(i)); if (type == null) diff --git a/ethereumj-core/src/main/java/org/ethereum/net/MessageDeserializer.java b/ethereumj-core/src/main/java/org/ethereum/net/MessageDeserializer.java index e5c0ef8e..1ad39d23 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/MessageDeserializer.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/MessageDeserializer.java @@ -9,7 +9,7 @@ public class MessageDeserializer { /** * Get exactly one message payload */ - public static void deserialize(byte [] msgData, int level, int startPos, int endPos){ + private static void deserialize(byte [] msgData, int level, int startPos, int endPos){ if (msgData == null || msgData.length == 0) return ; int pos = startPos; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java index 3c7555cf..1b7b0062 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java @@ -31,7 +31,6 @@ public class ClientPeer { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { - Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); @@ -58,18 +57,14 @@ public class ClientPeer { // Start the client. ChannelFuture f = b.connect(host, port).sync(); // (5) - // Wait until the connection is closed. f.channel().closeFuture().sync(); } catch (InterruptedException ie){ - System.out.println("-- ClientPeer: catch (InterruptedException ie) --"); ie.printStackTrace(); } finally { workerGroup.shutdownGracefully(); } - - } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java index f8095d90..556258bb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java @@ -122,7 +122,6 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { timer.schedule(new TimerTask() { public void run() { - System.out.println("[Send: TX]"); sendTx(ctx); } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/BlocksMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/BlocksMessage.java index eaa48756..35982ea8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/BlocksMessage.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/BlocksMessage.java @@ -61,7 +61,6 @@ public class BlocksMessage extends Message { sb.append("[").append(transactionData).append("]\n"); } } - return "Blocks Message [\n" + sb.toString() + " ]"; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLP.java b/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLP.java index 9a9e9db8..ea2f66e5 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLP.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLP.java @@ -1,73 +1,91 @@ package org.ethereum.net.rlp; -import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Queue; +/** + * Recursive Length Prefix (RLP) encoding. + * + * The purpose of RLP is to encode arbitrarily nested arrays of binary data, and + * RLP is the main encoding method used to serialize objects in Ethereum. The + * only purpose of RLP is to encode structure; encoding specific atomic data + * types (eg. strings, ints, floats) is left up to higher-order protocols; in + * Ethereum the standard is that integers are represented in big endian binary + * form. If one wishes to use RLP to encode a dictionary, the two suggested + * canonical forms are to either use [[k1,v1],[k2,v2]...] with keys in + * lexicographic order or to use the higher-level Patricia Tree encoding as + * Ethereum does. + * + * The RLP encoding function takes in an item. An item is defined as follows: + * + * - A string (ie. byte array) is an item - A list of items is an item + * + * For example, an empty string is an item, as is the string containing the word + * "cat", a list containing any number of strings, as well as more complex data + * structures like ["cat",["puppy","cow"],"horse",[[]],"pig",[""],"sheep"]. Note + * that in the context of the rest of this article, "string" will be used as a + * synonym for "a certain number of bytes of binary data"; no special encodings + * are used and no knowledge about the content of the strings is implied. + * + * See: https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP + */ public class RLP { - public static byte decodeOneByteItem(byte[] data, int index) { + /** + * Reason for threshold according to Vitalik Buterin: + * - 56 bytes maximizes the benefit of both options + * - if we went with 60 then we would have only had 4 slots for long strings + * so RLP would not have been able to store objects above 4gb + * - if we went with 48 then RLP would be fine for 2^128 space, but that's way too much + * - so 56 and 2^64 space seems like the right place to put the cutoff + * - also, that's where Bitcoin's varint does the cutof + **/ + private static int SIZE_THRESHOLD = 56; + + /* + * If a string is 0-55 bytes long, the RLP encoding consists of a single + * byte with value 0x80 plus the length of the string followed by the + * string. The range of the first byte is thus [0x80, 0xb7]. + */ + private static int OFFSET_SHORT_ITEM = 0x80; + + /* + * If the total payload of a list (i.e. the combined length of all its + * items) is 0-55 bytes long, the RLP encoding consists of a single byte + * with value 0xc0 plus the length of the list followed by the concatenation + * of the RLP encodings of the items. The range of the first byte is thus + * [0xc0, 0xf7]. + */ + private static int OFFSET_SHORT_LIST = 0xc0; + + private static byte decodeOneByteItem(byte[] data, int index) { // null item - if ((data[index] & 0xFF) == 0x80) { - return (byte) (data[index] - 0x80); + if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM) { + return (byte) (data[index] - OFFSET_SHORT_ITEM); } // single byte item - if ((data[index] & 0xFF) < 0x80) { + if ((data[index] & 0xFF) < OFFSET_SHORT_ITEM) { return (byte) (data[index]); } // single byte item - if ((data[index] & 0xFF) == 0x81) { + if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM+1) { return (byte) (data[index + 1]); } return 0; } - public static String decodeStringItem(byte[] data, int index) { - - String value = null; - - if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < 0xC0) { - - byte lenghtOfLenght = (byte) (data[index] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[index + i] << (8 * pow); - pow--; - } - - value = new String(data, index + lenghtOfLenght + 1, length); - - } else if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - - byte length = (byte) ((data[index] & 0xFF) - 0x80); - - value = new String(data, index + 1, length); - - } else { - throw new Error("wrong decode attempt"); - } - - return value; - } - public static int decodeInt(byte[] data, int index) { int value = 0; - if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { + if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { - byte length = (byte) (data[index] - 0x80); + byte length = (byte) (data[index] - OFFSET_SHORT_ITEM); byte pow = (byte) (length - 1); - for (int i = 1; i <= length; ++i) { value += data[index + i] << (8 * pow); pow--; @@ -78,12 +96,12 @@ public class RLP { return value; } - public static short decodeShort(byte[] data, int index) { + private static short decodeShort(byte[] data, int index) { short value = 0; - if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - byte length = (byte) (data[index] - 0x80); + if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { + byte length = (byte) (data[index] - OFFSET_SHORT_ITEM); value = ByteBuffer.wrap(data, index, length).getShort(); } else { value = data[index]; @@ -91,230 +109,170 @@ public class RLP { return value; } - public static short decodeLong(byte[] data, int index) { + private static long decodeLong(byte[] data, int index) { - short value = 0; + long value = 0; - if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { + if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { - byte length = (byte) (data[index] - 0x80); + byte length = (byte) (data[index] - OFFSET_SHORT_ITEM); byte pow = (byte) (length - 1); - for (int i = 1; i <= length; ++i) { - value += data[index + i] << (8 * pow); pow--; } } else { throw new Error("wrong decode attempt"); } + return value; + } + + private static String decodeStringItem(byte[] data, int index) { + String value = null; + + if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < OFFSET_SHORT_LIST) { + + byte lengthOfLength = (byte) (data[index] - 0xB7); + int length = calcLengthRaw(lengthOfLength, data, index); + value = new String(data, index + lengthOfLength + 1, length); + + } else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { + + byte length = (byte) ((data[index] & 0xFF) - OFFSET_SHORT_ITEM); + value = new String(data, index + 1, length); + + } else { + throw new Error("wrong decode attempt"); + } return value; } - public static byte[] decodeItemBytes(byte[] data, int index) { + private static byte[] decodeItemBytes(byte[] data, int index) { byte[] value = null; + int length = 0; - if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < 0xC0) { + if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (data[index] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); + byte lengthOfLength = (byte) (data[index] - 0xB7); + length = calcLengthRaw(lengthOfLength, data, index); - int length = 0; + } else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[index + i] << (8 * pow); - pow--; - } - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = valueBytes; - - } else if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - - byte length = (byte) (data[index] - 0x80); - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = valueBytes; + length = (byte) (data[index] - OFFSET_SHORT_ITEM); } else { - throw new Error("wrong decode attempt"); - } - + byte[] valueBytes = new byte[length]; + System.arraycopy(data, index, valueBytes, 0, length); + value = valueBytes; return value; } public static BigInteger decodeBigInteger(byte[] data, int index) { BigInteger value = null; + int length = 0; - if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < 0xC0) { + if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (data[index] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); + byte lengthOfLength = (byte) (data[index] - 0xB7); + length = calcLengthRaw(lengthOfLength, data, index); - int length = 0; + } else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[index + i] << (8 * pow); - pow--; - } - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = new BigInteger(valueBytes); - - } else if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - - byte length = (byte) (data[index] - 0x80); - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = new BigInteger(valueBytes); + length = (byte) (data[index] - OFFSET_SHORT_ITEM); } else { - throw new Error("wrong decode attempt"); - } - + byte[] valueBytes = new byte[length]; + System.arraycopy(data, index, valueBytes, 0, length); + value = new BigInteger(valueBytes); return value; } - public static byte[] decodeByteArray(byte[] data, int index) { + private static byte[] decodeByteArray(byte[] data, int index) { byte[] value = null; + int length = 0; - if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < 0xC0) { + if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (data[index] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); + byte lengthOfLength = (byte) (data[index] - 0xB7); + length = calcLengthRaw(lengthOfLength, data, index); - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[index + i] << (8 * pow); - pow--; - } - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = valueBytes; - - } else if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - - byte length = (byte) (data[index] - 0x80); - - byte[] valueBytes = new byte[length]; - System.arraycopy(data, index, valueBytes, 0, length); - - value = valueBytes; + } else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { + length = (byte) (data[index] - OFFSET_SHORT_ITEM); + } else { - throw new Error("wrong decode attempt"); - } - + byte[] valueBytes = new byte[length]; + System.arraycopy(data, index, valueBytes, 0, length); + value = valueBytes; return value; } - public static int nextItemLength(byte[] data, int index) { + private static int nextItemLength(byte[] data, int index) { if (index >= data.length) return -1; if ((data[index] & 0xFF) >= 0xF7) { - byte lenghtOfLenght = (byte) (data[index] - 0xF7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (data[index + i] & 0xFF) << (8 * pow); - pow--; - } - - return length; - - } - - if ((data[index] & 0xFF) >= 0xC0 && (data[index] & 0xFF) < 0xF7) { - - byte length = (byte) ((data[index] & 0xFF) - 0xC0); + byte lengthOfLength = (byte) (data[index] - 0xF7); + + int length = calcLength(lengthOfLength, data, index); return length; } + if ((data[index] & 0xFF) >= OFFSET_SHORT_LIST && (data[index] & 0xFF) < 0xF7) { - if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < 0xC0) { - - byte lenghtOfLenght = (byte) (data[index] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (data[index + i] & 0xFF) << (8 * pow); - pow--; - } - - return length; - - } - - if ((data[index] & 0xFF) > 0x80 && (data[index] & 0xFF) < 0xB7) { - - byte length = (byte) ((data[index] & 0xFF) - 0x80); + byte length = (byte) ((data[index] & 0xFF) - OFFSET_SHORT_LIST); return length; } + if ((data[index] & 0xFF) >= 0xB7 && (data[index] & 0xFF) < OFFSET_SHORT_LIST) { - if ((data[index] & 0xFF) == 0x80) { + byte lengthOfLength = (byte) (data[index] - 0xB7); + int length = calcLength(lengthOfLength, data, index); + return length; + } + if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM && (data[index] & 0xFF) < 0xB7) { + byte length = (byte) ((data[index] & 0xFF) - OFFSET_SHORT_ITEM); + return length; + } + if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM) { return 1; } - - if ((data[index] & 0xFF) < 0x80) { - + if ((data[index] & 0xFF) < OFFSET_SHORT_ITEM) { return 1; } - return -1; } public static byte[] decodeIP4Bytes(byte[] data, int index) { - int length = (data[index] & 0xFF) - 0xC0; + int length = (data[index] & 0xFF) - OFFSET_SHORT_LIST; int offset = 1; byte aByte = decodeOneByteItem(data, index + offset); - if ((data[index + offset] & 0xFF) > 0x80) + if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM) offset = offset + 2; else offset = offset + 1; byte bByte = decodeOneByteItem(data, index + offset); - if ((data[index + offset] & 0xFF) > 0x80) + if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM) offset = offset + 2; else offset = offset + 1; byte cByte = decodeOneByteItem(data, index + offset); - if ((data[index + offset] & 0xFF) > 0x80) + if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM) offset = offset + 2; else offset = offset + 1; @@ -336,31 +294,22 @@ public class RLP { if ((payload[pos] & 0xFF) >= 0xF7) { - byte lenghtOfLenght = (byte) (payload[pos] - 0xF7); + byte lengthOfLength = (byte) (payload[pos] - 0xF7); - return pos + lenghtOfLenght + 1; + return pos + lengthOfLength + 1; } - if ((payload[pos] & 0xFF) >= 0xC0 && (payload[pos] & 0xFF) < 0xF7) { + if ((payload[pos] & 0xFF) >= OFFSET_SHORT_LIST && (payload[pos] & 0xFF) < 0xF7) { - byte length = (byte) ((payload[pos] & 0xFF) - 0xC0); + byte length = (byte) ((payload[pos] & 0xFF) - OFFSET_SHORT_LIST); return pos + 1; } - if ((payload[pos] & 0xFF) >= 0xB7 && (payload[pos] & 0xFF) < 0xC0) { + if ((payload[pos] & 0xFF) >= 0xB7 && (payload[pos] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (payload[pos] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (payload[pos + i] & 0xFF) << (8 * pow); - pow--; - } - - return pos + lenghtOfLenght + 1; + byte lengthOfLength = (byte) (payload[pos] - 0xB7); + int length = calcLength(lengthOfLength, payload, pos); + return pos + lengthOfLength + 1; } return -1; @@ -372,58 +321,32 @@ public class RLP { return -1; if ((payload[pos] & 0xFF) >= 0xF7) { - byte lenghtOfLength = (byte) (payload[pos] - 0xF7); - byte pow = (byte) (lenghtOfLength - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLength; ++i) { - - length += (payload[pos + i] & 0xFF) << (8 * pow); - pow--; - } - - return pos + lenghtOfLength + length + 1; + byte lengthOfLength = (byte) (payload[pos] - 0xF7); + int length = calcLength(lengthOfLength, payload, pos); + return pos + lengthOfLength + length + 1; } + if ((payload[pos] & 0xFF) >= OFFSET_SHORT_LIST && (payload[pos] & 0xFF) < 0xF7) { - if ((payload[pos] & 0xFF) >= 0xC0 && (payload[pos] & 0xFF) < 0xF7) { - - byte length = (byte) ((payload[pos] & 0xFF) - 0xC0); + byte length = (byte) ((payload[pos] & 0xFF) - OFFSET_SHORT_LIST); return pos + 1 + length; } + if ((payload[pos] & 0xFF) >= 0xB7 && (payload[pos] & 0xFF) < OFFSET_SHORT_LIST) { - if ((payload[pos] & 0xFF) >= 0xB7 && (payload[pos] & 0xFF) < 0xC0) { - - byte lenghtOfLenght = (byte) (payload[pos] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (payload[pos + i] & 0xFF) << (8 * pow); - pow--; - } - - return pos + lenghtOfLenght + length + 1; + byte lengthOfLength = (byte) (payload[pos] - 0xB7); + int length = calcLength(lengthOfLength, payload, pos); + return pos + lengthOfLength + length + 1; } + if ((payload[pos] & 0xFF) > OFFSET_SHORT_ITEM && (payload[pos] & 0xFF) < 0xB7) { - if ((payload[pos] & 0xFF) > 0x80 && (payload[pos] & 0xFF) < 0xB7) { - - byte length = (byte) ((payload[pos] & 0xFF) - 0x80); + byte length = (byte) ((payload[pos] & 0xFF) - OFFSET_SHORT_ITEM); return pos + 1 + length; } - - if ((payload[pos] & 0xFF) == 0x80) { - + if ((payload[pos] & 0xFF) == OFFSET_SHORT_ITEM) { return pos + 1; } - - if ((payload[pos] & 0xFF) < 0x80) { - + if ((payload[pos] & 0xFF) < OFFSET_SHORT_ITEM) { return pos + 1; } - return -1; } @@ -432,7 +355,6 @@ public class RLP { */ public static void fullTraverse(byte[] msgData, int level, int startPos, int endPos, int levelToIndex, Queue index) { - try { if (msgData == null || msgData.length == 0) @@ -449,33 +371,24 @@ public class RLP { // for the length of the list if ((msgData[pos] & 0xFF) >= 0xF7) { - byte lenghtOfLenght = (byte) (msgData[pos] - 0xF7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (msgData[pos + i] & 0xFF) << (8 * pow); - pow--; - } + byte lengthOfLength = (byte) (msgData[pos] - 0xF7); + int length = calcLength(lengthOfLength, msgData, pos); // now we can parse an item for data[1]..data[length] System.out.println("-- level: [" + level + "] Found big list length: " + length); - fullTraverse(msgData, level + 1, pos + lenghtOfLenght + 1, - pos + lenghtOfLenght + length, levelToIndex, index); + fullTraverse(msgData, level + 1, pos + lengthOfLength + 1, + pos + lengthOfLength + length, levelToIndex, index); - pos += lenghtOfLenght + length + 1; + pos += lengthOfLength + length + 1; continue; } - // It's a list with a payload less than 55 bytes - if ((msgData[pos] & 0xFF) >= 0xC0 + if ((msgData[pos] & 0xFF) >= OFFSET_SHORT_LIST && (msgData[pos] & 0xFF) < 0xF7) { - byte length = (byte) ((msgData[pos] & 0xFF) - 0xC0); + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_LIST); System.out.println("-- level: [" + level + "] Found small list length: " + length); @@ -486,56 +399,43 @@ public class RLP { pos += 1 + length; continue; } - // It's an item with a payload more than 55 bytes // data[0] - 0xB7 = how much next bytes allocated for // the length of the string if ((msgData[pos] & 0xFF) >= 0xB7 - && (msgData[pos] & 0xFF) < 0xC0) { + && (msgData[pos] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (msgData[pos] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (msgData[pos + i] & 0xFF) << (8 * pow); - pow--; - } + byte lengthOfLength = (byte) (msgData[pos] - 0xB7); + int length = calcLength(lengthOfLength, msgData, pos); // now we can parse an item for data[1]..data[length] System.out.println("-- level: [" + level + "] Found big item length: " + length); - pos += lenghtOfLenght + length + 1; + pos += lengthOfLength + length + 1; continue; } - // It's an item less than 55 bytes long, - // data[0] - 0x80 == lenght of the item - if ((msgData[pos] & 0xFF) > 0x80 + // data[0] - 0x80 == length of the item + if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM && (msgData[pos] & 0xFF) < 0xB7) { - byte length = (byte) ((msgData[pos] & 0xFF) - 0x80); + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM); System.out.println("-- level: [" + level + "] Found small item length: " + length); pos += 1 + length; - continue; } - // null item - if ((msgData[pos] & 0xFF) == 0x80) { + if ((msgData[pos] & 0xFF) == OFFSET_SHORT_ITEM) { System.out.println("-- level: [" + level + "] Found null item: "); pos += 1; continue; } - // single byte item - if ((msgData[pos] & 0xFF) < 0x80) { + if ((msgData[pos] & 0xFF) < OFFSET_SHORT_ITEM) { System.out.println("-- level: [" + level + "] Found single item: "); pos += 1; @@ -548,6 +448,26 @@ public class RLP { } } + private static int calcLength(int lengthOfLength, byte[] msgData, int pos) { + byte pow = (byte) (lengthOfLength - 1); + int length = 0; + for (int i = 1; i <= lengthOfLength; ++i) { + length += (msgData[pos + i] & 0xFF) << (8 * pow); + pow--; + } + return length; + } + + private static int calcLengthRaw(int lengthOfLength, byte[] msgData, int index) { + byte pow = (byte) (lengthOfLength - 1); + int length = 0; + for (int i = 1; i <= lengthOfLength; ++i) { + length += msgData[index + i] << (8 * pow); + pow--; + } + return length; + } + /** * Parse wire byte[] message into RLP elements * @@ -557,41 +477,31 @@ public class RLP { * - outcome of recursive RLP structure */ public static void parseObjects(byte[] msgData, RLPList rlpList) { - RLP.fullTraverse2(msgData, 0, 0, msgData.length, 1, rlpList); + RLP.fullTraverse(msgData, 0, 0, msgData.length, 1, rlpList); } /** * Get exactly one message payload */ - public static void fullTraverse2(byte[] msgData, int level, int startPos, + private static void fullTraverse(byte[] msgData, int level, int startPos, int endPos, int levelToIndex, RLPList rlpList) { try { - if (msgData == null || msgData.length == 0) return; int pos = startPos; while (pos < endPos) { - // It's a list with a payload more than 55 bytes // data[0] - 0xF7 = how many next bytes allocated // for the length of the list if ((msgData[pos] & 0xFF) >= 0xF7) { - byte lenghtOfLenght = (byte) (msgData[pos] - 0xF7); - byte pow = (byte) (lenghtOfLenght - 1); + byte lengthOfLength = (byte) (msgData[pos] - 0xF7); + int length = calcLength(lengthOfLength, msgData, pos); - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (msgData[pos + i] & 0xFF) << (8 * pow); - pow--; - } - - byte[] rlpData = new byte[lenghtOfLenght + length + 1]; - System.arraycopy(msgData, pos, rlpData, 0, lenghtOfLenght + byte[] rlpData = new byte[lengthOfLength + length + 1]; + System.arraycopy(msgData, pos, rlpData, 0, lengthOfLength + length + 1); RLPList newLevelList = new RLPList(); @@ -600,23 +510,22 @@ public class RLP { // todo: this done to get some data for testing should be // delete // byte[] subList = Arrays.copyOfRange(msgData, pos, pos + - // lenghtOfLenght + length + 1); + // lengthOfLength + length + 1); // System.out.println(Utils.toHexString(subList)); - fullTraverse2(msgData, level + 1, pos + lenghtOfLenght + 1, - pos + lenghtOfLenght + length + 1, levelToIndex, + fullTraverse(msgData, level + 1, pos + lengthOfLength + 1, + pos + lengthOfLength + length + 1, levelToIndex, newLevelList); rlpList.addItem(newLevelList); - pos += lenghtOfLenght + length + 1; + pos += lengthOfLength + length + 1; continue; } - // It's a list with a payload less than 55 bytes - if ((msgData[pos] & 0xFF) >= 0xC0 + if ((msgData[pos] & 0xFF) >= OFFSET_SHORT_LIST && (msgData[pos] & 0xFF) < 0xF7) { - byte length = (byte) ((msgData[pos] & 0xFF) - 0xC0); + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_LIST); byte[] rlpData = new byte[length + 1]; System.arraycopy(msgData, pos, rlpData, 0, length + 1); @@ -625,53 +534,43 @@ public class RLP { newLevelList.setRLPData(rlpData); if (length > 0) - fullTraverse2(msgData, level + 1, pos + 1, pos + length + fullTraverse(msgData, level + 1, pos + 1, pos + length + 1, levelToIndex, newLevelList); rlpList.addItem(newLevelList); pos += 1 + length; continue; } - // It's an item with a payload more than 55 bytes // data[0] - 0xB7 = how much next bytes allocated for // the length of the string if ((msgData[pos] & 0xFF) >= 0xB7 - && (msgData[pos] & 0xFF) < 0xC0) { + && (msgData[pos] & 0xFF) < OFFSET_SHORT_LIST) { - byte lenghtOfLenght = (byte) (msgData[pos] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - int length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += (msgData[pos + i] & 0xFF) << (8 * pow); - pow--; - } + byte lengthOfLength = (byte) (msgData[pos] - 0xB7); + int length = calcLength(lengthOfLength, msgData, pos); // now we can parse an item for data[1]..data[length] byte[] item = new byte[length]; - System.arraycopy(msgData, pos + lenghtOfLenght + 1, item, + System.arraycopy(msgData, pos + lengthOfLength + 1, item, 0, length); - byte[] rlpPrefix = new byte[lenghtOfLenght + 1]; + byte[] rlpPrefix = new byte[lengthOfLength + 1]; System.arraycopy(msgData, pos, rlpPrefix, 0, - lenghtOfLenght + 1); + lengthOfLength + 1); RLPItem rlpItem = new RLPItem(item); rlpList.addItem(rlpItem); - pos += lenghtOfLenght + length + 1; + pos += lengthOfLength + length + 1; continue; } - // It's an item less than 55 bytes long, // data[0] - 0x80 == length of the item - if ((msgData[pos] & 0xFF) > 0x80 + if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM && (msgData[pos] & 0xFF) < 0xB7) { - byte length = (byte) ((msgData[pos] & 0xFF) - 0x80); + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM); byte[] item = new byte[length]; System.arraycopy(msgData, pos + 1, item, 0, length); @@ -685,19 +584,16 @@ public class RLP { continue; } - // null item - if ((msgData[pos] & 0xFF) == 0x80) { - + if ((msgData[pos] & 0xFF) == OFFSET_SHORT_ITEM) { byte[] item = new byte[0]; RLPItem rlpItem = new RLPItem(item); rlpList.addItem(rlpItem); pos += 1; continue; } - // single byte item - if ((msgData[pos] & 0xFF) < 0x80) { + if ((msgData[pos] & 0xFF) < OFFSET_SHORT_ITEM) { byte[] item = { (byte) (msgData[pos] & 0xFF) }; @@ -713,218 +609,162 @@ public class RLP { } } - /* - * def rlp_encode(input): if isinstance(input,str): if len(input) == 1 and - * chr(input) < 128: return input else: return encode_length(len(input),128) - * + input elif isinstance(input,list): output = '' for item in input: - * output += rlp_encode(item) return encode_length(len(output),192) + output - * - * def encode_length(L,offset): if L < 56: return chr(L + offset) elif L < - * 256**8: BL = to_binary(L) return chr(len(BL) + offset + 55) + BL else: - * raise Exception("input too long") - * - * def to_binary(x): return '' if x == 0 else to_binary(int(x / 256)) + - * chr(x % 256) - */ - private static String rlpEncode(Object item) { - if (item instanceof String) { - String str = ((String) item); int length = str.length(); - if (length == 1 && str.charAt(0) < 128) + if (length == 1 && str.charAt(0) < OFFSET_SHORT_ITEM) return str; else - return encodeLenght(str.length(), 128) + str; + return encodeLength(str.length(), OFFSET_SHORT_ITEM) + str; } else if (item instanceof List) { - List itemList = (List) item; StringBuilder output = new StringBuilder(); for (Object oneItem : itemList) output.append(rlpEncode(oneItem)); - return encodeLenght(output.toString().length(), 192) + return encodeLength(output.toString().length(), OFFSET_SHORT_LIST) + output.toString(); } - throw new Error("unsupported type" + item.getClass()); } - private static String encodeLenght(int L, int offset) { - - if (L < 56) + /** Integer limitation goes up to 2^31-1 so length can never be bigger */ + private static String encodeLength(int L, int offset) { + if (L < SIZE_THRESHOLD) return "" + (char) (L + offset); - else if (L < (256 ^ 8)) { - + else if (L < Math.pow(256, 8)) { String BL = toBinary(L); - return "" + (char) (BL.length() + offset + 55) + BL; + return "" + (char) (BL.length() + offset + SIZE_THRESHOLD - 1) + BL; } else throw new Error("input too long"); - } - - public static byte getCommandCode(byte[] data) { - - byte command = 0; - - int index = getFirstListElement(data, 0); - - command = data[index]; - - command = ((int) (command & 0xFF) == 0x80) ? 0 : command; - - return command; - } - - public static Object decode(char[] data) { - - if (data == null || data.length == 0) - return null; - - if (data[0] >= 0xF7) { /* - * It's a list with a payload more than 55 bytes - * data[0] - 0xF7 = how many next bytes - * allocated for the length of the list - */ - ; - - byte lenghtOfLenght = (byte) (data[0] - 0xF7); - byte pow = (byte) (lenghtOfLenght - 1); - - long length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[i] << (8 * pow); - pow--; - } - - System.out.println(length); - - // now we can parse an item for data[1]..data[length] - } - - if (data[0] >= 0xC0 && data[0] < 0xF7) /* - * It's a list with a payload - * less than 55 bytes - */ - ; - - if (data[0] >= 0xB7 && data[0] < 0xC0) {/* - * It's an item with a payload - * more than 55 bytes data[0] - - * 0xB7 = how much next bytes - * allocated for the length of - * the string - */ - ; - - byte lenghtOfLenght = (byte) (data[0] - 0xB7); - byte pow = (byte) (lenghtOfLenght - 1); - - long length = 0; - - for (int i = 1; i <= lenghtOfLenght; ++i) { - - length += data[i] << (8 * pow); - pow--; - } - // now we can parse an item for data[1]..data[length] - } - - if (data[0] >= 0x80 && data[0] < 0xB7) {/* - * It's an item less than 55 - * bytes long, data[0] - 0x80 == - * lenght of the item - */ - ; - } - - if (data[0] == 0x80) /* null item */ - ; - if (data[0] < 0x80) /* single byte item */ - ; - - return null; - } - + private static String toBinary(int x) { - if (x == 0) return ""; else return toBinary(x >> 8) + ((char) (x & 0x00FF)); + } + + public static byte getCommandCode(byte[] data) { + byte command = 0; + int index = getFirstListElement(data, 0); + command = data[index]; + command = ((int) (command & 0xFF) == OFFSET_SHORT_ITEM) ? 0 : command; + return command; + } + private static Object decode(char[] data) { + + if (data == null || data.length == 0) + return null; + + if (data[0] >= 0xF7) { + /* + * It's a list with a payload more than 55 bytes + * data[0] - 0xF7 = how many next bytes allocated for the length of the list + */ + byte lengthOfLength = (byte) (data[0] - 0xF7); + + byte pow = (byte) (lengthOfLength - 1); + long length = 0; + for (int i = 1; i <= lengthOfLength; ++i) { + length += data[i] << (8 * pow); + pow--; + } + System.out.println(length); + // now we can parse an item for data[1]..data[length] + } + if (data[0] >= OFFSET_SHORT_LIST && data[0] < 0xF7) + /* + * It's a list with a payload less than 55 bytes + */ + ; + if (data[0] >= 0xB7 && data[0] < OFFSET_SHORT_LIST) { + /* + * It's an item with a payload more than 55 bytes + * data[0] - 0xB7 = how much next bytes allocated for the length of the string + */ + ; + byte lengthOfLength = (byte) (data[0] - 0xB7); + + byte pow = (byte) (lengthOfLength - 1); + long length = 0; + for (int i = 1; i <= lengthOfLength; ++i) { + length += data[i] << (8 * pow); + pow--; + } + System.out.println(length); + // now we can parse an item for data[1]..data[length] + } + if (data[0] >= OFFSET_SHORT_ITEM && data[0] < 0xB7) { + /* + * It's an item less than 55 bytes long, + * data[0] - OFFSET_SHORT_ITEM == length of the item + */ + ; + } + if (data[0] == OFFSET_SHORT_ITEM) + /* null item */ + ; + if (data[0] < OFFSET_SHORT_ITEM) + /* single byte item */ + ; + return null; } public static byte[] encodeByte(byte singleByte) { if ((singleByte & 0xFF) == 0) { - - return new byte[] { (byte) 0x80 }; + return new byte[] { (byte) OFFSET_SHORT_ITEM }; } else if ((singleByte & 0xFF) < 0x7F) { - return new byte[] { singleByte }; } else { - - return new byte[] { (byte) 0x81, singleByte }; + return new byte[] { (byte) (OFFSET_SHORT_ITEM+1), singleByte }; } } public static byte[] encodeShort(short singleShort) { - if (singleShort <= 0xFF) - return encodeByte((byte) singleShort); else { - - return new byte[] { (byte) 0x82, (byte) (singleShort >> 8 & 0xFF), + return new byte[] { (byte) (OFFSET_SHORT_ITEM+2), (byte) (singleShort >> 8 & 0xFF), (byte) (singleShort >> 0 & 0xFF) }; - } } public static byte[] encodeString(String srcString) { - return encodeElement(srcString.getBytes()); } public static byte[] encodeBigInteger(BigInteger srcBigInteger) { - return encodeElement(srcBigInteger.toByteArray()); } public static byte[] encodeElement(byte[] srcData) { if (srcData.length <= 0x37) { - // length = 8X - byte length = (byte) (0x80 + srcData.length); - + byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length); byte[] data = Arrays.copyOf(srcData, srcData.length + 1); System.arraycopy(data, 0, data, 1, srcData.length); data[0] = length; return data; - } else { - // length of length = BX // prefix = [BX, [length]] - int tmpLenght = srcData.length; + int tmpLength = srcData.length; byte byteNum = 0; - while (tmpLenght != 0) { - + while (tmpLength != 0) { ++byteNum; - tmpLenght = tmpLenght >> 8; + tmpLength = tmpLength >> 8; } - byte[] lenBytes = new byte[byteNum]; for (int i = 0; i < byteNum; ++i) { lenBytes[0] = (byte) ((srcData.length >> (8 * i)) & 0xFF); } - // first byte = F7 + bytes.length byte[] data = Arrays.copyOf(srcData, srcData.length + 1 + byteNum); System.arraycopy(data, 0, data, 1 + byteNum, srcData.length); @@ -939,7 +779,6 @@ public class RLP { int totalLength = 0; for (int i = 0; i < elements.length; ++i) { - totalLength += elements[i].length; } @@ -947,28 +786,23 @@ public class RLP { int copyPos = 0; if (totalLength <= 0x37) { - data = new byte[1 + totalLength]; - data[0] = (byte) (0xC0 + totalLength); + data = new byte[1 + totalLength]; + data[0] = (byte) (OFFSET_SHORT_LIST + totalLength); copyPos = 1; - } else { - // length of length = BX // prefix = [BX, [length]] - int tmpLenght = totalLength; + int tmpLength = totalLength; byte byteNum = 0; - while (tmpLenght != 0) { - + while (tmpLength != 0) { ++byteNum; - tmpLenght = tmpLenght >> 8; + tmpLength = tmpLength >> 8; } - - tmpLenght = totalLength; + tmpLength = totalLength; byte[] lenBytes = new byte[byteNum]; for (int i = 0; i < byteNum; ++i) { - lenBytes[i] = (byte) ((tmpLenght >> (8 * i)) & 0xFF); + lenBytes[i] = (byte) ((tmpLength >> (8 * i)) & 0xFF); } - // first byte = F7 + bytes.length data = new byte[1 + lenBytes.length + totalLength]; data[0] = (byte) (0xF7 + byteNum); @@ -976,54 +810,10 @@ public class RLP { copyPos = lenBytes.length + 1; } - for (int i = 0; i < elements.length; ++i) { - System.arraycopy(elements[i], 0, data, copyPos, elements[i].length); copyPos += elements[i].length; } - return data; } - - public static void main(String args[]) { - - char[] data = { 0xF9, 20, 100 }; - - decode(data); - } - - public static void main2(String args[]) throws UnsupportedEncodingException { - - List moreInnerList = new ArrayList(); - moreInnerList.add("aa"); - - List innerList = new ArrayList(); - innerList.add(moreInnerList); - - List list = new ArrayList(); - list.add("dogy"); - // list.add("dogy"); - // list.add("dogy"); - // list.add(innerList); - list.add("cat"); - - String result = rlpEncode(list); - - byte[] bytes = result.getBytes(); - - for (char oneChar : result.toCharArray()) { - - byte oneByte = (byte) oneChar; - - System.out.print(Integer.toHexString((int) oneByte & 0x00FF) + " "); - } - System.out.println(); - - System.out.println(result); - - // System.out.println('\u0080'); - // System.out.println(toBinary(252)); - } - } \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLPList.java b/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLPList.java index 05c85a39..05c732ad 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLPList.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/rlp/RLPList.java @@ -20,12 +20,10 @@ public class RLPList implements RLPElement{ } public void addItem(RLPElement element){ - list.add(element); } public RLPElement getElement(int index){ - return list.get(index); } @@ -52,17 +50,13 @@ public class RLPList implements RLPElement{ if (element instanceof RLPList) { RLPList rlpList = (RLPList) element; - - System.out.print("["); - + System.out.print("["); for (RLPElement singleElement : rlpList.getList()) { recursivePrint(singleElement); } System.out.print("]"); } else { - String hex = Utils.toHexString(((RLPItem) element).getData()); - System.out.print(hex + ", "); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/vo/PeerData.java b/ethereumj-core/src/main/java/org/ethereum/net/vo/PeerData.java index 0ba50f85..d1fa377a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/vo/PeerData.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/vo/PeerData.java @@ -79,13 +79,13 @@ public class PeerData { @Override public String toString() { - return "Peer: [ ip=" + getInetAddress()+ ", port=" + getPort() + ", peerId=" + Hex.toHexString( getPeerId() ) + "]"; + return "Peer: [ip=" + getInetAddress() + ", port=" + getPort() + ", peerId=" + Hex.toHexString(getPeerId()) + "]"; } @Override public boolean equals(Object obj) { - PeerData peerData2 = (PeerData)obj; - return this.getInetAddress().equals(peerData2.getInetAddress()); + PeerData peerData = (PeerData) obj; + return this.getInetAddress().equals(peerData.getInetAddress()); } @Override diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java new file mode 100644 index 00000000..c54ecd40 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -0,0 +1,159 @@ +package org.ethereum.vm; + +import java.util.HashMap; +import java.util.Map; + +/** + * Instruction set for the Ethereum Virtual Machine + */ +public enum OpCode { + + /** + * Stop and Arithmetic Operations + */ + + STOP(0x00), + ADD(0x01), + MUL(0x02), + SUB(0x03), + DIV(0x04), + SDIV(0x05), + MOD(0x06), + SMOD(0x07), + EXP(0x08), + NEG(0x09), + LT(0x0a), + GT(0x0b), + EQ(0x0c), + NOT(0x0d), + + /** + * Bitwise Logic Operations + */ + + AND(0x10), + OR(0x11), + XOR(0x12), + BYTE(0x13), + + /** + * SHA3 + */ + + SHA3(0x20), + + /** + * Environmental Information + */ + + ADDRESS(0x30), + BALANCE(0x31), + ORIGIN(0x32), + CALLER(0x33), + CALLVALUE(0x34), + CALLDATALOAD(0x35), + CALLDATASIZE(0x36), + CALLDATACOPY(0x37), + CODESIZE(0x38), + CODECOPY(0x39), + GASPRICE(0x3a), + + /** + * Block Information + */ + + PREVHASH(0x40), + COINBASE(0x41), + TIMESTAMP(0x42), + NUMBER(0x43), + DIFFICULTY(0x44), + GASLIMIT(0x45), + + /** + * Memory, Storage and Flow Operations + */ + + POP(0x50), + DUP(0x51), + SWAP(0x52), + MLOAD(0x53), + MSTORE(0x54), + MSTORE8(0x55), + SLOAD(0x56), + SSTORE(0x57), + JUMP(0x58), + JUMPI(0x59), + PC(0x5a), + MSIZE(0x5b), + GAS(0x5c), + + /** + * Push Operations + */ + + PUSH1(0x60), + PUSH2(0x61), + PUSH3(0x62), + PUSH4(0x63), + PUSH5(0x64), + PUSH6(0x65), + PUSH7(0x66), + PUSH8(0x67), + PUSH9(0x68), + PUSH10(0x69), + PUSH11(0x6a), + PUSH12(0x6b), + PUSH13(0x6c), + PUSH14(0x6d), + PUSH15(0x6e), + PUSH16(0x6f), + PUSH17(0x70), + PUSH18(0x71), + PUSH19(0x72), + PUSH20(0x73), + PUSH21(0x74), + PUSH22(0x75), + PUSH23(0x76), + PUSH24(0x77), + PUSH25(0x78), + PUSH26(0x79), + PUSH27(0x7a), + PUSH28(0x7b), + PUSH29(0x7c), + PUSH30(0x7d), + PUSH31(0x7e), + PUSH32(0x7f), + + /** + * System operations + */ + + CREATE(0xf0), + CALL(0xf1), + RETURN(0xf2), + SUICIDE(0xff); + + private byte opcode; + + private static final Map intToTypeMap = new HashMap(); + static { + for (OpCode type : OpCode.values()) { + intToTypeMap.put(type.opcode, type); + } + } + + private OpCode(int op) { + this.opcode = (byte) op; + } + + public static OpCode fromInt(int i) { + OpCode type = intToTypeMap.get(i); + if (type == null) + return OpCode.STOP; + return type; + } + + public int asInt() { + return opcode; + } +}