Decouple Genesis from repository and validate txStateRoot
This commit is contained in:
parent
a4b2570c13
commit
b43209457a
|
@ -59,7 +59,7 @@ public class Block {
|
||||||
/* Constructors */
|
/* Constructors */
|
||||||
|
|
||||||
public Block(byte[] rawData) {
|
public Block(byte[] rawData) {
|
||||||
logger.debug("RLP encoded [ " + Hex.toHexString(rawData) + " ]");
|
logger.debug("new Block from RLP encoded [ " + Hex.toHexString(rawData) + " ]");
|
||||||
this.rlpEncoded = rawData;
|
this.rlpEncoded = rawData;
|
||||||
this.parsed = false;
|
this.parsed = false;
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,7 @@ public class Block {
|
||||||
this.header = new BlockHeader(parentHash, unclesHash, coinbase,
|
this.header = new BlockHeader(parentHash, unclesHash, coinbase,
|
||||||
difficulty, number, minGasPrice, gasLimit, gasUsed,
|
difficulty, number, minGasPrice, gasLimit, gasUsed,
|
||||||
timestamp, extraData, nonce);
|
timestamp, extraData, nonce);
|
||||||
this.txsState = new Trie(null);
|
this.transactionsList = transactionsList;
|
||||||
|
|
||||||
this.header.setTxTrieRoot(txsState.getRootHash());
|
|
||||||
this.transactionsList = transactionsList;
|
|
||||||
this.uncleList = uncleList;
|
this.uncleList = uncleList;
|
||||||
this.parsed = true;
|
this.parsed = true;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +87,7 @@ public class Block {
|
||||||
|
|
||||||
// Parse Transactions
|
// Parse Transactions
|
||||||
RLPList txReceipts = (RLPList) block.get(1);
|
RLPList txReceipts = (RLPList) block.get(1);
|
||||||
this.parseTxs(txReceipts);
|
this.parseTxs(this.header.getTxTrieRoot(), txReceipts);
|
||||||
|
|
||||||
// Parse Uncles
|
// Parse Uncles
|
||||||
RLPList uncleBlocks = (RLPList) block.get(2);
|
RLPList uncleBlocks = (RLPList) block.get(2);
|
||||||
|
@ -188,32 +185,25 @@ public class Block {
|
||||||
this.header.setNonce(nonce);
|
this.header.setNonce(nonce);
|
||||||
rlpEncoded = null;
|
rlpEncoded = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Trie getTxsState() {
|
|
||||||
return this.txsState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Transaction> getTransactionsList() {
|
public List<Transaction> getTransactionsList() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
if (transactionsList == null) {
|
if (transactionsList == null)
|
||||||
this.transactionsList = new ArrayList<>();
|
transactionsList = new ArrayList<>();
|
||||||
}
|
|
||||||
return transactionsList;
|
return transactionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TransactionReceipt> getTxReceiptList() {
|
public List<TransactionReceipt> getTxReceiptList() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
if (transactionsList == null) {
|
if (txReceiptList == null)
|
||||||
this.txReceiptList = new ArrayList<>();
|
txReceiptList = new ArrayList<>();
|
||||||
}
|
|
||||||
return txReceiptList;
|
return txReceiptList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Block> getUncleList() {
|
public List<Block> getUncleList() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
if (uncleList == null) {
|
if (uncleList == null)
|
||||||
this.uncleList = new ArrayList<>();
|
uncleList = new ArrayList<>();
|
||||||
}
|
|
||||||
return uncleList;
|
return uncleList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,30 +248,31 @@ public class Block {
|
||||||
return toStringBuff.toString();
|
return toStringBuff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseTxs(RLPList txReceipts) {
|
private void parseTxs(byte[] expectedRoot, RLPList txReceipts) {
|
||||||
|
|
||||||
this.txsState = new Trie(null);
|
this.txsState = new Trie(null);
|
||||||
for (int i = 0; i < txReceipts.size(); i++) {
|
for (int i = 0; i < txReceipts.size(); i++) {
|
||||||
RLPElement rlpTxReceipt = txReceipts.get(i);
|
RLPElement rlpTxReceipt = txReceipts.get(i);
|
||||||
RLPElement txData = ((RLPList)rlpTxReceipt).get(0);
|
RLPElement txData = ((RLPList)rlpTxReceipt).get(0);
|
||||||
|
|
||||||
Transaction tx = new Transaction(txData.getRLPData());
|
|
||||||
this.addAndProcessTransaction(i, tx);
|
|
||||||
|
|
||||||
// YP 4.3.1
|
// YP 4.3.1
|
||||||
RLPElement cummGas = ((RLPList)rlpTxReceipt).get(1);
|
RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(1);
|
||||||
RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(2);
|
RLPElement cummGas = ((RLPList)rlpTxReceipt).get(2);
|
||||||
|
|
||||||
|
Transaction tx = new Transaction(txData.getRLPData());
|
||||||
|
this.transactionsList.add(tx);
|
||||||
TransactionReceipt txReceipt =
|
TransactionReceipt txReceipt =
|
||||||
new TransactionReceipt(tx, cummGas.getRLPData(), pstTxState.getRLPData());
|
new TransactionReceipt(tx, pstTxState.getRLPData(), cummGas.getRLPData());
|
||||||
txReceiptList.add(txReceipt);
|
this.addTxReceipt(i, txReceipt);
|
||||||
}
|
}
|
||||||
this.header.setTxTrieRoot(txsState.getRootHash());
|
String calculatedRoot = Hex.toHexString(txsState.getRootHash());
|
||||||
|
if(!calculatedRoot.equals(Hex.toHexString(expectedRoot)))
|
||||||
|
logger.error("Added tx receipts don't match the given txsStateRoot");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAndProcessTransaction(int counter, Transaction tx) {
|
private void addTxReceipt(int counter, TransactionReceipt txReceipt) {
|
||||||
this.transactionsList.add(tx);
|
this.txReceiptList.add(txReceipt);
|
||||||
this.txsState.update(RLP.encodeInt(counter), tx.getEncoded());
|
this.txsState.update(RLP.encodeInt(counter), txReceipt.getEncoded());
|
||||||
|
|
||||||
/* Figure out type of tx
|
/* Figure out type of tx
|
||||||
* 1. Contract creation
|
* 1. Contract creation
|
||||||
|
@ -294,8 +285,6 @@ public class Block {
|
||||||
* 3. Account to account -
|
* 3. Account to account -
|
||||||
* - update state object
|
* - update state object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// this.allAccountsState.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.ethereum.core;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import org.ethereum.util.ByteUtil;
|
import static org.ethereum.util.ByteUtil.*;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.ethereum.util.RLPItem;
|
import org.ethereum.util.RLPItem;
|
||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
|
@ -59,9 +59,13 @@ public class BlockHeader {
|
||||||
this.unclesHash = ((RLPItem) rlpHeader.get(1)).getRLPData();
|
this.unclesHash = ((RLPItem) rlpHeader.get(1)).getRLPData();
|
||||||
this.coinbase = ((RLPItem) rlpHeader.get(2)).getRLPData();
|
this.coinbase = ((RLPItem) rlpHeader.get(2)).getRLPData();
|
||||||
this.stateRoot = ((RLPItem) rlpHeader.get(3)).getRLPData();
|
this.stateRoot = ((RLPItem) rlpHeader.get(3)).getRLPData();
|
||||||
|
|
||||||
this.txTrieRoot = ((RLPItem) rlpHeader.get(4)).getRLPData();
|
this.txTrieRoot = ((RLPItem) rlpHeader.get(4)).getRLPData();
|
||||||
|
if(this.txTrieRoot == null)
|
||||||
|
this.txTrieRoot = EMPTY_BYTE_ARRAY;
|
||||||
|
|
||||||
this.difficulty = ((RLPItem) rlpHeader.get(5)).getRLPData();
|
this.difficulty = ((RLPItem) rlpHeader.get(5)).getRLPData();
|
||||||
|
|
||||||
byte[] nrBytes = ((RLPItem) rlpHeader.get(6)).getRLPData();
|
byte[] nrBytes = ((RLPItem) rlpHeader.get(6)).getRLPData();
|
||||||
byte[] gpBytes = ((RLPItem) rlpHeader.get(7)).getRLPData();
|
byte[] gpBytes = ((RLPItem) rlpHeader.get(7)).getRLPData();
|
||||||
byte[] glBytes = ((RLPItem) rlpHeader.get(8)).getRLPData();
|
byte[] glBytes = ((RLPItem) rlpHeader.get(8)).getRLPData();
|
||||||
|
@ -211,36 +215,36 @@ public class BlockHeader {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
||||||
toStringBuff.setLength(0);
|
toStringBuff.setLength(0);
|
||||||
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("\n");
|
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("\n");
|
||||||
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("\n");
|
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("\n");
|
||||||
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("\n");
|
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("\n");
|
||||||
toStringBuff.append(" stateRoot=" + ByteUtil.toHexString(stateRoot)).append("\n");
|
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("\n");
|
||||||
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n");
|
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("\n");
|
||||||
toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("\n");
|
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("\n");
|
||||||
toStringBuff.append(" number=" + number).append("\n");
|
toStringBuff.append(" number=" + number).append("\n");
|
||||||
toStringBuff.append(" minGasPrice=" + minGasPrice).append("\n");
|
toStringBuff.append(" minGasPrice=" + minGasPrice).append("\n");
|
||||||
toStringBuff.append(" gasLimit=" + gasLimit).append("\n");
|
toStringBuff.append(" gasLimit=" + gasLimit).append("\n");
|
||||||
toStringBuff.append(" gasUsed=" + gasUsed).append("\n");
|
toStringBuff.append(" gasUsed=" + gasUsed).append("\n");
|
||||||
toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n");
|
toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n");
|
||||||
toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("\n");
|
toStringBuff.append(" extraData=" + toHexString(extraData)).append("\n");
|
||||||
toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("\n");
|
toStringBuff.append(" nonce=" + toHexString(nonce)).append("\n");
|
||||||
return toStringBuff.toString();
|
return toStringBuff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFlatString() {
|
public String toFlatString() {
|
||||||
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("");
|
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("");
|
||||||
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("");
|
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("");
|
||||||
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("");
|
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("");
|
||||||
toStringBuff.append(" stateRoot=" + ByteUtil.toHexString(stateRoot)).append("");
|
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("");
|
||||||
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("");
|
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("");
|
||||||
toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("");
|
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("");
|
||||||
toStringBuff.append(" number=" + number).append("");
|
toStringBuff.append(" number=" + number).append("");
|
||||||
toStringBuff.append(" minGasPrice=" + minGasPrice).append("");
|
toStringBuff.append(" minGasPrice=" + minGasPrice).append("");
|
||||||
toStringBuff.append(" gasLimit=" + gasLimit).append("");
|
toStringBuff.append(" gasLimit=" + gasLimit).append("");
|
||||||
toStringBuff.append(" gasUsed=" + gasUsed).append("");
|
toStringBuff.append(" gasUsed=" + gasUsed).append("");
|
||||||
toStringBuff.append(" timestamp=" + timestamp).append("");
|
toStringBuff.append(" timestamp=" + timestamp).append("");
|
||||||
toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("");
|
toStringBuff.append(" extraData=" + toHexString(extraData)).append("");
|
||||||
toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("");
|
toStringBuff.append(" nonce=" + toHexString(nonce)).append("");
|
||||||
return toStringBuff.toString();
|
return toStringBuff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.ethereum.core;
|
package org.ethereum.core;
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.db.Repository;
|
import org.ethereum.trie.Trie;
|
||||||
import org.ethereum.manager.WorldManager;
|
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -29,7 +28,7 @@ import java.math.BigInteger;
|
||||||
*/
|
*/
|
||||||
public class Genesis extends Block {
|
public class Genesis extends Block {
|
||||||
|
|
||||||
private String[] premine = new String[] {
|
private static String[] premine = new String[] {
|
||||||
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
|
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
|
||||||
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
|
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
|
||||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be", // # (V)
|
"b9c015918bdaba24b4ff057a92a3873d6eb201be", // # (V)
|
||||||
|
@ -64,16 +63,16 @@ public class Genesis extends Block {
|
||||||
super(PARENT_HASH, UNCLES_HASH, COINBASE, DIFFICULTY,
|
super(PARENT_HASH, UNCLES_HASH, COINBASE, DIFFICULTY,
|
||||||
NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP,
|
NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP,
|
||||||
EXTRA_DATA, NONCE, null, null);
|
EXTRA_DATA, NONCE, null, null);
|
||||||
|
|
||||||
Repository repository = WorldManager.getInstance().getRepository();
|
Trie state = new Trie(null);
|
||||||
// The proof-of-concept series include a development premine, making the state root hash
|
// The proof-of-concept series include a development premine, making the state root hash
|
||||||
// some value stateRoot. The latest documentation should be consulted for the value of the state root.
|
// some value stateRoot. The latest documentation should be consulted for the value of the state root.
|
||||||
for (String address : premine) {
|
for (String address : premine) {
|
||||||
repository.createAccount(Hex.decode(address));
|
AccountState acctState = new AccountState();
|
||||||
repository.addBalance (Hex.decode(address), BigInteger.valueOf(2).pow(200) );
|
acctState.addToBalance(getPremineAmount());
|
||||||
|
state.update(Hex.decode(address), acctState.getEncoded());
|
||||||
}
|
}
|
||||||
setStateRoot(repository.getWorldState().getRootHash());
|
setStateRoot(state.getRootHash());
|
||||||
repository.dumpState(0, 0, null);
|
|
||||||
|
|
||||||
logger.info("Genesis-hash: {}", Hex.toHexString(this.getHash()));
|
logger.info("Genesis-hash: {}", Hex.toHexString(this.getHash()));
|
||||||
logger.info("Genesis-stateRoot: {}", Hex.toHexString(this.getStateRoot()));
|
logger.info("Genesis-stateRoot: {}", Hex.toHexString(this.getStateRoot()));
|
||||||
|
@ -85,4 +84,12 @@ public class Genesis extends Block {
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final static String[] getPremine() {
|
||||||
|
return premine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static BigInteger getPremineAmount() {
|
||||||
|
return BigInteger.valueOf(2).pow(200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,13 @@ public class Repository {
|
||||||
try {
|
try {
|
||||||
if (!iterator.hasNext()) {
|
if (!iterator.hasNext()) {
|
||||||
logger.info("DB is empty - adding Genesis");
|
logger.info("DB is empty - adding Genesis");
|
||||||
|
for (String address : Genesis.getPremine()) {
|
||||||
|
this.createAccount(Hex.decode(address));
|
||||||
|
this.addBalance (Hex.decode(address), Genesis.getPremineAmount());
|
||||||
|
}
|
||||||
blockchain.storeBlock(Genesis.getInstance());
|
blockchain.storeBlock(Genesis.getInstance());
|
||||||
logger.debug("Block #{} -> {}", Genesis.NUMBER, blockchain.getLastBlock().toFlatString());
|
logger.debug("Block #{} -> {}", Genesis.NUMBER, blockchain.getLastBlock().toFlatString());
|
||||||
|
dumpState(0, 0, null);
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Displaying blocks stored in DB sorted on blocknumber");
|
logger.debug("Displaying blocks stored in DB sorted on blocknumber");
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class HelloMessage extends Message {
|
||||||
|
|
||||||
// the message does no distinguish between the 0 and null so here I check command code for null
|
// the message does no distinguish between the 0 and null so here I check command code for null
|
||||||
// TODO: find out if it can be 00
|
// TODO: find out if it can be 00
|
||||||
if (((RLPItem)(paramsList).get(0)).getRLPData() != null) {
|
if (((RLPItem)paramsList.get(0)).getRLPData() != null) {
|
||||||
throw new Error("HelloMessage: parsing for mal data");
|
throw new Error("HelloMessage: parsing for mal data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Arrays;
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.db.ByteArrayWrapper;
|
import org.ethereum.db.ByteArrayWrapper;
|
||||||
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.util.Value;
|
import org.ethereum.util.Value;
|
||||||
import org.iq80.leveldb.DB;
|
import org.iq80.leveldb.DB;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -46,7 +47,7 @@ public class Trie implements TrieFacade {
|
||||||
private Object prevRoot;
|
private Object prevRoot;
|
||||||
private Object root;
|
private Object root;
|
||||||
private Cache cache;
|
private Cache cache;
|
||||||
|
|
||||||
public Trie(DB db) {
|
public Trie(DB db) {
|
||||||
this(db, "");
|
this(db, "");
|
||||||
}
|
}
|
||||||
|
@ -413,7 +414,7 @@ public class Trie implements TrieFacade {
|
||||||
if (root == null
|
if (root == null
|
||||||
|| (root instanceof byte[] && ((byte[]) root).length == 0)
|
|| (root instanceof byte[] && ((byte[]) root).length == 0)
|
||||||
|| (root instanceof String && "".equals((String) root))) {
|
|| (root instanceof String && "".equals((String) root))) {
|
||||||
return new byte[0];
|
return ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
} else if (root instanceof byte[]) {
|
} else if (root instanceof byte[]) {
|
||||||
return (byte[]) this.getRoot();
|
return (byte[]) this.getRoot();
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue