From 99004b211de3a5bea915276acc0bb944561a1029 Mon Sep 17 00:00:00 2001 From: nicksavers Date: Tue, 13 May 2014 17:05:37 +0200 Subject: [PATCH] Add partial tests for genesis block --- .../org/ethereum/gui/ConnectionConsole.java | 5 +- .../main/java/org/ethereum/net/vo/Block.java | 143 +++++++++++++----- .../java/org/ethereum/block/BlockTest.java | 75 +++++++-- .../java/org/ethereum/net/MessagesTest.java | 8 +- 4 files changed, 179 insertions(+), 52 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ConnectionConsole.java b/ethereumj-core/src/main/java/org/ethereum/gui/ConnectionConsole.java index 9e43df80..8c13ae5f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ConnectionConsole.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ConnectionConsole.java @@ -61,10 +61,9 @@ public class ConnectionConsole extends JFrame implements PeerListener{ public void componentShown(ComponentEvent e) { Thread t = new Thread() { public void run() { -// new ClientPeer(thisConsole).connect("54.201.28.117", 30303); -// new ClientPeer(thisConsole).connect("82.217.72.169", 30303); - new ClientPeer(thisConsole).connect("54.204.10.41", 30303); + new ClientPeer(thisConsole).connect("54.201.28.117", 30303); // new ClientPeer(thisConsole).connect("82.217.72.169", 30303); +// new ClientPeer(thisConsole).connect("54.204.10.41", 30303); } }; t.start(); 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 98051165..4f33269c 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 @@ -25,6 +25,7 @@ public class Block { private static int GAS_LIMIT = (int) Math.pow(10, 6); private RLPList rawData; + private byte[] encodedBlock; private boolean parsed = false; private byte[] hash; @@ -38,18 +39,34 @@ public class Block { 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[] stateRoot; /* 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; + 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; - - private long timestamp; + /* 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(); @@ -59,15 +76,27 @@ public class Block { this.rawData = rawData; this.parsed = false; } - - public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] stateHash, byte[] txTrieHash, byte[] difficulty, long timestamp, byte[] extraData, byte[] nonce, List transactionsList, List uncleList) { + + public Block(byte[] encodedBlock) { + this.encodedBlock = encodedBlock; + } + + public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, + byte[] stateRoot, byte[] txTrieRoot, byte[] difficulty, + long timestamp, long number, long minGasPrice, long gasLimit, + long gasUsed, byte[] extraData, byte[] nonce, + List transactionsList, List uncleList) { this.parentHash = parentHash; this.unclesHash = unclesHash; this.coinbase = coinbase; - this.stateHash = stateHash; - this.txTrieHash = txTrieHash; + this.stateRoot = stateRoot; + this.txTrieRoot = txTrieRoot; this.difficulty = difficulty; this.timestamp = timestamp; + this.number = number; + this.minGasPrice = minGasPrice; + this.gasLimit = gasLimit; + this.gasUsed = gasUsed; this.extraData = extraData; this.nonce = nonce; this.transactionsList = transactionsList; @@ -75,24 +104,36 @@ public class Block { this.parsed = true; } - // [parent_hash, uncles_hash, coinbase, state_root, tx_list_hash, difficulty, timestamp, extradata, nonce] + // [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root, + // difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed, + // extradata, nonce] private void parseRLP() { this.hash = HashUtil.sha3(rawData.getRLPData()); List params = ((RLPList) rawData.getElement(0)).getList(); - this.parentHash = ((RLPItem) params.get(0)).getData(); - this.unclesHash = ((RLPItem) params.get(1)).getData(); - this.coinbase = ((RLPItem) params.get(2)).getData(); - this.stateHash = ((RLPItem) params.get(3)).getData(); - this.txTrieHash = ((RLPItem) params.get(4)).getData(); - this.difficulty = ((RLPItem) params.get(5)).getData(); + this.parentHash = ((RLPItem) params.get(0)).getData(); + this.unclesHash = ((RLPItem) params.get(1)).getData(); + this.coinbase = ((RLPItem) params.get(2)).getData(); + this.stateRoot = ((RLPItem) params.get(3)).getData(); + this.txTrieRoot = ((RLPItem) params.get(4)).getData(); + this.difficulty = ((RLPItem) params.get(5)).getData(); - byte[] tsBytes = ((RLPItem) params.get(6)).getData(); - this.timestamp = (new BigInteger(tsBytes)).longValue(); - this.extraData = ((RLPItem) params.get(7)).getData(); - this.nonce = ((RLPItem) params.get(8)).getData(); + byte[] tsBytes = ((RLPItem) params.get(6)).getData(); + byte[] nrBytes = ((RLPItem) params.get(7)).getData(); + byte[] gpBytes = ((RLPItem) params.get(8)).getData(); + byte[] glBytes = ((RLPItem) params.get(9)).getData(); + byte[] guBytes = ((RLPItem) params.get(10)).getData(); + + this.timestamp = (new BigInteger(tsBytes)).longValue(); + this.number = (new BigInteger(nrBytes)).longValue(); + this.minGasPrice = (new BigInteger(gpBytes)).longValue(); + this.gasLimit = (new BigInteger(glBytes)).longValue(); + this.gasUsed = (new BigInteger(guBytes)).longValue(); + + this.extraData = ((RLPItem) params.get(11)).getData(); + this.nonce = ((RLPItem) params.get(12)).getData(); // parse transactions List transactions = ((RLPList) rawData.getElement(1)).getList(); @@ -134,14 +175,14 @@ public class Block { return coinbase; } - public byte[] getStateHash() { + public byte[] getStateRoot() { if (!parsed) parseRLP(); - return stateHash; + return stateRoot; } - public byte[] getTxTrieHash() { + public byte[] getTxTrieRoot() { if (!parsed) parseRLP(); - return txTrieHash; + return txTrieRoot; } public byte[] getDifficulty() { @@ -153,8 +194,24 @@ public class Block { if (!parsed) parseRLP(); return timestamp; } + + public long getNumber() { + return number; + } - public byte[] getExtraData() { + public long getMinGasPrice() { + return minGasPrice; + } + + public long getGasLimit() { + return gasLimit; + } + + public long getGasUsed() { + return gasUsed; + } + + public byte[] getExtraData() { if (!parsed) parseRLP(); return extraData; } @@ -174,21 +231,28 @@ public class Block { return uncleList; } - // [parent_hash, uncles_hash, coinbase, state_root, tx_list_hash, difficulty, timestamp, extradata, nonce] + // [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root, + // difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed, + // extradata, nonce] @Override public String toString() { if (!parsed) parseRLP(); - return "BlockData [" + " hash=" + Utils.toHexString(hash) + - " parentHash=" + Utils.toHexString(parentHash) + - ", unclesHash=" + Utils.toHexString(unclesHash) + - ", coinbase=" + Utils.toHexString(coinbase) + - ", stateHash=" + Utils.toHexString(stateHash) + - ", txTrieHash=" + Utils.toHexString(txTrieHash) + - ", difficulty=" + Utils.toHexString(difficulty) + - ", timestamp=" + timestamp + - ", extraData=" + Utils.toHexString(extraData) + - ", nonce=" + Utils.toHexString(nonce) + + return "BlockData [" + + " hash=" + Utils.toHexString(hash) + + " parentHash=" + Utils.toHexString(parentHash) + + ", unclesHash=" + Utils.toHexString(unclesHash) + + ", coinbase=" + Utils.toHexString(coinbase) + + ", stateHash=" + Utils.toHexString(stateRoot) + + ", txTrieHash=" + Utils.toHexString(txTrieRoot) + + ", difficulty=" + Utils.toHexString(difficulty) + + ", timestamp=" + timestamp + + ", number=" + number + + ", minGasPrice=" + minGasPrice + + ", gasLimit=" + gasLimit + + ", gasUsed=" + gasUsed + + ", extraData=" + Utils.toHexString(extraData) + + ", nonce=" + Utils.toHexString(nonce) + ']'; } @@ -217,4 +281,13 @@ public class Block { return Math.floor((this.getParent().getOplimit() * (EMA_FACTOR - 1) + Math.floor(GAS_LIMIT * LIMIT_FACTOR)) / EMA_FACTOR); } + + public byte[] getEncoded() { + if (this.encodedBlock == null) parseRLP(); + return this.encodedBlock; + } + + public byte[] hash() { + return HashUtil.sha3(this.getEncoded()); + } } diff --git a/ethereumj-core/src/test/java/org/ethereum/block/BlockTest.java b/ethereumj-core/src/test/java/org/ethereum/block/BlockTest.java index e08c5fb6..c5f9f603 100644 --- a/ethereumj-core/src/test/java/org/ethereum/block/BlockTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/block/BlockTest.java @@ -5,12 +5,20 @@ import org.ethereum.crypto.HashUtil; import org.ethereum.net.rlp.RLP; import org.ethereum.net.rlp.RLPList; import org.ethereum.net.vo.Block; +import org.ethereum.util.RlpEncoder; import org.junit.Test; +import static org.junit.Assert.*; + import java.io.IOException; import java.math.BigInteger; public class BlockTest { + + // https://ethereum.etherpad.mozilla.org/12 + private String CPP_PoC5_GENESIS_STATE_ROOT_HEX_HASH = "2f4399b08efe68945c1cf90ffe85bbe3ce978959da753f9e649f034015b8817d"; + private String CPP_PoC5_GENESIS_HEX_RLP_ENCODED = "f8cbf8c7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a02f4399b08efe68945c1cf90ffe85bbe3ce978959da753f9e649f034015b8817da00000000000000000000000000000000000000000000000000000000000000000834000008080830f4240808080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0"; + private String CPP_PoC5_GENESIS_HEX_HASH = "69a7356a245f9dc5b865475ada5ee4e89b18f93c06503a9db3b3630e88e9fb4e"; @Test /* Creating genesis hash not ready yet */ public void test1() throws IOException { @@ -50,8 +58,6 @@ public class BlockTest { block.appendRaw(RLPEmptyList); */ - // gennesis hash - //ab6b9a5613970faa771b12d449b2e9bb925ab7a369f0a4b86b286e9d540099cf /* 1 */ byte[] prevHash = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -108,23 +114,72 @@ public class BlockTest { System.out.println(Hex.toHexString(genesis)); byte[] hash = HashUtil.sha3(genesis); - - System.out.println(Hex.toHexString(hash)); - - System.out.println("ab6b9a5613970faa771b12d449b2e9bb925ab7a369f0a4b86b286e9d540099cf"); + assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(hash)); } @Test /* got from go guy */ - public void test2(){ + public void testGenesisFromRLP(){ + // from RLP encoding + byte[] genesisBytes = Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED); + Block genesis = new Block(genesisBytes); + assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(genesis.hash())); + } + + @Test + public void testGenesisFromNew() { + + System.out.println(CPP_PoC5_GENESIS_HEX_RLP_ENCODED); + Object genesisItems = RlpEncoder.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED.getBytes(), 0).getDecoded(); + // TODO: verify genesis items with expected values - byte[] goGenesisBytes = Hex.decode("f8a4f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794000000000000000000000000000000000000000080a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347834000008080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0"); - System.out.println( Hex.toHexString( HashUtil.sha3(goGenesisBytes) ) ); + /* From: https://ethereum.etherpad.mozilla.org/11 + Genesis block is: + ( + B32(0, 0, ...), + B32(sha3(B())), + B20(0, 0, ...), + B32(stateRoot), + B32(0, 0, ...), + P(2^22), + P(0), + P(0), + P(1000000), + P(0), + P(0) + B() + B32(sha3(B(42))) + ) + */ + + byte[] parentHash = new byte[32]; System.out.println(Hex.toHexString(parentHash)); + byte[] unclesHash = HashUtil.sha3(new byte[0]); System.out.println(Hex.toHexString(unclesHash)); + byte[] coinbase = new byte[20]; System.out.println(Hex.toHexString(coinbase)); + byte[] stateRoot = Hex.decode(CPP_PoC5_GENESIS_STATE_ROOT_HEX_HASH); System.out.println(Hex.toHexString(stateRoot)); + byte[] txTrieRoot = new byte[32]; System.out.println(Hex.toHexString(txTrieRoot)); + byte[] difficulty = doubleToByteArray(Math.pow(2, 22)); System.out.println(Hex.toHexString(difficulty)); + long timestamp = 0; System.out.println(Long.toHexString(timestamp)); + long number = 0; System.out.println(Long.toHexString(number)); + long minGasPrice = 0; System.out.println(Long.toHexString(minGasPrice)); + long gasLimit = 1000000; System.out.println(Long.toHexString(gasLimit)); + long gasUsed = 0; System.out.println(Long.toHexString(gasUsed)); + byte[] extraData = new byte[0]; System.out.println(Hex.toHexString(extraData)); + byte[] nonce = HashUtil.sha3(new byte[]{42}); System.out.println(Hex.toHexString(nonce)); + Block block = new Block(parentHash, unclesHash, coinbase, stateRoot, txTrieRoot, difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce, null, null); + assertEquals(CPP_PoC5_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(block.getEncoded())); + assertEquals(CPP_PoC5_GENESIS_HEX_HASH, block.hash()); + } + + private byte[] doubleToByteArray(double d) { + byte[] output = new byte[8]; + long lng = Double.doubleToLongBits(d); + for(int i = 0; i < 8; i++) output[i] = (byte)((lng >> ((7 - i) * 8)) & 0xff); + return output; } @Test /* create BlockData from part of real RLP BLOCKS message */ public void test3(){ - String blocksMsg= "F8C8F8C4A07B2536237CBF114A043B0F9B27C76F84AC160EA5B87B53E42C7E76148964D450A01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347943854AAF203BA5F8D49B1EC221329C7AEBCF050D3A07A3BE0EE10ECE4B03097BF74AABAC628AA0FAE617377D30AB1B97376EE31F41AA01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347833FBFE884533F1CE880A0000000000000000000000000000000000000000000000000F3DEEA84969B6E95C0C0"; + String blocksMsg = "F8C8F8C4A07B2536237CBF114A043B0F9B27C76F84AC160EA5B87B53E42C7E76148964D450A01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347943854AAF203BA5F8D49B1EC221329C7AEBCF050D3A07A3BE0EE10ECE4B03097BF74AABAC628AA0FAE617377D30AB1B97376EE31F41AA01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347833FBFE884533F1CE880A0000000000000000000000000000000000000000000000000F3DEEA84969B6E95C0C0"; byte[] payload = Hex.decode(blocksMsg); 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 395ca3e1..c13a5eda 100644 --- a/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java @@ -351,10 +351,10 @@ public class MessagesTest { Utils.toHexString(block.getCoinbase()).toUpperCase()); assertEquals("5E2D2CC0B42B38B5B18C9D65734F9877C035DD390B9C12C48624F2243668A268", - Utils.toHexString(block.getStateHash()).toUpperCase()); + Utils.toHexString(block.getStateRoot()).toUpperCase()); assertEquals("1DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347", - Utils.toHexString(block.getTxTrieHash()).toUpperCase()); + Utils.toHexString(block.getTxTrieRoot()).toUpperCase()); assertEquals("02471A26", Utils.toHexString(block.getDifficulty()).toUpperCase()); assertEquals(1398260220, block.getTimestamp()); @@ -395,10 +395,10 @@ public class MessagesTest { Utils.toHexString(block.getCoinbase()).toUpperCase()); assertEquals("990DC3B5ACBEE04124361D958FE51ACB582593613FC290683940A0769549D3ED", - Utils.toHexString(block.getStateHash()).toUpperCase()); + Utils.toHexString(block.getStateRoot()).toUpperCase()); assertEquals("9BFE4817D274EA3EB8672E9FE848C3885B53BBBD1D7C26E6039F90FB96B942B0", - Utils.toHexString(block.getTxTrieHash()).toUpperCase()); + Utils.toHexString(block.getTxTrieRoot()).toUpperCase()); assertEquals("3FF000", Utils.toHexString(block.getDifficulty()).toUpperCase()); assertEquals(1396643511, block.getTimestamp());