Add genesis block and block encoding
This commit is contained in:
parent
41862c44a1
commit
02bce31d63
|
@ -1,6 +1,7 @@
|
|||
package org.ethereum.core;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.util.RLP;
|
||||
import org.ethereum.util.RLPElement;
|
||||
import org.ethereum.util.RLPItem;
|
||||
import org.ethereum.util.RLPList;
|
||||
|
@ -25,7 +26,6 @@ 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;
|
||||
|
@ -77,14 +77,10 @@ public class Block {
|
|||
this.parsed = false;
|
||||
}
|
||||
|
||||
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,
|
||||
long number, long minGasPrice, long gasLimit, long gasUsed,
|
||||
long timestamp, byte[] extraData, byte[] nonce,
|
||||
List<Transaction> transactionsList, List<Block> uncleList) {
|
||||
this.parentHash = parentHash;
|
||||
this.unclesHash = unclesHash;
|
||||
|
@ -92,11 +88,11 @@ public class Block {
|
|||
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.timestamp = timestamp;
|
||||
this.extraData = extraData;
|
||||
this.nonce = nonce;
|
||||
this.transactionsList = transactionsList;
|
||||
|
@ -105,7 +101,7 @@ public class Block {
|
|||
}
|
||||
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
|
||||
// difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed,
|
||||
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
|
||||
// extradata, nonce]
|
||||
private void parseRLP() {
|
||||
|
||||
|
@ -113,37 +109,38 @@ public class Block {
|
|||
|
||||
this.hash = HashUtil.sha3(params.getRLPData());
|
||||
|
||||
RLPList header = (RLPList) params.get(0);
|
||||
|
||||
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();
|
||||
this.parentHash = ((RLPItem) header.get(0)).getData();
|
||||
this.unclesHash = ((RLPItem) header.get(1)).getData();
|
||||
this.coinbase = ((RLPItem) header.get(2)).getData();
|
||||
this.stateRoot = ((RLPItem) header.get(3)).getData();
|
||||
this.txTrieRoot = ((RLPItem) header.get(4)).getData();
|
||||
this.difficulty = ((RLPItem) header.get(5)).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();
|
||||
byte[] tsBytes = ((RLPItem) header.get(6)).getData();
|
||||
byte[] nrBytes = ((RLPItem) header.get(7)).getData();
|
||||
byte[] gpBytes = ((RLPItem) header.get(8)).getData();
|
||||
byte[] glBytes = ((RLPItem) header.get(9)).getData();
|
||||
byte[] guBytes = ((RLPItem) header.get(10)).getData();
|
||||
|
||||
this.timestamp = (new BigInteger(tsBytes)).longValue();
|
||||
this.number = (new BigInteger(nrBytes)).longValue();
|
||||
this.timestamp = tsBytes == null ? 0 : (new BigInteger(tsBytes)).longValue();
|
||||
this.number = nrBytes == null ? 0 : (new BigInteger(nrBytes)).longValue();
|
||||
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(gpBytes)).longValue();
|
||||
this.gasLimit = glBytes == null ? 0 : (new BigInteger(glBytes)).longValue();
|
||||
this.gasUsed = guBytes == null ? 0 : (new BigInteger(guBytes)).longValue();
|
||||
|
||||
this.extraData = ((RLPItem) params.get(11)).getData();
|
||||
this.nonce = ((RLPItem) params.get(12)).getData();
|
||||
this.extraData = ((RLPItem) header.get(11)).getData();
|
||||
this.nonce = ((RLPItem) header.get(12)).getData();
|
||||
|
||||
// parse transactions
|
||||
RLPList transactions = (RLPList) rawData.get(1);
|
||||
RLPList transactions = (RLPList) params.get(1);
|
||||
for (RLPElement rlpTx : transactions){
|
||||
Transaction tx = new Transaction((RLPList)rlpTx);
|
||||
this.transactionsList.add(tx);
|
||||
}
|
||||
// parse uncles
|
||||
RLPList uncleBlocks = (RLPList) rawData.get(2);
|
||||
RLPList uncleBlocks = (RLPList) params.get(2);
|
||||
for (RLPElement rawUncle : uncleBlocks){
|
||||
Block blockData = new Block((RLPList)rawUncle);
|
||||
this.uncleList.add(blockData);
|
||||
|
@ -153,7 +150,7 @@ public class Block {
|
|||
|
||||
public byte[] getHash(){
|
||||
if (!parsed) parseRLP();
|
||||
return hash;
|
||||
return HashUtil.sha3(this.getEncoded());
|
||||
}
|
||||
|
||||
public Block getParent() {
|
||||
|
@ -224,16 +221,22 @@ public class Block {
|
|||
|
||||
public List<Transaction> getTransactionsList() {
|
||||
if (!parsed) parseRLP();
|
||||
if (transactionsList == null) {
|
||||
this.transactionsList = new ArrayList<Transaction>();
|
||||
}
|
||||
return transactionsList;
|
||||
}
|
||||
|
||||
public List<Block> getUncleList() {
|
||||
if (!parsed) parseRLP();
|
||||
if (uncleList == null) {
|
||||
this.uncleList = new ArrayList<Block>();
|
||||
}
|
||||
return uncleList;
|
||||
}
|
||||
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
|
||||
// difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed,
|
||||
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
|
||||
// extradata, nonce]
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -247,11 +250,11 @@ public class Block {
|
|||
", stateHash=" + Utils.toHexString(stateRoot) +
|
||||
", txTrieHash=" + Utils.toHexString(txTrieRoot) +
|
||||
", difficulty=" + Utils.toHexString(difficulty) +
|
||||
", timestamp=" + timestamp +
|
||||
", number=" + number +
|
||||
", minGasPrice=" + minGasPrice +
|
||||
", gasLimit=" + gasLimit +
|
||||
", gasUsed=" + gasUsed +
|
||||
", timestamp=" + timestamp +
|
||||
", extraData=" + Utils.toHexString(extraData) +
|
||||
", nonce=" + Utils.toHexString(nonce) +
|
||||
']';
|
||||
|
@ -284,11 +287,35 @@ public class Block {
|
|||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
if (this.encodedBlock == null) parseRLP();
|
||||
return this.encodedBlock;
|
||||
}
|
||||
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);
|
||||
|
||||
public byte[] hash() {
|
||||
return HashUtil.sha3(this.getEncoded());
|
||||
byte[] header = RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||
stateRoot, txTrieRoot, difficulty, number,
|
||||
minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce);
|
||||
|
||||
byte[] transactions = RLP.encodeList();
|
||||
byte[] uncles = RLP.encodeList();
|
||||
|
||||
return RLP.encodeList(header, transactions, uncles);
|
||||
|
||||
// TODO: Alternative clean way to encode, using RLP.encode() after it's optimized
|
||||
// Object[] header = new Object[] { parentHash, unclesHash, coinbase,
|
||||
// stateRoot, txTrieRoot, difficulty, number, minGasPrice,
|
||||
// gasLimit, gasUsed, timestamp, extraData, nonce };
|
||||
// Object[] transactions = this.getTransactionsList().toArray();
|
||||
// Object[] uncles = this.getUncleList().toArray();
|
||||
// return RLP.encode(new Object[] { header, transactions, uncles });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.ethereum.core;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.util.RLP;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
public class Genesis extends Block {
|
||||
|
||||
private static byte[] zeroHash256 = new byte[32];
|
||||
private static byte[] zeroHash160 = new byte[20];
|
||||
private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList());
|
||||
|
||||
private static byte[] parentHash = zeroHash256;
|
||||
private static byte[] unclesHash = sha3EmptyList;
|
||||
private static byte[] coinbase = zeroHash160;
|
||||
private static byte[] stateRoot = // TODO: Get stateRoot from actual state
|
||||
Hex.decode("2f4399b08efe68945c1cf90ffe85bbe3ce978959da753f9e649f034015b8817d");
|
||||
private static byte[] txTrieRoot = zeroHash256;
|
||||
private static byte[] difficulty = BigInteger.valueOf((long) Math.pow(2, 22)).toByteArray();
|
||||
private static long number = 0;
|
||||
private static long minGasPrice = 0;
|
||||
private static long gasLimit = 1000000;
|
||||
private static long gasUsed = 0;
|
||||
private static long timestamp = 0;
|
||||
private static byte[] extraData = new byte[0];
|
||||
private static byte[] nonce = HashUtil.sha3(new byte[]{42});
|
||||
|
||||
public Genesis() {
|
||||
super(parentHash, unclesHash, coinbase, stateRoot,
|
||||
txTrieRoot, difficulty, number, minGasPrice, gasLimit, gasUsed,
|
||||
timestamp, extraData, nonce, null, null);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@ package org.ethereum.block;
|
|||
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
import org.ethereum.core.Block;
|
||||
import org.ethereum.core.Genesis;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.ethereum.util.RLP;
|
||||
import org.ethereum.util.RLPList;
|
||||
import org.junit.Test;
|
||||
|
@ -11,6 +13,7 @@ import static org.junit.Assert.*;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BlockTest {
|
||||
|
||||
|
@ -120,17 +123,12 @@ public class BlockTest {
|
|||
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()));
|
||||
Block genesis = new Block(RLP.decode2(genesisBytes));
|
||||
assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(genesis.getHash()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenesisFromNew() {
|
||||
|
||||
System.out.println(CPP_PoC5_GENESIS_HEX_RLP_ENCODED);
|
||||
Object genesisItems = RLP.decode(Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED), 0).getDecoded();
|
||||
// TODO: verify genesis items with expected values
|
||||
|
||||
/* From: https://ethereum.etherpad.mozilla.org/11
|
||||
Genesis block is:
|
||||
(
|
||||
|
@ -149,30 +147,9 @@ public class BlockTest {
|
|||
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;
|
||||
Block genesis = new Genesis();
|
||||
assertEquals(CPP_PoC5_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(genesis.getEncoded()));
|
||||
assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(genesis.getHash()));
|
||||
}
|
||||
|
||||
@Test /* create BlockData from part of real RLP BLOCKS message */
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue