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 */
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.parsed = false;
}
@ -71,10 +71,7 @@ public class Block {
this.header = new BlockHeader(parentHash, unclesHash, coinbase,
difficulty, number, minGasPrice, gasLimit, gasUsed,
timestamp, extraData, nonce);
this.txsState = new Trie(null);
this.header.setTxTrieRoot(txsState.getRootHash());
this.transactionsList = transactionsList;
this.transactionsList = transactionsList;
this.uncleList = uncleList;
this.parsed = true;
}
@ -90,7 +87,7 @@ public class Block {
// Parse Transactions
RLPList txReceipts = (RLPList) block.get(1);
this.parseTxs(txReceipts);
this.parseTxs(this.header.getTxTrieRoot(), txReceipts);
// Parse Uncles
RLPList uncleBlocks = (RLPList) block.get(2);
@ -188,32 +185,25 @@ public class Block {
this.header.setNonce(nonce);
rlpEncoded = null;
}
public Trie getTxsState() {
return this.txsState;
}
public List<Transaction> getTransactionsList() {
if (!parsed) parseRLP();
if (transactionsList == null) {
this.transactionsList = new ArrayList<>();
}
if (transactionsList == null)
transactionsList = new ArrayList<>();
return transactionsList;
}
public List<TransactionReceipt> getTxReceiptList() {
if (!parsed) parseRLP();
if (transactionsList == null) {
this.txReceiptList = new ArrayList<>();
}
if (txReceiptList == null)
txReceiptList = new ArrayList<>();
return txReceiptList;
}
public List<Block> getUncleList() {
if (!parsed) parseRLP();
if (uncleList == null) {
this.uncleList = new ArrayList<>();
}
if (uncleList == null)
uncleList = new ArrayList<>();
return uncleList;
}
@ -258,30 +248,31 @@ public class Block {
return toStringBuff.toString();
}
private void parseTxs(RLPList txReceipts) {
private void parseTxs(byte[] expectedRoot, RLPList txReceipts) {
this.txsState = new Trie(null);
for (int i = 0; i < txReceipts.size(); i++) {
RLPElement rlpTxReceipt = txReceipts.get(i);
RLPElement txData = ((RLPList)rlpTxReceipt).get(0);
Transaction tx = new Transaction(txData.getRLPData());
this.addAndProcessTransaction(i, tx);
// YP 4.3.1
RLPElement cummGas = ((RLPList)rlpTxReceipt).get(1);
RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(2);
RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(1);
RLPElement cummGas = ((RLPList)rlpTxReceipt).get(2);
Transaction tx = new Transaction(txData.getRLPData());
this.transactionsList.add(tx);
TransactionReceipt txReceipt =
new TransactionReceipt(tx, cummGas.getRLPData(), pstTxState.getRLPData());
txReceiptList.add(txReceipt);
new TransactionReceipt(tx, pstTxState.getRLPData(), cummGas.getRLPData());
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) {
this.transactionsList.add(tx);
this.txsState.update(RLP.encodeInt(counter), tx.getEncoded());
private void addTxReceipt(int counter, TransactionReceipt txReceipt) {
this.txReceiptList.add(txReceipt);
this.txsState.update(RLP.encodeInt(counter), txReceipt.getEncoded());
/* Figure out type of tx
* 1. Contract creation
@ -294,8 +285,6 @@ public class Block {
* 3. Account to account -
* - update state object
*/
// this.allAccountsState.update();
}
/**

View File

@ -2,7 +2,7 @@ package org.ethereum.core;
import java.math.BigInteger;
import org.ethereum.util.ByteUtil;
import static org.ethereum.util.ByteUtil.*;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
@ -59,9 +59,13 @@ public class BlockHeader {
this.unclesHash = ((RLPItem) rlpHeader.get(1)).getRLPData();
this.coinbase = ((RLPItem) rlpHeader.get(2)).getRLPData();
this.stateRoot = ((RLPItem) rlpHeader.get(3)).getRLPData();
this.txTrieRoot = ((RLPItem) rlpHeader.get(4)).getRLPData();
if(this.txTrieRoot == null)
this.txTrieRoot = EMPTY_BYTE_ARRAY;
this.difficulty = ((RLPItem) rlpHeader.get(5)).getRLPData();
byte[] nrBytes = ((RLPItem) rlpHeader.get(6)).getRLPData();
byte[] gpBytes = ((RLPItem) rlpHeader.get(7)).getRLPData();
byte[] glBytes = ((RLPItem) rlpHeader.get(8)).getRLPData();
@ -211,36 +215,36 @@ public class BlockHeader {
public String toString() {
toStringBuff.setLength(0);
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("\n");
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("\n");
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("\n");
toStringBuff.append(" stateRoot=" + ByteUtil.toHexString(stateRoot)).append("\n");
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n");
toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("\n");
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("\n");
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("\n");
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("\n");
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("\n");
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("\n");
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("\n");
toStringBuff.append(" number=" + number).append("\n");
toStringBuff.append(" minGasPrice=" + minGasPrice).append("\n");
toStringBuff.append(" gasLimit=" + gasLimit).append("\n");
toStringBuff.append(" gasUsed=" + gasUsed).append("\n");
toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n");
toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("\n");
toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("\n");
toStringBuff.append(" extraData=" + toHexString(extraData)).append("\n");
toStringBuff.append(" nonce=" + toHexString(nonce)).append("\n");
return toStringBuff.toString();
}
public String toFlatString() {
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("");
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("");
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("");
toStringBuff.append(" stateRoot=" + ByteUtil.toHexString(stateRoot)).append("");
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("");
toStringBuff.append(" difficulty=" + ByteUtil.toHexString(difficulty)).append("");
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("");
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("");
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("");
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("");
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("");
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("");
toStringBuff.append(" number=" + number).append("");
toStringBuff.append(" minGasPrice=" + minGasPrice).append("");
toStringBuff.append(" gasLimit=" + gasLimit).append("");
toStringBuff.append(" gasUsed=" + gasUsed).append("");
toStringBuff.append(" timestamp=" + timestamp).append("");
toStringBuff.append(" extraData=" + ByteUtil.toHexString(extraData)).append("");
toStringBuff.append(" nonce=" + ByteUtil.toHexString(nonce)).append("");
toStringBuff.append(" extraData=" + toHexString(extraData)).append("");
toStringBuff.append(" nonce=" + toHexString(nonce)).append("");
return toStringBuff.toString();
}

View File

@ -1,8 +1,7 @@
package org.ethereum.core;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.Repository;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.Trie;
import org.ethereum.util.RLP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,7 +28,7 @@ import java.math.BigInteger;
*/
public class Genesis extends Block {
private String[] premine = new String[] {
private static String[] premine = new String[] {
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
"b9c015918bdaba24b4ff057a92a3873d6eb201be", // # (V)
@ -64,16 +63,16 @@ public class Genesis extends Block {
super(PARENT_HASH, UNCLES_HASH, COINBASE, DIFFICULTY,
NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP,
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
// some value stateRoot. The latest documentation should be consulted for the value of the state root.
for (String address : premine) {
repository.createAccount(Hex.decode(address));
repository.addBalance (Hex.decode(address), BigInteger.valueOf(2).pow(200) );
AccountState acctState = new AccountState();
acctState.addToBalance(getPremineAmount());
state.update(Hex.decode(address), acctState.getEncoded());
}
setStateRoot(repository.getWorldState().getRootHash());
repository.dumpState(0, 0, null);
setStateRoot(state.getRootHash());
logger.info("Genesis-hash: {}", Hex.toHexString(this.getHash()));
logger.info("Genesis-stateRoot: {}", Hex.toHexString(this.getStateRoot()));
@ -85,4 +84,12 @@ public class Genesis extends Block {
}
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 {
if (!iterator.hasNext()) {
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());
logger.debug("Block #{} -> {}", Genesis.NUMBER, blockchain.getLastBlock().toFlatString());
dumpState(0, 0, null);
} else {
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
// 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");
}

View File

@ -9,6 +9,7 @@ import java.util.Arrays;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.Value;
import org.iq80.leveldb.DB;
import org.slf4j.Logger;
@ -46,7 +47,7 @@ public class Trie implements TrieFacade {
private Object prevRoot;
private Object root;
private Cache cache;
public Trie(DB db) {
this(db, "");
}
@ -413,7 +414,7 @@ public class Trie implements TrieFacade {
if (root == null
|| (root instanceof byte[] && ((byte[]) root).length == 0)
|| (root instanceof String && "".equals((String) root))) {
return new byte[0];
return ByteUtil.EMPTY_BYTE_ARRAY;
} else if (root instanceof byte[]) {
return (byte[]) this.getRoot();
} else {