Document Transaction and Block and add VM OpCode enum

This commit is contained in:
nicksavers 2014-05-05 03:38:09 +02:00
parent 1f3455f5c6
commit 6fca92b62f
4 changed files with 246 additions and 37 deletions

View File

@ -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;
}
}

View File

@ -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 blocks parents 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 blocks 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<Transaction> transactionsList, List<Block> uncleList) {
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] stateHash, byte[] txTrieHash, byte[] difficulty, long timestamp, byte[] extraData, byte[] nonce, List<Transaction> transactionsList, List<Block> 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);
}
}

View File

@ -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
/* 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 +

View File

@ -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());