Merge pull request #77 from nicksavers/master
Decouple Genesis from Repository and add txTrieRoot validation
This commit is contained in:
commit
d63cc83976
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -280,30 +270,31 @@ public class Block {
|
|||
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -316,8 +307,6 @@ public class Block {
|
|||
* 3. Account to account -
|
||||
* - update state object
|
||||
*/
|
||||
|
||||
// this.allAccountsState.update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,55 +215,55 @@ 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();
|
||||
}
|
||||
|
||||
public String toStylishString() {
|
||||
|
||||
toStringBuff.setLength(0);
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> parentHash</font>=" + ByteUtil.toHexString(parentHash)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> unclesHash</font>=" + ByteUtil.toHexString(unclesHash)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> coinbase</font>=" + ByteUtil.toHexString(coinbase)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> stateRoot</font>=" + ByteUtil.toHexString(stateRoot)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> txTrieHash</font>=" + ByteUtil.toHexString(txTrieRoot)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> difficulty</font>=" + ByteUtil.toHexString(difficulty)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> parentHash</font>=" + toHexString(parentHash)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> unclesHash</font>=" + toHexString(unclesHash)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> coinbase</font>=" + toHexString(coinbase)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> stateRoot</font>=" + toHexString(stateRoot)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> txTrieHash</font>=" + toHexString(txTrieRoot)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> difficulty</font>=" + toHexString(difficulty)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> number</font>=" + number).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> minGasPrice</font>=" + minGasPrice).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> gasLimit</font>=" + gasLimit).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> gasUsed</font>=" + gasUsed).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> timestamp</font>=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> extraData</font>=" + ByteUtil.toHexString(extraData)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> nonce</font>=" + ByteUtil.toHexString(nonce)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> extraData</font>=" + toHexString(extraData)).append("<br/>");
|
||||
toStringBuff.append(", <font color=\"${attribute_color}\"> nonce</font>=" + toHexString(nonce)).append("<br/>");
|
||||
return toStringBuff.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue