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 c44c2e75..2e04a787 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Block.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Block.java @@ -43,7 +43,8 @@ public class Block { * 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 in the transactions list portion + * 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. @@ -72,6 +73,8 @@ public class Block { private byte[] nonce; private List transactionsList = new ArrayList(); + private List txRecipeList = new ArrayList(); + private List uncleList = new ArrayList(); private Trie state; @@ -146,9 +149,13 @@ public class Block { Transaction tx = new Transaction(txData.getRLPData()); this.transactionsList.add(tx); - // YP 4.3.1 should do something with that later - RLPElement txRecipe1 = ((RLPList)rlpTx).get(1); - RLPElement txRecipe2 = ((RLPList)rlpTx).get(2); + // YP 4.3.1 + RLPElement cummGas = ((RLPList)rlpTx).get(1); + RLPElement pstTxState = ((RLPList)rlpTx).get(2); + + TransactionRecipe txRecipe = + new TransactionRecipe(tx, cummGas.getRLPData(), pstTxState.getRLPData()); + txRecipeList.add(txRecipe); } // Parse Uncles @@ -244,6 +251,14 @@ public class Block { return transactionsList; } + public List getTxRecipeList() { + if (!parsed) parseRLP(); + if (transactionsList == null) { + this.txRecipeList = new ArrayList(); + } + return txRecipeList; + } + public List getUncleList() { if (!parsed) parseRLP(); if (uncleList == null) { @@ -278,10 +293,10 @@ public class Block { toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("\n"); toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("\n"); - for (Transaction tx : getTransactionsList()){ + for (TransactionRecipe txRecipe : getTxRecipeList()){ toStringBuff.append("\n"); - toStringBuff.append( tx.toString() ); + toStringBuff.append(txRecipe.toString()); } toStringBuff.append("\n]"); 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 db482d26..2395efc1 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/TransactionRecipe.java new file mode 100644 index 00000000..f9e64131 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionRecipe.java @@ -0,0 +1,51 @@ +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 + */ + +public class TransactionRecipe { + + private Transaction transaction; + private byte[] postTxState; + private byte[] cumulativeGas; + + /* Tx Recipe in encoded form */ + private byte[] rlpEncoded; + + + public TransactionRecipe(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) { + this.transaction = transaction; + this.postTxState = postTxState; + this.cumulativeGas = cumulativeGas; + } + + public byte[] getEncoded(){ + + if(rlpEncoded != null) return rlpEncoded; + + byte[] transactionEl = transaction.getEncoded(); + byte[] postTxStateEl = RLP.encodeElement(this.postTxState); + byte[] cumulativeGasEl = RLP.encodeElement(this.cumulativeGas); + + rlpEncoded = RLP.encodeList(transactionEl, postTxStateEl, cumulativeGasEl); + + return rlpEncoded; + } + + @Override + public String toString() { + return "TransactionRecipe[" + + "\n " + transaction + + "\n , postTxState=" + Hex.toHexString(postTxState) + + "\n , cumulativeGas=" + Hex.toHexString(cumulativeGas) + + ']'; + } +} 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 c1cd94f8..58e31553 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/StateTest.java @@ -4,8 +4,11 @@ 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; @@ -50,4 +53,73 @@ public class StateTest { assertEquals("23b503734ff34ddb7bd5e478f1645680ec778ab3f90007cb1c854653693e5adc", Hex.toHexString(trie.getRootHash())); } + + @Test // right way to calc tx trie hash + public void test1(){ + + /* txTrieHash=a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f */ + String expected = "a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f"; + Transaction tx = new Transaction( + new byte[]{}, + Hex.decode("09184E72A000"), + Hex.decode("03E8"), + Hex.decode("0000000000000000000000000000000000000000"), + Hex.decode("03e8"), + Hex.decode("60016000546006601160003960066000f261778e600054") + ); + byte[] cowPrivKey = Hex.decode("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"); + tx.sign(cowPrivKey); + + byte[] postTxState = Hex.decode("7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527"); + byte[] cumGas = Hex.decode("0272"); + + TransactionRecipe tr = new TransactionRecipe(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())); + + + /* *** GROSS DATA *** + + BlockData [ + hash=22cf863ab836a6f5c29389d2e77f4792a3b3b52908c98ed14b1cbe91491a3e36 + parentHash=77ef4fdaf389dca53236bcf7f72698e154eab2828f86fbc4fc6cd9225d285c89 + unclesHash=1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 + coinbase=4c5f4d519dff3c16f0d54b6866e256fbbbc1a600 + stateHash=69c21ff84a5af0b53b11c61110a16d6ad43dad37b3eb29ae8e88c936eb06456a + txTrieHash=a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f + difficulty=3ff000 + number=1 + minGasPrice=10000000000000 + gasLimit=999023 + gasUsed=626 + timestamp=1401979976 (2014.06.05 15:52:56) + extraData=null + nonce=0000000000000000000000000000000000000000000000005d439960040e4505 + + TransactionRecipe[ + TransactionData [ hash=1ee6fa3149a5e9c09b54009eb6e108aaa7ecd79483d57eedcf2dff93a1505588 nonce=null, + gasPrice=09184e72a000, gas=03e8, receiveAddress=0000000000000000000000000000000000000000, value=03e8, + data=60016000546006601160003960066000f261778e600054, signatureV=27, + signatureR=2b379f22050e3554c3fa5423d9040bb28dcc7f905300db4e67c03bcf9b27003c, + signatureS=59f47793e050974e6b5fca2848b19925637b883a012693b54d712f1c4f74def5 + ] + , postTxState=7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527 + , cumulativeGas=0272] + ] + + +++ 4c5f4d519dff3c16f0d54b6866e256fbbbc1a600: + +++ 77045e71a7a2c50903d88e564cd72fab11e82051: $[61,77,8e,60,0,54] ([]) + * cd2a3d9f938e13cd947ec05abc7fe734df8dd826: #1 1606938044258990275541962092341162602522202987522792835300376 (-6260000000001000) + */ + } + + + + + } +