Add partial tests for genesis block

This commit is contained in:
nicksavers 2014-05-13 17:05:37 +02:00
parent 808105dce2
commit 99004b211d
4 changed files with 179 additions and 52 deletions

View File

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

View File

@ -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 blocks 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<Transaction> transactionsList = new ArrayList<Transaction>();
@ -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<Transaction> transactionsList, List<Block> 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<Transaction> transactionsList, List<Block> 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<RLPElement> 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());
}
}

View File

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

View File

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