From 6ec5dd9d12f39a3e7d77d938628d38a2ea64ab8d Mon Sep 17 00:00:00 2001 From: nicksavers Date: Fri, 6 Jun 2014 15:30:24 +0200 Subject: [PATCH] Calculate txTrieRoot from actual transactions in a block and move block header to separate class --- .../main/java/org/ethereum/core/Block.java | 244 ++++++------------ .../java/org/ethereum/core/BlockHeader.java | 232 +++++++++++++++++ .../main/java/org/ethereum/core/Genesis.java | 34 ++- .../java/org/ethereum/core/Transaction.java | 2 +- ...ionRecipe.java => TransactionReceipt.java} | 21 +- .../src/main/java/org/ethereum/util/RLP.java | 21 +- .../main/java/org/ethereum/vm/DataWord.java | 2 +- .../src/main/resources/system.properties | 2 +- .../java/org/ethereum/core/StateTest.java | 17 +- .../test/java/org/ethereum/util/RLPTest.java | 36 +++ .../java/org/ethereum/vm/DataWordTest.java | 22 +- 11 files changed, 415 insertions(+), 218 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java rename ethereumj-core/src/main/java/org/ethereum/core/{TransactionRecipe.java => TransactionReceipt.java} (66%) diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Block.java b/ethereumj-core/src/main/java/org/ethereum/core/Block.java index 2e04a787..5fcb3181 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Block.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Block.java @@ -6,9 +6,7 @@ import org.ethereum.trie.Trie; import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPElement; -import org.ethereum.util.RLPItem; import org.ethereum.util.RLPList; -import org.ethereum.util.Utils; import org.spongycastle.util.BigIntegers; import java.math.BigInteger; @@ -27,81 +25,42 @@ public class Block { /* A scalar value equal to the mininum limit of gas expenditure per block */ private static long MIN_GAS_LIMIT = BigInteger.valueOf(10).pow(4).longValue(); + private BlockHeader header; + + /* Transactions */ + private List txReceiptList = new ArrayList(); + private List transactionsList = new ArrayList(); + + /* Uncles */ + private List uncleList = new ArrayList(); + + /* Private */ + private byte[] rlpEncoded; 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[] stateRoot; - /* The SHA3 256-bit hash of the root node of the trie structure - * populated with each transaction recipe in the transaction recipes - * list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_reciepe)] - * of the block */ - private byte[] txTrieRoot; - /* 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; - /* A scalar value equal to the reasonable output of Unix's time() - * at this block's inception */ - private long timestamp; - /* A scalar value equal to the number of ancestor blocks. - * The genesis block has a number of zero */ - private long number; - /* A scalar value equal to the minimum price of gas a transaction - * must have provided in order to be sufficient for inclusion - * by this miner in this block */ - private long minGasPrice; - /* A scalar value equal to the current limit of gas expenditure per block */ - private long gasLimit; - /* A scalar value equal to the total gas used in transactions in this block */ - private long gasUsed; - /* An arbitrary byte array containing data relevant to this block. - * With the exception of the genesis block, this must be 32 bytes or fewer */ - private byte[] extraData; - /* A 256-bit hash which proves that a sufficient amount - * of computation has been carried out on this block */ - private byte[] nonce; - - private List transactionsList = new ArrayList(); - private List txRecipeList = new ArrayList(); - - private List uncleList = new ArrayList(); - private Trie state; - + private Trie accountState; + private Trie txsState; + + /* Constructors */ + public Block(byte[] rawData) { this.rlpEncoded = rawData; this.parsed = false; } public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, - byte[] txTrieRoot, byte[] difficulty, long number, - long minGasPrice, long gasLimit, long gasUsed, long timestamp, - byte[] extraData, byte[] nonce, List transactionsList, - List uncleList) { - this.parentHash = parentHash; - this.unclesHash = unclesHash; - this.coinbase = coinbase; - this.state = new Trie(Config.STATE_DB.getDb()); - this.stateRoot = state.getRootHash(); - this.txTrieRoot = txTrieRoot; - this.difficulty = difficulty; - this.number = number; - this.minGasPrice = minGasPrice; - this.gasLimit = gasLimit; - this.gasUsed = gasUsed; - this.timestamp = timestamp; - this.extraData = extraData; - this.nonce = nonce; + byte[] difficulty, long number, long minGasPrice, long gasLimit, + long gasUsed, long timestamp, byte[] extraData, byte[] nonce, + List transactionsList, List uncleList) { + this.header = new BlockHeader(parentHash, unclesHash, coinbase, + difficulty, number, minGasPrice, gasLimit, gasUsed, + timestamp, extraData, nonce); + this.accountState = new Trie(Config.STATE_DB.getDb()); + this.txsState = new Trie(null); + this.header.setStateRoot(accountState.getRootHash()); + this.header.setTxTrieRoot(txsState.getRootHash()); this.transactionsList = transactionsList; this.uncleList = uncleList; this.parsed = true; @@ -117,46 +76,28 @@ public class Block { // Parse Header RLPList header = (RLPList) block.get(0); - - this.parentHash = ((RLPItem) header.get(0)).getRLPData(); - this.unclesHash = ((RLPItem) header.get(1)).getRLPData(); - this.coinbase = ((RLPItem) header.get(2)).getRLPData(); - this.stateRoot = ((RLPItem) header.get(3)).getRLPData(); - this.txTrieRoot = ((RLPItem) header.get(4)).getRLPData(); - this.difficulty = ((RLPItem) header.get(5)).getRLPData(); - - byte[] nrBytes = ((RLPItem) header.get(6)).getRLPData(); - byte[] gpBytes = ((RLPItem) header.get(7)).getRLPData(); - byte[] glBytes = ((RLPItem) header.get(8)).getRLPData(); - byte[] guBytes = ((RLPItem) header.get(9)).getRLPData(); - byte[] tsBytes = ((RLPItem) header.get(10)).getRLPData(); - - this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue(); - this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue(); - this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue(); - this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue(); - this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue(); - - this.extraData = ((RLPItem) header.get(11)).getRLPData(); - this.nonce = ((RLPItem) header.get(12)).getRLPData(); + this.header = new BlockHeader(header); // Parse Transactions - RLPList transactions = (RLPList) block.get(1); - for (RLPElement rlpTx : transactions){ - - RLPElement txData = ((RLPList)rlpTx).get(0); + this.txsState = new Trie(null); + RLPList txReceipts = (RLPList) block.get(1); + for (int i = 0; i < txReceipts.size(); i++) { + RLPElement rlpTxReceipt = txReceipts.get(i); + RLPElement txData = ((RLPList)rlpTxReceipt).get(0); Transaction tx = new Transaction(txData.getRLPData()); this.transactionsList.add(tx); + this.txsState.update(RLP.encodeInt(i), tx.getEncoded()); // YP 4.3.1 - RLPElement cummGas = ((RLPList)rlpTx).get(1); - RLPElement pstTxState = ((RLPList)rlpTx).get(2); + RLPElement cummGas = ((RLPList)rlpTxReceipt).get(1); + RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(2); - TransactionRecipe txRecipe = - new TransactionRecipe(tx, cummGas.getRLPData(), pstTxState.getRLPData()); - txRecipeList.add(txRecipe); +// TransactionReceipt txReceipt = +// new TransactionReceipt(tx, cummGas.getRLPData(), pstTxState.getRLPData()); +// txReceiptList.add(txReceipt); } + this.header.setTxTrieRoot(txsState.getRootHash()); // Parse Uncles RLPList uncleBlocks = (RLPList) block.get(2); @@ -180,67 +121,67 @@ public class Block { public byte[] getParentHash() { if (!parsed) parseRLP(); - return parentHash; + return this.header.getParentHash(); } public byte[] getUnclesHash() { if (!parsed) parseRLP(); - return unclesHash; + return this.header.getUnclesHash(); } public byte[] getCoinbase() { if (!parsed) parseRLP(); - return coinbase; + return this.header.getCoinbase(); } public byte[] getStateRoot() { if (!parsed) parseRLP(); - return this.stateRoot; + return this.header.getStateRoot(); } public byte[] getTxTrieRoot() { if (!parsed) parseRLP(); - return txTrieRoot; + return this.header.getTxTrieRoot(); } public byte[] getDifficulty() { if (!parsed) parseRLP(); - return difficulty; + return this.header.getDifficulty(); } public long getTimestamp() { if (!parsed) parseRLP(); - return timestamp; + return this.header.getTimestamp(); } public long getNumber() { if (!parsed) parseRLP(); - return number; + return this.header.getNumber(); } public long getMinGasPrice() { if (!parsed) parseRLP(); - return minGasPrice; + return this.header.getMinGasPrice(); } public long getGasLimit() { if (!parsed) parseRLP(); - return gasLimit; + return this.header.getGasLimit(); } public long getGasUsed() { if (!parsed) parseRLP(); - return gasUsed; + return this.header.getGasUsed(); } public byte[] getExtraData() { if (!parsed) parseRLP(); - return extraData; + return this.header.getExtraData(); } public byte[] getNonce() { if (!parsed) parseRLP(); - return nonce; + return this.header.getNonce(); } public List getTransactionsList() { @@ -251,12 +192,12 @@ public class Block { return transactionsList; } - public List getTxRecipeList() { + public List getTxReceiptList() { if (!parsed) parseRLP(); if (transactionsList == null) { - this.txRecipeList = new ArrayList(); + this.txReceiptList = new ArrayList(); } - return txRecipeList; + return txReceiptList; } public List getUncleList() { @@ -279,27 +220,13 @@ public class Block { toStringBuff.setLength(0); toStringBuff.append("BlockData [\n"); toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append("\n"); - toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("\n"); - toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("\n"); - toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("\n"); - toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("\n"); - toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n"); - toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("\n"); - toStringBuff.append(" number=" + number).append("\n"); - toStringBuff.append(" minGasPrice=" + minGasPrice).append("\n"); - toStringBuff.append(" gasLimit=" + gasLimit).append("\n"); - toStringBuff.append(" gasUsed=" + gasUsed).append("\n"); - toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n"); - toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("\n"); - toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("\n"); - - for (TransactionRecipe txRecipe : getTxRecipeList()){ - + toStringBuff.append(header.toString()); + + for (TransactionReceipt txReceipt : getTxReceiptList()) { toStringBuff.append("\n"); - toStringBuff.append(txRecipe.toString()); + toStringBuff.append(txReceipt.toString()); } - - toStringBuff.append("\n]"); + toStringBuff.append("\n ]"); return toStringBuff.toString(); } @@ -309,20 +236,8 @@ public class Block { toStringBuff.setLength(0); toStringBuff.append("BlockData ["); toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append(""); - toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append(""); - toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append(""); - toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append(""); - toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append(""); - toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append(""); - toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append(""); - toStringBuff.append(" number=" + number).append(""); - toStringBuff.append(" minGasPrice=" + minGasPrice).append(""); - toStringBuff.append(" gasLimit=" + gasLimit).append(""); - toStringBuff.append(" gasUsed=" + gasUsed).append(""); - toStringBuff.append(" timestamp=" + timestamp).append(""); - toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append(""); - toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append(""); - + toStringBuff.append(header.toFlatString()); + for (Transaction tx : getTransactionsList()){ toStringBuff.append("\n"); @@ -334,8 +249,10 @@ public class Block { } public byte[] updateState(byte[] key, byte[] value) { - this.state.update(key, value); - return this.stateRoot = this.state.getRootHash(); + this.accountState.update(key, value); + byte[] stateRoot = this.accountState.getRootHash(); + this.header.setStateRoot(stateRoot); + return stateRoot; } /** @@ -365,21 +282,21 @@ public class Block { * @return */ public long calcGasLimit() { - if (parentHash == null) + if (this.header.getParentHash() == null) return 1000000L; else { Block parent = this.getParent(); - return Math.max(MIN_GAS_LIMIT, (parent.gasLimit * (1024 - 1) + (parent.gasUsed * 6 / 5)) / 1024); + return Math.max(MIN_GAS_LIMIT, (parent.header.getGasLimit() * (1024 - 1) + (parent.header.getGasUsed() * 6 / 5)) / 1024); } } public byte[] calcDifficulty() { - if (parentHash == null) + if (this.header.getParentHash() == null) return Genesis.DIFFICULTY; else { Block parent = this.getParent(); - long parentDifficulty = new BigInteger(1, parent.difficulty).longValue(); - long newDifficulty = timestamp >= parent.timestamp + 42 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10)); + long parentDifficulty = new BigInteger(1, parent.header.getDifficulty()).longValue(); + long newDifficulty = this.header.getTimestamp() >= parent.header.getTimestamp() + 42 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10)); return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty)); } } @@ -395,24 +312,7 @@ public class Block { // Object[] uncles = this.getUncleList().toArray(); // return RLP.encode(new Object[] { header, transactions, uncles }); - byte[] parentHash = RLP.encodeElement(this.parentHash); - byte[] unclesHash = RLP.encodeElement(this.unclesHash); - byte[] coinbase = RLP.encodeElement(this.coinbase); - byte[] stateRoot = RLP.encodeElement(this.stateRoot); - byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot); - byte[] difficulty = RLP.encodeElement(this.difficulty); - byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number)); - byte[] minGasPrice = RLP.encodeBigInteger(BigInteger.valueOf(this.minGasPrice)); - byte[] gasLimit = RLP.encodeBigInteger(BigInteger.valueOf(this.gasLimit)); - byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed)); - byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp)); - byte[] extraData = RLP.encodeElement(this.extraData); - byte[] nonce = RLP.encodeElement(this.nonce); - - byte[] header = RLP.encodeList(parentHash, unclesHash, coinbase, - stateRoot, txTrieRoot, difficulty, number, - minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce); - + byte[] header = this.header.getEncoded(); byte[] transactions = RLP.encodeList(); byte[] uncles = RLP.encodeList(); diff --git a/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java b/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java new file mode 100644 index 00000000..83d67e3a --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java @@ -0,0 +1,232 @@ +package org.ethereum.core; + +import java.math.BigInteger; + +import org.ethereum.util.ByteUtil; +import org.ethereum.util.RLP; +import org.ethereum.util.RLPItem; +import org.ethereum.util.RLPList; +import org.ethereum.util.Utils; + +/** + * Block header is a value object containing + * the basic information of a block + */ +public class BlockHeader { + + /* 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[] stateRoot; + /* The SHA3 256-bit hash of the root node of the trie structure + * populated with each transaction recipe in the transaction recipes + * list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_reciepe)] + * of the block */ + private byte[] txTrieRoot; + /* 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; + /* A scalar value equal to the reasonable output of Unix's time() + * at this block's inception */ + private long timestamp; + /* A scalar value equal to the number of ancestor blocks. + * The genesis block has a number of zero */ + private long number; + /* A scalar value equal to the minimum price of gas a transaction + * must have provided in order to be sufficient for inclusion + * by this miner in this block */ + private long minGasPrice; + /* A scalar value equal to the current limit of gas expenditure per block */ + private long gasLimit; + /* A scalar value equal to the total gas used in transactions in this block */ + private long gasUsed; + /* An arbitrary byte array containing data relevant to this block. + * With the exception of the genesis block, this must be 32 bytes or fewer */ + private byte[] extraData; + /* A 256-bit hash which proves that a sufficient amount + * of computation has been carried out on this block */ + private byte[] nonce; + + public BlockHeader(RLPList rlpHeader) { + this.parentHash = ((RLPItem) rlpHeader.get(0)).getRLPData(); + this.unclesHash = ((RLPItem) rlpHeader.get(1)).getRLPData(); + this.coinbase = ((RLPItem) rlpHeader.get(2)).getRLPData(); + this.stateRoot = ((RLPItem) rlpHeader.get(3)).getRLPData(); + this.txTrieRoot = ((RLPItem) rlpHeader.get(4)).getRLPData(); + this.difficulty = ((RLPItem) rlpHeader.get(5)).getRLPData(); + + byte[] nrBytes = ((RLPItem) rlpHeader.get(6)).getRLPData(); + byte[] gpBytes = ((RLPItem) rlpHeader.get(7)).getRLPData(); + byte[] glBytes = ((RLPItem) rlpHeader.get(8)).getRLPData(); + byte[] guBytes = ((RLPItem) rlpHeader.get(9)).getRLPData(); + byte[] tsBytes = ((RLPItem) rlpHeader.get(10)).getRLPData(); + + this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue(); + this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue(); + this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue(); + this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue(); + this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue(); + + this.extraData = ((RLPItem) rlpHeader.get(11)).getRLPData(); + this.nonce = ((RLPItem) rlpHeader.get(12)).getRLPData(); + } + + public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase, + byte[] difficulty, long number, long minGasPrice, long gasLimit, + long gasUsed, long timestamp, byte[] extraData, byte[] nonce) { + this.parentHash = parentHash; + this.unclesHash = unclesHash; + this.coinbase = coinbase; + this.difficulty = difficulty; + this.number = number; + this.minGasPrice = minGasPrice; + this.gasLimit = gasLimit; + this.gasUsed = gasUsed; + this.timestamp = timestamp; + this.extraData = extraData; + this.nonce = nonce; + } + + public byte[] getParentHash() { + return parentHash; + } + public void setParentHash(byte[] parentHash) { + this.parentHash = parentHash; + } + public byte[] getUnclesHash() { + return unclesHash; + } + public void setUnclesHash(byte[] unclesHash) { + this.unclesHash = unclesHash; + } + public byte[] getCoinbase() { + return coinbase; + } + public void setCoinbase(byte[] coinbase) { + this.coinbase = coinbase; + } + public byte[] getStateRoot() { + return stateRoot; + } + public void setStateRoot(byte[] stateRoot) { + this.stateRoot = stateRoot; + } + public byte[] getTxTrieRoot() { + return txTrieRoot; + } + public void setTxTrieRoot(byte[] txTrieRoot) { + this.txTrieRoot = txTrieRoot; + } + public byte[] getDifficulty() { + return difficulty; + } + public void setDifficulty(byte[] difficulty) { + this.difficulty = difficulty; + } + public long getTimestamp() { + return timestamp; + } + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + public long getNumber() { + return number; + } + public void setNumber(long number) { + this.number = number; + } + public long getMinGasPrice() { + return minGasPrice; + } + public void setMinGasPrice(long minGasPrice) { + this.minGasPrice = minGasPrice; + } + public long getGasLimit() { + return gasLimit; + } + public void setGasLimit(long gasLimit) { + this.gasLimit = gasLimit; + } + public long getGasUsed() { + return gasUsed; + } + public void setGasUsed(long gasUsed) { + this.gasUsed = gasUsed; + } + public byte[] getExtraData() { + return extraData; + } + public void setExtraData(byte[] extraData) { + this.extraData = extraData; + } + public byte[] getNonce() { + return nonce; + } + public void setNonce(byte[] nonce) { + this.nonce = nonce; + } + + public byte[] getEncoded() { + byte[] parentHash = RLP.encodeElement(this.parentHash); + byte[] unclesHash = RLP.encodeElement(this.unclesHash); + byte[] coinbase = RLP.encodeElement(this.coinbase); + byte[] stateRoot = RLP.encodeElement(this.stateRoot); + byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot); + byte[] difficulty = RLP.encodeElement(this.difficulty); + byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number)); + byte[] minGasPrice = RLP.encodeBigInteger(BigInteger.valueOf(this.minGasPrice)); + byte[] gasLimit = RLP.encodeBigInteger(BigInteger.valueOf(this.gasLimit)); + byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed)); + byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp)); + byte[] extraData = RLP.encodeElement(this.extraData); + byte[] nonce = RLP.encodeElement(this.nonce); + + return RLP.encodeList(parentHash, unclesHash, coinbase, + stateRoot, txTrieRoot, difficulty, number, + minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce); + } + + private StringBuffer toStringBuff = new StringBuffer(); + + public String toString() { + toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("\n"); + toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("\n"); + toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("\n"); + toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("\n"); + toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n"); + toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("\n"); + toStringBuff.append(" number=" + number).append("\n"); + toStringBuff.append(" minGasPrice=" + minGasPrice).append("\n"); + toStringBuff.append(" gasLimit=" + gasLimit).append("\n"); + toStringBuff.append(" gasUsed=" + gasUsed).append("\n"); + toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n"); + toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("\n"); + toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("\n"); + return toStringBuff.toString(); + } + + public String toFlatString() { + toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append(""); + toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append(""); + toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append(""); + toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append(""); + toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append(""); + toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append(""); + toStringBuff.append(" number=" + number).append(""); + toStringBuff.append(" minGasPrice=" + minGasPrice).append(""); + toStringBuff.append(" gasLimit=" + gasLimit).append(""); + toStringBuff.append(" gasUsed=" + gasUsed).append(""); + toStringBuff.append(" timestamp=" + timestamp).append(""); + toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append(""); + toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append(""); + return toStringBuff.toString(); + } + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java b/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java index b103f379..5058384e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java @@ -13,6 +13,17 @@ public class Genesis extends Block { Logger logger = LoggerFactory.getLogger(this.getClass()); + private AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200)); + private String[] premine = new String[] { + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // # (M) + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // # (A) + "e6716f9544a56c530d868e4bfbacb172315bdead", // # (J) + "8a40bfaa73256b60764c1bf40675a99083efb075", // # (G) + "e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH) + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // # (V) + "6c386a4b26f73c802f34673f7248bb118f97424a", // # (HH) + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826" }; // # (R) + private static byte[] zeroHash256 = new byte[32]; private static byte[] zeroHash160 = new byte[20]; private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList()); @@ -20,7 +31,6 @@ public class Genesis extends Block { public static byte[] PARENT_HASH = zeroHash256; public static byte[] UNCLES_HASH = sha3EmptyList; public static byte[] COINBASE = zeroHash160; - public static byte[] TX_TRIE_ROOT = new byte[0]; public static byte[] DIFFICULTY = BigInteger.valueOf(2).pow(22).toByteArray(); public static long NUMBER = 0; public static long MIN_GAS_PRICE = 0; @@ -33,28 +43,14 @@ public class Genesis extends Block { private static Block instance; private Genesis() { - super(PARENT_HASH, UNCLES_HASH, COINBASE, TX_TRIE_ROOT, DIFFICULTY, + super(PARENT_HASH, UNCLES_HASH, COINBASE, DIFFICULTY, NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP, EXTRA_DATA, NONCE, null, null); // Premine state - AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200)); - // # (M) - this.updateState(Hex.decode("2ef47100e0787b915105fd5e3f4ff6752079d5cb"), acct.getEncoded()); - // # (A) - this.updateState(Hex.decode("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"), acct.getEncoded()); - // # (J) - this.updateState(Hex.decode("e6716f9544a56c530d868e4bfbacb172315bdead"), acct.getEncoded()); - // # (G) - this.updateState(Hex.decode("8a40bfaa73256b60764c1bf40675a99083efb075"), acct.getEncoded()); - // # (CH) - this.updateState(Hex.decode("e4157b34ea9615cfbde6b4fda419828124b70c78"), acct.getEncoded()); - // # (V) - this.updateState(Hex.decode("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"), acct.getEncoded()); - // # (HH) - this.updateState(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct.getEncoded()); - // # (R) - this.updateState(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct.getEncoded()); + for (String address : premine) { + this.updateState(Hex.decode(address), acct.getEncoded()); + } logger.info("Genesis-hash: " + Hex.toHexString(this.getHash())); logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot())); diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java index 2395efc1..4f550cd1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java @@ -214,7 +214,7 @@ public class Transaction { ", signatureV=" + signature.v + ", signatureR=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.r)) + ", signatureS=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.s)) + - "\n ]"; + " ]"; } /** diff --git a/ethereumj-core/src/main/java/org/ethereum/core/TransactionRecipe.java b/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java similarity index 66% rename from ethereumj-core/src/main/java/org/ethereum/core/TransactionRecipe.java rename to ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java index f9e64131..22c6b95b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/TransactionRecipe.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java @@ -3,31 +3,28 @@ package org.ethereum.core; import org.ethereum.util.RLP; import org.spongycastle.util.encoders.Hex; -import java.util.Arrays; - /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 06/06/2014 04:03 + * The transaction receipt is a tuple of three items + * comprising the transaction, together with the post-transaction state, + * and the cumulative gas used in the block containing the transaction receipt + * as of immediately after the transaction has happened, */ - -public class TransactionRecipe { +public class TransactionReceipt { private Transaction transaction; private byte[] postTxState; private byte[] cumulativeGas; - /* Tx Recipe in encoded form */ + /* Tx Receipt in encoded form */ private byte[] rlpEncoded; - - public TransactionRecipe(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) { + public TransactionReceipt(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) { this.transaction = transaction; this.postTxState = postTxState; this.cumulativeGas = cumulativeGas; } - public byte[] getEncoded(){ + public byte[] getEncoded() { if(rlpEncoded != null) return rlpEncoded; @@ -42,7 +39,7 @@ public class TransactionRecipe { @Override public String toString() { - return "TransactionRecipe[" + + return "TransactionReceipt[" + "\n " + transaction + "\n , postTxState=" + Hex.toHexString(postTxState) + "\n , cumulativeGas=" + Hex.toHexString(cumulativeGas) + diff --git a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java index 48562cc1..f1af2ce9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java @@ -762,7 +762,7 @@ public class RLP { } else if ((singleByte & 0xFF) < 0x7F) { return new byte[] { singleByte }; } else { - return new byte[] { (byte) (OFFSET_SHORT_ITEM+1), singleByte }; + return new byte[] { (byte) (OFFSET_SHORT_ITEM + 1), singleByte }; } } @@ -775,6 +775,25 @@ public class RLP { (byte) (singleShort >> 0 & 0xFF) }; } } + + public static byte[] encodeInt(int singleInt) { + if (singleInt <= 0xFF) + return encodeByte((byte) singleInt); + else if (singleInt <= 0xFFFF) + return encodeShort((short) singleInt); + else if (singleInt <= 0xFFFFFF) + return new byte[] { (byte) (OFFSET_SHORT_ITEM + 3), + (byte) (singleInt >>> 16), + (byte) (singleInt >>> 8), + (byte) singleInt}; + else { + return new byte[] { (byte) (OFFSET_SHORT_ITEM + 4), + (byte) (singleInt >>> 24), + (byte) (singleInt >>> 16), + (byte) (singleInt >>> 8), + (byte) singleInt}; + } + } public static byte[] encodeString(String srcString) { return encodeElement(srcString.getBytes()); diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java b/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java index b97ead32..dc09ab50 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java @@ -12,7 +12,7 @@ import java.nio.ByteBuffer; */ public class DataWord { - static DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack + public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack byte[] data = new byte[32]; diff --git a/ethereumj-core/src/main/resources/system.properties b/ethereumj-core/src/main/resources/system.properties index 8925ac14..aaa27411 100644 --- a/ethereumj-core/src/main/resources/system.properties +++ b/ethereumj-core/src/main/resources/system.properties @@ -69,4 +69,4 @@ samples.dir = samples # the existing database will be # destroyed and all the data will be # downloaded from peers again -database.reset = false +database.reset = true diff --git a/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java b/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java index 58e31553..906c9a19 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java @@ -4,11 +4,9 @@ import static org.junit.Assert.*; import java.math.BigInteger; -import org.abego.treelayout.internal.util.Contract; import org.ethereum.trie.MockDB; import org.ethereum.trie.Trie; import org.ethereum.util.RLP; -import org.junit.Assert; import org.junit.Test; import org.spongycastle.util.encoders.Hex; @@ -55,7 +53,7 @@ public class StateTest { @Test // right way to calc tx trie hash - public void test1(){ + public void testCalculatePostTxState(){ /* txTrieHash=a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f */ String expected = "a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f"; @@ -73,14 +71,13 @@ public class StateTest { byte[] postTxState = Hex.decode("7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527"); byte[] cumGas = Hex.decode("0272"); - TransactionRecipe tr = new TransactionRecipe(tx, postTxState, cumGas); + TransactionReceipt tr = new TransactionReceipt(tx, postTxState, cumGas); Trie trie = new Trie(new MockDB()); - trie.update(RLP.encodeByte((byte)0), tr.getEncoded()); - System.out.println(Hex.toHexString(trie.getRootHash())); - - Assert.assertEquals(expected, Hex.toHexString(trie.getRootHash())); - + trie.update(RLP.encodeInt(0), tr.getEncoded()); + String txTrieRoot = Hex.toHexString(trie.getRootHash()); + System.out.println(txTrieRoot); + assertEquals(expected, txTrieRoot); /* *** GROSS DATA *** @@ -100,7 +97,7 @@ public class StateTest { extraData=null nonce=0000000000000000000000000000000000000000000000005d439960040e4505 - TransactionRecipe[ + TransactionReceipt[ TransactionData [ hash=1ee6fa3149a5e9c09b54009eb6e108aaa7ecd79483d57eedcf2dff93a1505588 nonce=null, gasPrice=09184e72a000, gas=03e8, receiveAddress=0000000000000000000000000000000000000000, value=03e8, data=60016000546006601160003960066000f261778e600054, signatureV=27, diff --git a/ethereumj-core/src/test/java/org/ethereum/util/RLPTest.java b/ethereumj-core/src/test/java/org/ethereum/util/RLPTest.java index 6d8755fe..f901c762 100644 --- a/ethereumj-core/src/test/java/org/ethereum/util/RLPTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/util/RLPTest.java @@ -150,6 +150,42 @@ public class RLPTest { assertArrayEquals(expected5, data); } + @Test /** encode int */ + public void testEncodeInt(){ + + byte[] expected = {(byte)0x80}; + byte[] data = RLP.encodeInt(0); + assertArrayEquals(expected, data); + + byte[] expected2 = {(byte)0x78}; + data = RLP.encodeInt(120); + assertArrayEquals(expected2, data); + + byte[] expected3 = {(byte)0x81, (byte)0x7F}; + data = RLP.encodeInt(127); + assertArrayEquals(expected3, data); + + byte[] expected4 = {(byte)0x82, (byte)0x76, (byte)0x5F}; + data = RLP.encodeInt(30303); + assertArrayEquals(expected4, data); + + byte[] expected5 = {(byte)0x82, (byte)0x4E, (byte)0xEA}; + data = RLP.encodeInt(20202); + assertArrayEquals(expected5, data); + + byte[] expected6 = {(byte)0x83, 1, 0, 0}; + data = RLP.encodeInt(65536); + assertArrayEquals(expected6, data); + + byte[] expected7 = {(byte)0x80}; + data = RLP.encodeInt(Integer.MIN_VALUE); + assertArrayEquals(expected7, data); + + byte[] expected8 = {(byte)0x84, (byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF}; + data = RLP.encodeInt(Integer.MAX_VALUE); + assertArrayEquals(expected8, data); + } + @Test /** encode BigInteger */ public void test6(){ diff --git a/ethereumj-core/src/test/java/org/ethereum/vm/DataWordTest.java b/ethereumj-core/src/test/java/org/ethereum/vm/DataWordTest.java index 229c0860..b13b3621 100644 --- a/ethereumj-core/src/test/java/org/ethereum/vm/DataWordTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/vm/DataWordTest.java @@ -9,7 +9,7 @@ public class DataWordTest { @Test public void testAddPerformance() { - boolean enabled = true; + boolean enabled = false; if(enabled) { byte[] one = new byte[] { 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, @@ -68,4 +68,24 @@ public class DataWordTest { // y.add2(new DataWord(three)); // System.out.println(Hex.toHexString(y.data)); } + + @Test + public void testMod() { + String expected = "000000000000000000000000000000000000000000000000000000000000001a"; + + byte[] one = new byte[32]; + one[31] = 0x1e; // 0x000000000000000000000000000000000000000000000000000000000000001e + + byte[] two = new byte[32]; + for (int i = 0; i < two.length; i++) { + two[i] = (byte) 0xff; + } + two[31] = 0x56; // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56 + + DataWord x = new DataWord(one);// System.out.println(x.value()); + DataWord y = new DataWord(two);// System.out.println(y.value()); + y.mod(x); + assertEquals(32, y.data.length); + assertEquals(expected, Hex.toHexString(y.data)); + } }