diff --git a/ethereumj-core/src/main/java/org/ethereum/crypto/vm/OpCode.java b/ethereumj-core/src/main/java/org/ethereum/crypto/vm/OpCode.java new file mode 100644 index 00000000..1cac5dd2 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/crypto/vm/OpCode.java @@ -0,0 +1,144 @@ +package org.ethereum.crypto.vm; + +/** + * 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 int opcode; + + private OpCode(int opcode) { + this.opcode = opcode; + } + + public int getOpCode() { + return this.opcode; + } + + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/vo/Block.java b/ethereumj-core/src/main/java/org/ethereum/net/vo/Block.java index 1147101a..0fbc97c8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/vo/Block.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/vo/Block.java @@ -11,21 +11,41 @@ import java.util.ArrayList; import java.util.List; /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 13/04/14 19:34 + * The block in Ethereum is the collection of relevant pieces of information + * (known as the blockheader), H, together with information corresponding to + * the comprised transactions, R, and a set of other blockheaders U that are known + * to have a parent equal to the present block’s parent’s parent + * (such blocks are known as uncles). */ public class Block { + private static int LIMIT_FACTOR = (int) Math.pow(2, 16); + private static double EMA_FACTOR = 1.5; + /* A scalar value equal to the current limit of gas expenditure per block */ + private static int GAS_LIMIT = (int) Math.pow(10, 6); + private RLPList rawData; private boolean parsed = false; private byte[] hash; + + /* The SHA3 256-bit hash of the parent block, in its entirety */ private byte[] parentHash; + /* The SHA3 256-bit hash of the uncles list portion of this block */ private byte[] unclesHash; + /* The 160-bit address to which all fees collected from the + * successful mining of this block be transferred; formally */ private byte[] coinbase; + /* The SHA3 256-bit hash of the root node of the state trie, + * after all transactions are executed and finalisations applied */ private byte[] stateHash; - private byte[] txListHash; + /* The SHA3 256-bit hash of the root node of the trie structure + * populated with each transaction in the transactions list portion + * of the block */ + private byte[] txTrieHash; + /* A scalar value corresponding to the difficulty level of this block. + * This can be calculated from the previous block’s difficulty level + * and the timestamp */ private byte[] difficulty; private long timestamp; @@ -40,12 +60,12 @@ public class Block { this.parsed = false; } - public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] stateHash, byte[] txListHash, byte[] difficulty, long timestamp, byte[] extraData, byte[] nonce, List transactionsList, List uncleList) { + public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] stateHash, byte[] txTrieHash, byte[] difficulty, long timestamp, byte[] extraData, byte[] nonce, List transactionsList, List uncleList) { this.parentHash = parentHash; this.unclesHash = unclesHash; this.coinbase = coinbase; this.stateHash = stateHash; - this.txListHash = txListHash; + this.txTrieHash = txTrieHash; this.difficulty = difficulty; this.timestamp = timestamp; this.extraData = extraData; @@ -66,7 +86,7 @@ public class Block { this.unclesHash = ((RLPItem) params.get(1)).getData(); this.coinbase = ((RLPItem) params.get(2)).getData(); this.stateHash = ((RLPItem) params.get(3)).getData(); - this.txListHash = ((RLPItem) params.get(4)).getData(); + this.txTrieHash = ((RLPItem) params.get(4)).getData(); this.difficulty = ((RLPItem) params.get(5)).getData(); byte[] tsBytes = ((RLPItem) params.get(6)).getData(); @@ -95,6 +115,11 @@ public class Block { return hash; } + public Block getParent() { + // TODO: Implement + return null; + } + public byte[] getParentHash() { if (!parsed) parseRLP(); return parentHash; @@ -115,9 +140,9 @@ public class Block { return stateHash; } - public byte[] getTxListHash() { + public byte[] getTxTrieHash() { if (!parsed) parseRLP(); - return txListHash; + return txTrieHash; } public byte[] getDifficulty() { @@ -160,11 +185,37 @@ public class Block { ", unclesHash=" + Utils.toHexString(unclesHash) + ", coinbase=" + Utils.toHexString(coinbase) + ", stateHash=" + Utils.toHexString(stateHash) + - ", txListHash=" + Utils.toHexString(txListHash) + + ", txTrieHash=" + Utils.toHexString(txTrieHash) + ", difficulty=" + Utils.toHexString(difficulty) + ", timestamp=" + timestamp + ", extraData=" + Utils.toHexString(extraData) + ", nonce=" + Utils.toHexString(nonce) + ']'; } + + /** + * Because every transaction published into the blockchain imposes on the + * network the cost of needing to download and verify it, there is a need + * for some regulatory mechanism to prevent abuse. + * + * To solve this we simply institute a floating cap: + * + * No block can have more operations than BLK_LIMIT_FACTOR times + * the long-term exponential moving average. + * + * Specifically: + * + * blk.oplimit = floor((blk.parent.oplimit * (EMAFACTOR - 1) + * + floor(GAS_LIMIT * BLK_LIMIT_FACTOR)) / EMA_FACTOR) + * + * BLK_LIMIT_FACTOR and EMA_FACTOR are constants that will be set + * to 65536 and 1.5 for the time being, but will likely be changed + * after further analysis. + * + * @return + */ + public double getOplimit() { + return Math.floor((this.getParent().getOplimit() * (EMA_FACTOR - 1) + + Math.floor(GAS_LIMIT * LIMIT_FACTOR)) / EMA_FACTOR); + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/vo/Transaction.java b/ethereumj-core/src/main/java/org/ethereum/net/vo/Transaction.java index 5777532e..62475570 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/vo/Transaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/vo/Transaction.java @@ -7,35 +7,49 @@ import org.ethereum.net.rlp.RLPList; import org.ethereum.util.Utils; /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 21/04/14 09:19 + * A transaction (formally, T ) is a single cryptographically + * signed instruction sent by an actor external to Ethereum. + * An external actor can be a person (via a mobile device or desktop computer) + * or could be from a piece of automated software running on a server. + * There are two types of transactions: those which result in message calls + * and those which result in the creation of new contracts. */ public class Transaction { private RLPList rawData; private boolean parsed = false; -// creation contract tx or simple send tx -// [ nonce, value, receiveAddress, gasPrice, gasDeposit, data, signatureV, signatureR, signatureS ] -// or -// [ nonce, endowment, 0, gasPrice, gasDeposit (for init), body, init, signatureV, signatureR, signatureS ] - + /* creation contract tx or simple send tx + * [ nonce, value, receiveAddress, gasPrice, gasDeposit, data, signatureV, signatureR, signatureS ] + * or + * [ nonce, endowment, 0, gasPrice, gasDeposit (for init), body, init, signatureV, signatureR, signatureS ] + */ + + /* SHA3 hash of the rlpEncoded transaction */ private byte[] hash; + /* a counter used to make sure each transaction can only be processed once */ private byte[] nonce; + /* the amount of ether to transfer (calculated as wei) */ private byte[] value; - - // In creation transaction the receive address is - 0 - private byte[] receiveAddress; + /* the address of the destination account + * In creation transaction the receive address is - 0 */ + private byte[] receiveAddress; + /* the amount of ether to pay as a transaction fee + * to the miner for each unit of gas */ private byte[] gasPrice; - private byte[] gas; - - // Contract creation [data] will hold the contract - // for other transaction [data] can hold data + /* the amount of "gas" to allow for the computation. + * Gas is the fuel of the computational engine; + * every computational step taken and every byte added + * to the state or transaction list consumes some gas. */ + private byte[] gasLimit; + /* An unlimited size byte array specifying + * either input [data] of the message call + * or the [body] for a new contract */ private byte[] data; + /* Initialisation code for a new contract */ private byte[] init; - - // Signature + /* the elliptic curve signature + * (including public key recovery bits) */ private ECDSASignature signature; public Transaction(RLPList rawData) { @@ -48,7 +62,7 @@ public class Transaction { this.value = value; this.receiveAddress = recieveAddress; this.gasPrice = gasPrice; - this.gas = gas; + this.gasLimit = gas; this.data = data; this.signature = ECDSASignature.fromComponents(r, s, v); parsed = true; @@ -61,7 +75,7 @@ public class Transaction { this.value = ((RLPItem) rawData.getElement(1)).getData(); this.receiveAddress = ((RLPItem) rawData.getElement(2)).getData(); this.gasPrice = ((RLPItem) rawData.getElement(3)).getData(); - this.gas = ((RLPItem) rawData.getElement(4)).getData(); + this.gasLimit = ((RLPItem) rawData.getElement(4)).getData(); this.data = ((RLPItem) rawData.getElement(5)).getData(); if (rawData.size() == 9){ // Simple transaction @@ -113,9 +127,9 @@ public class Transaction { return gasPrice; } - public byte[] getGas() { + public byte[] getGasLimit() { if (!parsed) rlpParse(); - return gas; + return gasLimit; } public byte[] getData() { @@ -141,7 +155,7 @@ public class Transaction { ", value=" + Utils.toHexString(value) + ", receiveAddress=" + Utils.toHexString(receiveAddress) + ", gasPrice=" + Utils.toHexString(gasPrice) + - ", gas=" + Utils.toHexString(gas) + + ", gas=" + Utils.toHexString(gasLimit) + ", data=" + Utils.toHexString(data) + ", init=" + Utils.toHexString(init) + ", signatureV=" + signature.v + diff --git a/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java b/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java index 5812f3e3..0d8cb9d5 100644 --- a/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java @@ -214,7 +214,7 @@ public class MessagesTest { Utils.toHexString( tx.getGasPrice() ).toUpperCase()); assertEquals("64", - Utils.toHexString( tx.getGas() ).toUpperCase()); + Utils.toHexString( tx.getGasLimit() ).toUpperCase()); assertEquals("NULL", Utils.toHexString( tx.getData() ).toUpperCase()); @@ -265,7 +265,7 @@ public class MessagesTest { Utils.toHexString( tx.getGasPrice() ).toUpperCase()); assertEquals("2710", - Utils.toHexString( tx.getGas() ).toUpperCase()); + Utils.toHexString( tx.getGasLimit() ).toUpperCase()); assertEquals("606956330C0D630000003359366000530A0D630000003359602060005301356000533557604060005301600054630000000C58", Utils.toHexString( tx.getData() ).toUpperCase()); @@ -300,7 +300,7 @@ public class MessagesTest { Utils.toHexString( tx.getGasPrice() ).toUpperCase()); assertEquals("2710", - Utils.toHexString( tx.getGas() ).toUpperCase()); + Utils.toHexString( tx.getGasLimit() ).toUpperCase()); assertEquals("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002D0ACEEE7E5AB874E22CCF8D1A649F59106D74E8", Utils.toHexString( tx.getData() ).toUpperCase()); @@ -354,7 +354,7 @@ public class MessagesTest { Utils.toHexString(block.getStateHash()).toUpperCase()); assertEquals("1DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347", - Utils.toHexString(block.getTxListHash()).toUpperCase()); + Utils.toHexString(block.getTxTrieHash()).toUpperCase()); assertEquals("02471A26", Utils.toHexString(block.getDifficulty()).toUpperCase()); assertEquals(1398260220, block.getTimestamp()); @@ -399,7 +399,7 @@ public class MessagesTest { Utils.toHexString(block.getStateHash()).toUpperCase()); assertEquals("9BFE4817D274EA3EB8672E9FE848C3885B53BBBD1D7C26E6039F90FB96B942B0", - Utils.toHexString(block.getTxListHash()).toUpperCase()); + Utils.toHexString(block.getTxTrieHash()).toUpperCase()); assertEquals("3FF000", Utils.toHexString(block.getDifficulty()).toUpperCase()); assertEquals(1396643511, block.getTimestamp());