Decouple Genesis from repository and validate txStateRoot

This commit is contained in:
nicksavers 2014-08-08 18:12:13 +01:00
parent a4b2570c13
commit b43209457a
6 changed files with 69 additions and 63 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {