Calculate txTrieRoot from actual transactions in a block and move block header to separate class
This commit is contained in:
parent
72f7e18d7a
commit
6ec5dd9d12
|
@ -6,9 +6,7 @@ import org.ethereum.trie.Trie;
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.ethereum.util.RLPElement;
|
import org.ethereum.util.RLPElement;
|
||||||
import org.ethereum.util.RLPItem;
|
|
||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
import org.ethereum.util.Utils;
|
|
||||||
import org.spongycastle.util.BigIntegers;
|
import org.spongycastle.util.BigIntegers;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
@ -27,81 +25,42 @@ public class Block {
|
||||||
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||||
private static long MIN_GAS_LIMIT = BigInteger.valueOf(10).pow(4).longValue();
|
private static long MIN_GAS_LIMIT = BigInteger.valueOf(10).pow(4).longValue();
|
||||||
|
|
||||||
|
private BlockHeader header;
|
||||||
|
|
||||||
|
/* Transactions */
|
||||||
|
private List<TransactionReceipt> txReceiptList = new ArrayList<TransactionReceipt>();
|
||||||
|
private List<Transaction> transactionsList = new ArrayList<Transaction>();
|
||||||
|
|
||||||
|
/* Uncles */
|
||||||
|
private List<Block> uncleList = new ArrayList<Block>();
|
||||||
|
|
||||||
|
/* Private */
|
||||||
|
|
||||||
private byte[] rlpEncoded;
|
private byte[] rlpEncoded;
|
||||||
private boolean parsed = false;
|
private boolean parsed = false;
|
||||||
|
|
||||||
private byte[] hash;
|
private byte[] hash;
|
||||||
|
|
||||||
/* The SHA3 256-bit hash of the parent block, in its entirety */
|
private Trie accountState;
|
||||||
private byte[] parentHash;
|
private Trie txsState;
|
||||||
/* The SHA3 256-bit hash of the uncles list portion of this block */
|
|
||||||
private byte[] unclesHash;
|
/* Constructors */
|
||||||
/* The 160-bit address to which all fees collected from the
|
|
||||||
* successful mining of this block be transferred; formally */
|
|
||||||
private byte[] coinbase;
|
|
||||||
/* The SHA3 256-bit hash of the root node of the state trie,
|
|
||||||
* after all transactions are executed and finalisations applied */
|
|
||||||
private byte[] stateRoot;
|
|
||||||
/* The SHA3 256-bit hash of the root node of the trie structure
|
|
||||||
* populated with each transaction recipe in the transaction recipes
|
|
||||||
* list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_reciepe)]
|
|
||||||
* of the block */
|
|
||||||
private byte[] txTrieRoot;
|
|
||||||
/* A scalar value corresponding to the difficulty level of this block.
|
|
||||||
* This can be calculated from the previous block’s difficulty level
|
|
||||||
* and the timestamp */
|
|
||||||
private byte[] difficulty;
|
|
||||||
/* A scalar value equal to the reasonable output of Unix's time()
|
|
||||||
* at this block's inception */
|
|
||||||
private long timestamp;
|
|
||||||
/* A scalar value equal to the number of ancestor blocks.
|
|
||||||
* The genesis block has a number of zero */
|
|
||||||
private long number;
|
|
||||||
/* A scalar value equal to the minimum price of gas a transaction
|
|
||||||
* must have provided in order to be sufficient for inclusion
|
|
||||||
* by this miner in this block */
|
|
||||||
private long minGasPrice;
|
|
||||||
/* A scalar value equal to the current limit of gas expenditure per block */
|
|
||||||
private long gasLimit;
|
|
||||||
/* A scalar value equal to the total gas used in transactions in this block */
|
|
||||||
private long gasUsed;
|
|
||||||
/* An arbitrary byte array containing data relevant to this block.
|
|
||||||
* With the exception of the genesis block, this must be 32 bytes or fewer */
|
|
||||||
private byte[] extraData;
|
|
||||||
/* A 256-bit hash which proves that a sufficient amount
|
|
||||||
* of computation has been carried out on this block */
|
|
||||||
private byte[] nonce;
|
|
||||||
|
|
||||||
private List<Transaction> transactionsList = new ArrayList<Transaction>();
|
|
||||||
private List<TransactionRecipe> txRecipeList = new ArrayList<TransactionRecipe>();
|
|
||||||
|
|
||||||
private List<Block> uncleList = new ArrayList<Block>();
|
|
||||||
private Trie state;
|
|
||||||
|
|
||||||
public Block(byte[] rawData) {
|
public Block(byte[] rawData) {
|
||||||
this.rlpEncoded = rawData;
|
this.rlpEncoded = rawData;
|
||||||
this.parsed = false;
|
this.parsed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
||||||
byte[] txTrieRoot, byte[] difficulty, long number,
|
byte[] difficulty, long number, long minGasPrice, long gasLimit,
|
||||||
long minGasPrice, long gasLimit, long gasUsed, long timestamp,
|
long gasUsed, long timestamp, byte[] extraData, byte[] nonce,
|
||||||
byte[] extraData, byte[] nonce, List<Transaction> transactionsList,
|
List<Transaction> transactionsList, List<Block> uncleList) {
|
||||||
List<Block> uncleList) {
|
this.header = new BlockHeader(parentHash, unclesHash, coinbase,
|
||||||
this.parentHash = parentHash;
|
difficulty, number, minGasPrice, gasLimit, gasUsed,
|
||||||
this.unclesHash = unclesHash;
|
timestamp, extraData, nonce);
|
||||||
this.coinbase = coinbase;
|
this.accountState = new Trie(Config.STATE_DB.getDb());
|
||||||
this.state = new Trie(Config.STATE_DB.getDb());
|
this.txsState = new Trie(null);
|
||||||
this.stateRoot = state.getRootHash();
|
this.header.setStateRoot(accountState.getRootHash());
|
||||||
this.txTrieRoot = txTrieRoot;
|
this.header.setTxTrieRoot(txsState.getRootHash());
|
||||||
this.difficulty = difficulty;
|
|
||||||
this.number = number;
|
|
||||||
this.minGasPrice = minGasPrice;
|
|
||||||
this.gasLimit = gasLimit;
|
|
||||||
this.gasUsed = gasUsed;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.extraData = extraData;
|
|
||||||
this.nonce = nonce;
|
|
||||||
this.transactionsList = transactionsList;
|
this.transactionsList = transactionsList;
|
||||||
this.uncleList = uncleList;
|
this.uncleList = uncleList;
|
||||||
this.parsed = true;
|
this.parsed = true;
|
||||||
|
@ -117,46 +76,28 @@ public class Block {
|
||||||
|
|
||||||
// Parse Header
|
// Parse Header
|
||||||
RLPList header = (RLPList) block.get(0);
|
RLPList header = (RLPList) block.get(0);
|
||||||
|
this.header = new BlockHeader(header);
|
||||||
this.parentHash = ((RLPItem) header.get(0)).getRLPData();
|
|
||||||
this.unclesHash = ((RLPItem) header.get(1)).getRLPData();
|
|
||||||
this.coinbase = ((RLPItem) header.get(2)).getRLPData();
|
|
||||||
this.stateRoot = ((RLPItem) header.get(3)).getRLPData();
|
|
||||||
this.txTrieRoot = ((RLPItem) header.get(4)).getRLPData();
|
|
||||||
this.difficulty = ((RLPItem) header.get(5)).getRLPData();
|
|
||||||
|
|
||||||
byte[] nrBytes = ((RLPItem) header.get(6)).getRLPData();
|
|
||||||
byte[] gpBytes = ((RLPItem) header.get(7)).getRLPData();
|
|
||||||
byte[] glBytes = ((RLPItem) header.get(8)).getRLPData();
|
|
||||||
byte[] guBytes = ((RLPItem) header.get(9)).getRLPData();
|
|
||||||
byte[] tsBytes = ((RLPItem) header.get(10)).getRLPData();
|
|
||||||
|
|
||||||
this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue();
|
|
||||||
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue();
|
|
||||||
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
|
||||||
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
|
||||||
this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue();
|
|
||||||
|
|
||||||
this.extraData = ((RLPItem) header.get(11)).getRLPData();
|
|
||||||
this.nonce = ((RLPItem) header.get(12)).getRLPData();
|
|
||||||
|
|
||||||
// Parse Transactions
|
// Parse Transactions
|
||||||
RLPList transactions = (RLPList) block.get(1);
|
this.txsState = new Trie(null);
|
||||||
for (RLPElement rlpTx : transactions){
|
RLPList txReceipts = (RLPList) block.get(1);
|
||||||
|
for (int i = 0; i < txReceipts.size(); i++) {
|
||||||
RLPElement txData = ((RLPList)rlpTx).get(0);
|
RLPElement rlpTxReceipt = txReceipts.get(i);
|
||||||
|
RLPElement txData = ((RLPList)rlpTxReceipt).get(0);
|
||||||
|
|
||||||
Transaction tx = new Transaction(txData.getRLPData());
|
Transaction tx = new Transaction(txData.getRLPData());
|
||||||
this.transactionsList.add(tx);
|
this.transactionsList.add(tx);
|
||||||
|
this.txsState.update(RLP.encodeInt(i), tx.getEncoded());
|
||||||
|
|
||||||
// YP 4.3.1
|
// YP 4.3.1
|
||||||
RLPElement cummGas = ((RLPList)rlpTx).get(1);
|
RLPElement cummGas = ((RLPList)rlpTxReceipt).get(1);
|
||||||
RLPElement pstTxState = ((RLPList)rlpTx).get(2);
|
RLPElement pstTxState = ((RLPList)rlpTxReceipt).get(2);
|
||||||
|
|
||||||
TransactionRecipe txRecipe =
|
// TransactionReceipt txReceipt =
|
||||||
new TransactionRecipe(tx, cummGas.getRLPData(), pstTxState.getRLPData());
|
// new TransactionReceipt(tx, cummGas.getRLPData(), pstTxState.getRLPData());
|
||||||
txRecipeList.add(txRecipe);
|
// txReceiptList.add(txReceipt);
|
||||||
}
|
}
|
||||||
|
this.header.setTxTrieRoot(txsState.getRootHash());
|
||||||
|
|
||||||
// Parse Uncles
|
// Parse Uncles
|
||||||
RLPList uncleBlocks = (RLPList) block.get(2);
|
RLPList uncleBlocks = (RLPList) block.get(2);
|
||||||
|
@ -180,67 +121,67 @@ public class Block {
|
||||||
|
|
||||||
public byte[] getParentHash() {
|
public byte[] getParentHash() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return parentHash;
|
return this.header.getParentHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getUnclesHash() {
|
public byte[] getUnclesHash() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return unclesHash;
|
return this.header.getUnclesHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getCoinbase() {
|
public byte[] getCoinbase() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return coinbase;
|
return this.header.getCoinbase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getStateRoot() {
|
public byte[] getStateRoot() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return this.stateRoot;
|
return this.header.getStateRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getTxTrieRoot() {
|
public byte[] getTxTrieRoot() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return txTrieRoot;
|
return this.header.getTxTrieRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getDifficulty() {
|
public byte[] getDifficulty() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return difficulty;
|
return this.header.getDifficulty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return timestamp;
|
return this.header.getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNumber() {
|
public long getNumber() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return number;
|
return this.header.getNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMinGasPrice() {
|
public long getMinGasPrice() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return minGasPrice;
|
return this.header.getMinGasPrice();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getGasLimit() {
|
public long getGasLimit() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return gasLimit;
|
return this.header.getGasLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getGasUsed() {
|
public long getGasUsed() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return gasUsed;
|
return this.header.getGasUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getExtraData() {
|
public byte[] getExtraData() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return extraData;
|
return this.header.getExtraData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getNonce() {
|
public byte[] getNonce() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return nonce;
|
return this.header.getNonce();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Transaction> getTransactionsList() {
|
public List<Transaction> getTransactionsList() {
|
||||||
|
@ -251,12 +192,12 @@ public class Block {
|
||||||
return transactionsList;
|
return transactionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TransactionRecipe> getTxRecipeList() {
|
public List<TransactionReceipt> getTxReceiptList() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
if (transactionsList == null) {
|
if (transactionsList == null) {
|
||||||
this.txRecipeList = new ArrayList<TransactionRecipe>();
|
this.txReceiptList = new ArrayList<TransactionReceipt>();
|
||||||
}
|
}
|
||||||
return txRecipeList;
|
return txReceiptList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Block> getUncleList() {
|
public List<Block> getUncleList() {
|
||||||
|
@ -279,27 +220,13 @@ public class Block {
|
||||||
toStringBuff.setLength(0);
|
toStringBuff.setLength(0);
|
||||||
toStringBuff.append("BlockData [\n");
|
toStringBuff.append("BlockData [\n");
|
||||||
toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append("\n");
|
toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append("\n");
|
||||||
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("\n");
|
toStringBuff.append(header.toString());
|
||||||
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("\n");
|
|
||||||
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("\n");
|
for (TransactionReceipt txReceipt : getTxReceiptList()) {
|
||||||
toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("\n");
|
|
||||||
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n");
|
|
||||||
toStringBuff.append(" difficulty=" + ByteUtil.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");
|
|
||||||
|
|
||||||
for (TransactionRecipe txRecipe : getTxRecipeList()){
|
|
||||||
|
|
||||||
toStringBuff.append("\n");
|
toStringBuff.append("\n");
|
||||||
toStringBuff.append(txRecipe.toString());
|
toStringBuff.append(txReceipt.toString());
|
||||||
}
|
}
|
||||||
|
toStringBuff.append("\n ]");
|
||||||
toStringBuff.append("\n]");
|
|
||||||
return toStringBuff.toString();
|
return toStringBuff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,20 +236,8 @@ public class Block {
|
||||||
toStringBuff.setLength(0);
|
toStringBuff.setLength(0);
|
||||||
toStringBuff.append("BlockData [");
|
toStringBuff.append("BlockData [");
|
||||||
toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append("");
|
toStringBuff.append(" hash=" + ByteUtil.toHexString(hash)).append("");
|
||||||
toStringBuff.append(" parentHash=" + ByteUtil.toHexString(parentHash)).append("");
|
toStringBuff.append(header.toFlatString());
|
||||||
toStringBuff.append(" unclesHash=" + ByteUtil.toHexString(unclesHash)).append("");
|
|
||||||
toStringBuff.append(" coinbase=" + ByteUtil.toHexString(coinbase)).append("");
|
|
||||||
toStringBuff.append(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("");
|
|
||||||
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("");
|
|
||||||
toStringBuff.append(" difficulty=" + ByteUtil.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("");
|
|
||||||
|
|
||||||
for (Transaction tx : getTransactionsList()){
|
for (Transaction tx : getTransactionsList()){
|
||||||
|
|
||||||
toStringBuff.append("\n");
|
toStringBuff.append("\n");
|
||||||
|
@ -334,8 +249,10 @@ public class Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] updateState(byte[] key, byte[] value) {
|
public byte[] updateState(byte[] key, byte[] value) {
|
||||||
this.state.update(key, value);
|
this.accountState.update(key, value);
|
||||||
return this.stateRoot = this.state.getRootHash();
|
byte[] stateRoot = this.accountState.getRootHash();
|
||||||
|
this.header.setStateRoot(stateRoot);
|
||||||
|
return stateRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -365,21 +282,21 @@ public class Block {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public long calcGasLimit() {
|
public long calcGasLimit() {
|
||||||
if (parentHash == null)
|
if (this.header.getParentHash() == null)
|
||||||
return 1000000L;
|
return 1000000L;
|
||||||
else {
|
else {
|
||||||
Block parent = this.getParent();
|
Block parent = this.getParent();
|
||||||
return Math.max(MIN_GAS_LIMIT, (parent.gasLimit * (1024 - 1) + (parent.gasUsed * 6 / 5)) / 1024);
|
return Math.max(MIN_GAS_LIMIT, (parent.header.getGasLimit() * (1024 - 1) + (parent.header.getGasUsed() * 6 / 5)) / 1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] calcDifficulty() {
|
public byte[] calcDifficulty() {
|
||||||
if (parentHash == null)
|
if (this.header.getParentHash() == null)
|
||||||
return Genesis.DIFFICULTY;
|
return Genesis.DIFFICULTY;
|
||||||
else {
|
else {
|
||||||
Block parent = this.getParent();
|
Block parent = this.getParent();
|
||||||
long parentDifficulty = new BigInteger(1, parent.difficulty).longValue();
|
long parentDifficulty = new BigInteger(1, parent.header.getDifficulty()).longValue();
|
||||||
long newDifficulty = timestamp >= parent.timestamp + 42 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
long newDifficulty = this.header.getTimestamp() >= parent.header.getTimestamp() + 42 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||||
return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,24 +312,7 @@ public class Block {
|
||||||
// Object[] uncles = this.getUncleList().toArray();
|
// Object[] uncles = this.getUncleList().toArray();
|
||||||
// return RLP.encode(new Object[] { header, transactions, uncles });
|
// return RLP.encode(new Object[] { header, transactions, uncles });
|
||||||
|
|
||||||
byte[] parentHash = RLP.encodeElement(this.parentHash);
|
byte[] header = this.header.getEncoded();
|
||||||
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);
|
|
||||||
|
|
||||||
byte[] header = RLP.encodeList(parentHash, unclesHash, coinbase,
|
|
||||||
stateRoot, txTrieRoot, difficulty, number,
|
|
||||||
minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce);
|
|
||||||
|
|
||||||
byte[] transactions = RLP.encodeList();
|
byte[] transactions = RLP.encodeList();
|
||||||
byte[] uncles = RLP.encodeList();
|
byte[] uncles = RLP.encodeList();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.ethereum.util.ByteUtil;
|
||||||
|
import org.ethereum.util.RLP;
|
||||||
|
import org.ethereum.util.RLPItem;
|
||||||
|
import org.ethereum.util.RLPList;
|
||||||
|
import org.ethereum.util.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block header is a value object containing
|
||||||
|
* the basic information of a block
|
||||||
|
*/
|
||||||
|
public class BlockHeader {
|
||||||
|
|
||||||
|
/* The SHA3 256-bit hash of the parent block, in its entirety */
|
||||||
|
private byte[] parentHash;
|
||||||
|
/* The SHA3 256-bit hash of the uncles list portion of this block */
|
||||||
|
private byte[] unclesHash;
|
||||||
|
/* The 160-bit address to which all fees collected from the
|
||||||
|
* successful mining of this block be transferred; formally */
|
||||||
|
private byte[] coinbase;
|
||||||
|
/* The SHA3 256-bit hash of the root node of the state trie,
|
||||||
|
* after all transactions are executed and finalisations applied */
|
||||||
|
private byte[] stateRoot;
|
||||||
|
/* The SHA3 256-bit hash of the root node of the trie structure
|
||||||
|
* populated with each transaction recipe in the transaction recipes
|
||||||
|
* list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_reciepe)]
|
||||||
|
* of the block */
|
||||||
|
private byte[] txTrieRoot;
|
||||||
|
/* A scalar value corresponding to the difficulty level of this block.
|
||||||
|
* This can be calculated from the previous block’s difficulty level
|
||||||
|
* and the timestamp */
|
||||||
|
private byte[] difficulty;
|
||||||
|
/* A scalar value equal to the reasonable output of Unix's time()
|
||||||
|
* at this block's inception */
|
||||||
|
private long timestamp;
|
||||||
|
/* A scalar value equal to the number of ancestor blocks.
|
||||||
|
* The genesis block has a number of zero */
|
||||||
|
private long number;
|
||||||
|
/* A scalar value equal to the minimum price of gas a transaction
|
||||||
|
* must have provided in order to be sufficient for inclusion
|
||||||
|
* by this miner in this block */
|
||||||
|
private long minGasPrice;
|
||||||
|
/* A scalar value equal to the current limit of gas expenditure per block */
|
||||||
|
private long gasLimit;
|
||||||
|
/* A scalar value equal to the total gas used in transactions in this block */
|
||||||
|
private long gasUsed;
|
||||||
|
/* An arbitrary byte array containing data relevant to this block.
|
||||||
|
* With the exception of the genesis block, this must be 32 bytes or fewer */
|
||||||
|
private byte[] extraData;
|
||||||
|
/* A 256-bit hash which proves that a sufficient amount
|
||||||
|
* of computation has been carried out on this block */
|
||||||
|
private byte[] nonce;
|
||||||
|
|
||||||
|
public BlockHeader(RLPList rlpHeader) {
|
||||||
|
this.parentHash = ((RLPItem) rlpHeader.get(0)).getRLPData();
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
byte[] guBytes = ((RLPItem) rlpHeader.get(9)).getRLPData();
|
||||||
|
byte[] tsBytes = ((RLPItem) rlpHeader.get(10)).getRLPData();
|
||||||
|
|
||||||
|
this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue();
|
||||||
|
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue();
|
||||||
|
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
||||||
|
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
||||||
|
this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue();
|
||||||
|
|
||||||
|
this.extraData = ((RLPItem) rlpHeader.get(11)).getRLPData();
|
||||||
|
this.nonce = ((RLPItem) rlpHeader.get(12)).getRLPData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
||||||
|
byte[] difficulty, long number, long minGasPrice, long gasLimit,
|
||||||
|
long gasUsed, long timestamp, byte[] extraData, byte[] nonce) {
|
||||||
|
this.parentHash = parentHash;
|
||||||
|
this.unclesHash = unclesHash;
|
||||||
|
this.coinbase = coinbase;
|
||||||
|
this.difficulty = difficulty;
|
||||||
|
this.number = number;
|
||||||
|
this.minGasPrice = minGasPrice;
|
||||||
|
this.gasLimit = gasLimit;
|
||||||
|
this.gasUsed = gasUsed;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.extraData = extraData;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getParentHash() {
|
||||||
|
return parentHash;
|
||||||
|
}
|
||||||
|
public void setParentHash(byte[] parentHash) {
|
||||||
|
this.parentHash = parentHash;
|
||||||
|
}
|
||||||
|
public byte[] getUnclesHash() {
|
||||||
|
return unclesHash;
|
||||||
|
}
|
||||||
|
public void setUnclesHash(byte[] unclesHash) {
|
||||||
|
this.unclesHash = unclesHash;
|
||||||
|
}
|
||||||
|
public byte[] getCoinbase() {
|
||||||
|
return coinbase;
|
||||||
|
}
|
||||||
|
public void setCoinbase(byte[] coinbase) {
|
||||||
|
this.coinbase = coinbase;
|
||||||
|
}
|
||||||
|
public byte[] getStateRoot() {
|
||||||
|
return stateRoot;
|
||||||
|
}
|
||||||
|
public void setStateRoot(byte[] stateRoot) {
|
||||||
|
this.stateRoot = stateRoot;
|
||||||
|
}
|
||||||
|
public byte[] getTxTrieRoot() {
|
||||||
|
return txTrieRoot;
|
||||||
|
}
|
||||||
|
public void setTxTrieRoot(byte[] txTrieRoot) {
|
||||||
|
this.txTrieRoot = txTrieRoot;
|
||||||
|
}
|
||||||
|
public byte[] getDifficulty() {
|
||||||
|
return difficulty;
|
||||||
|
}
|
||||||
|
public void setDifficulty(byte[] difficulty) {
|
||||||
|
this.difficulty = difficulty;
|
||||||
|
}
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
public void setTimestamp(long timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
public long getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
public void setNumber(long number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
public long getMinGasPrice() {
|
||||||
|
return minGasPrice;
|
||||||
|
}
|
||||||
|
public void setMinGasPrice(long minGasPrice) {
|
||||||
|
this.minGasPrice = minGasPrice;
|
||||||
|
}
|
||||||
|
public long getGasLimit() {
|
||||||
|
return gasLimit;
|
||||||
|
}
|
||||||
|
public void setGasLimit(long gasLimit) {
|
||||||
|
this.gasLimit = gasLimit;
|
||||||
|
}
|
||||||
|
public long getGasUsed() {
|
||||||
|
return gasUsed;
|
||||||
|
}
|
||||||
|
public void setGasUsed(long gasUsed) {
|
||||||
|
this.gasUsed = gasUsed;
|
||||||
|
}
|
||||||
|
public byte[] getExtraData() {
|
||||||
|
return extraData;
|
||||||
|
}
|
||||||
|
public void setExtraData(byte[] extraData) {
|
||||||
|
this.extraData = extraData;
|
||||||
|
}
|
||||||
|
public byte[] getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
public void setNonce(byte[] nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
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);
|
||||||
|
|
||||||
|
return RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||||
|
stateRoot, txTrieRoot, difficulty, number,
|
||||||
|
minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringBuffer toStringBuff = new StringBuffer();
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
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(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("\n");
|
||||||
|
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("\n");
|
||||||
|
toStringBuff.append(" difficulty=" + ByteUtil.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");
|
||||||
|
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(" stateHash=" + ByteUtil.toHexString(stateRoot)).append("");
|
||||||
|
toStringBuff.append(" txTrieHash=" + ByteUtil.toHexString(txTrieRoot)).append("");
|
||||||
|
toStringBuff.append(" difficulty=" + ByteUtil.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("");
|
||||||
|
return toStringBuff.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,17 @@ public class Genesis extends Block {
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger(this.getClass());
|
Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
private AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
private String[] premine = new String[] {
|
||||||
|
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // # (M)
|
||||||
|
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // # (A)
|
||||||
|
"e6716f9544a56c530d868e4bfbacb172315bdead", // # (J)
|
||||||
|
"8a40bfaa73256b60764c1bf40675a99083efb075", // # (G)
|
||||||
|
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
|
||||||
|
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // # (V)
|
||||||
|
"6c386a4b26f73c802f34673f7248bb118f97424a", // # (HH)
|
||||||
|
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826" }; // # (R)
|
||||||
|
|
||||||
private static byte[] zeroHash256 = new byte[32];
|
private static byte[] zeroHash256 = new byte[32];
|
||||||
private static byte[] zeroHash160 = new byte[20];
|
private static byte[] zeroHash160 = new byte[20];
|
||||||
private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList());
|
private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList());
|
||||||
|
@ -20,7 +31,6 @@ public class Genesis extends Block {
|
||||||
public static byte[] PARENT_HASH = zeroHash256;
|
public static byte[] PARENT_HASH = zeroHash256;
|
||||||
public static byte[] UNCLES_HASH = sha3EmptyList;
|
public static byte[] UNCLES_HASH = sha3EmptyList;
|
||||||
public static byte[] COINBASE = zeroHash160;
|
public static byte[] COINBASE = zeroHash160;
|
||||||
public static byte[] TX_TRIE_ROOT = new byte[0];
|
|
||||||
public static byte[] DIFFICULTY = BigInteger.valueOf(2).pow(22).toByteArray();
|
public static byte[] DIFFICULTY = BigInteger.valueOf(2).pow(22).toByteArray();
|
||||||
public static long NUMBER = 0;
|
public static long NUMBER = 0;
|
||||||
public static long MIN_GAS_PRICE = 0;
|
public static long MIN_GAS_PRICE = 0;
|
||||||
|
@ -33,28 +43,14 @@ public class Genesis extends Block {
|
||||||
private static Block instance;
|
private static Block instance;
|
||||||
|
|
||||||
private Genesis() {
|
private Genesis() {
|
||||||
super(PARENT_HASH, UNCLES_HASH, COINBASE, TX_TRIE_ROOT, 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);
|
||||||
|
|
||||||
// Premine state
|
// Premine state
|
||||||
AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
for (String address : premine) {
|
||||||
// # (M)
|
this.updateState(Hex.decode(address), acct.getEncoded());
|
||||||
this.updateState(Hex.decode("2ef47100e0787b915105fd5e3f4ff6752079d5cb"), acct.getEncoded());
|
}
|
||||||
// # (A)
|
|
||||||
this.updateState(Hex.decode("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"), acct.getEncoded());
|
|
||||||
// # (J)
|
|
||||||
this.updateState(Hex.decode("e6716f9544a56c530d868e4bfbacb172315bdead"), acct.getEncoded());
|
|
||||||
// # (G)
|
|
||||||
this.updateState(Hex.decode("8a40bfaa73256b60764c1bf40675a99083efb075"), acct.getEncoded());
|
|
||||||
// # (CH)
|
|
||||||
this.updateState(Hex.decode("e4157b34ea9615cfbde6b4fda419828124b70c78"), acct.getEncoded());
|
|
||||||
// # (V)
|
|
||||||
this.updateState(Hex.decode("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"), acct.getEncoded());
|
|
||||||
// # (HH)
|
|
||||||
this.updateState(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct.getEncoded());
|
|
||||||
// # (R)
|
|
||||||
this.updateState(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct.getEncoded());
|
|
||||||
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()));
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ public class Transaction {
|
||||||
", signatureV=" + signature.v +
|
", signatureV=" + signature.v +
|
||||||
", signatureR=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.r)) +
|
", signatureR=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.r)) +
|
||||||
", signatureS=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.s)) +
|
", signatureS=" + ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.s)) +
|
||||||
"\n ]";
|
" ]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,31 +3,28 @@ package org.ethereum.core;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* www.ethereumJ.com
|
* The transaction receipt is a tuple of three items
|
||||||
* User: Roman Mandeleil
|
* comprising the transaction, together with the post-transaction state,
|
||||||
* Created on: 06/06/2014 04:03
|
* and the cumulative gas used in the block containing the transaction receipt
|
||||||
|
* as of immediately after the transaction has happened,
|
||||||
*/
|
*/
|
||||||
|
public class TransactionReceipt {
|
||||||
public class TransactionRecipe {
|
|
||||||
|
|
||||||
private Transaction transaction;
|
private Transaction transaction;
|
||||||
private byte[] postTxState;
|
private byte[] postTxState;
|
||||||
private byte[] cumulativeGas;
|
private byte[] cumulativeGas;
|
||||||
|
|
||||||
/* Tx Recipe in encoded form */
|
/* Tx Receipt in encoded form */
|
||||||
private byte[] rlpEncoded;
|
private byte[] rlpEncoded;
|
||||||
|
|
||||||
|
public TransactionReceipt(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) {
|
||||||
public TransactionRecipe(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) {
|
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
this.postTxState = postTxState;
|
this.postTxState = postTxState;
|
||||||
this.cumulativeGas = cumulativeGas;
|
this.cumulativeGas = cumulativeGas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getEncoded(){
|
public byte[] getEncoded() {
|
||||||
|
|
||||||
if(rlpEncoded != null) return rlpEncoded;
|
if(rlpEncoded != null) return rlpEncoded;
|
||||||
|
|
||||||
|
@ -42,7 +39,7 @@ public class TransactionRecipe {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TransactionRecipe[" +
|
return "TransactionReceipt[" +
|
||||||
"\n " + transaction +
|
"\n " + transaction +
|
||||||
"\n , postTxState=" + Hex.toHexString(postTxState) +
|
"\n , postTxState=" + Hex.toHexString(postTxState) +
|
||||||
"\n , cumulativeGas=" + Hex.toHexString(cumulativeGas) +
|
"\n , cumulativeGas=" + Hex.toHexString(cumulativeGas) +
|
|
@ -762,7 +762,7 @@ public class RLP {
|
||||||
} else if ((singleByte & 0xFF) < 0x7F) {
|
} else if ((singleByte & 0xFF) < 0x7F) {
|
||||||
return new byte[] { singleByte };
|
return new byte[] { singleByte };
|
||||||
} else {
|
} else {
|
||||||
return new byte[] { (byte) (OFFSET_SHORT_ITEM+1), singleByte };
|
return new byte[] { (byte) (OFFSET_SHORT_ITEM + 1), singleByte };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,6 +775,25 @@ public class RLP {
|
||||||
(byte) (singleShort >> 0 & 0xFF) };
|
(byte) (singleShort >> 0 & 0xFF) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] encodeInt(int singleInt) {
|
||||||
|
if (singleInt <= 0xFF)
|
||||||
|
return encodeByte((byte) singleInt);
|
||||||
|
else if (singleInt <= 0xFFFF)
|
||||||
|
return encodeShort((short) singleInt);
|
||||||
|
else if (singleInt <= 0xFFFFFF)
|
||||||
|
return new byte[] { (byte) (OFFSET_SHORT_ITEM + 3),
|
||||||
|
(byte) (singleInt >>> 16),
|
||||||
|
(byte) (singleInt >>> 8),
|
||||||
|
(byte) singleInt};
|
||||||
|
else {
|
||||||
|
return new byte[] { (byte) (OFFSET_SHORT_ITEM + 4),
|
||||||
|
(byte) (singleInt >>> 24),
|
||||||
|
(byte) (singleInt >>> 16),
|
||||||
|
(byte) (singleInt >>> 8),
|
||||||
|
(byte) singleInt};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] encodeString(String srcString) {
|
public static byte[] encodeString(String srcString) {
|
||||||
return encodeElement(srcString.getBytes());
|
return encodeElement(srcString.getBytes());
|
||||||
|
|
|
@ -12,7 +12,7 @@ import java.nio.ByteBuffer;
|
||||||
*/
|
*/
|
||||||
public class DataWord {
|
public class DataWord {
|
||||||
|
|
||||||
static DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
|
public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
|
||||||
|
|
||||||
byte[] data = new byte[32];
|
byte[] data = new byte[32];
|
||||||
|
|
||||||
|
|
|
@ -69,4 +69,4 @@ samples.dir = samples
|
||||||
# the existing database will be
|
# the existing database will be
|
||||||
# destroyed and all the data will be
|
# destroyed and all the data will be
|
||||||
# downloaded from peers again
|
# downloaded from peers again
|
||||||
database.reset = false
|
database.reset = true
|
||||||
|
|
|
@ -4,11 +4,9 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import org.abego.treelayout.internal.util.Contract;
|
|
||||||
import org.ethereum.trie.MockDB;
|
import org.ethereum.trie.MockDB;
|
||||||
import org.ethereum.trie.Trie;
|
import org.ethereum.trie.Trie;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
@ -55,7 +53,7 @@ public class StateTest {
|
||||||
|
|
||||||
|
|
||||||
@Test // right way to calc tx trie hash
|
@Test // right way to calc tx trie hash
|
||||||
public void test1(){
|
public void testCalculatePostTxState(){
|
||||||
|
|
||||||
/* txTrieHash=a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f */
|
/* txTrieHash=a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f */
|
||||||
String expected = "a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f";
|
String expected = "a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f";
|
||||||
|
@ -73,14 +71,13 @@ public class StateTest {
|
||||||
byte[] postTxState = Hex.decode("7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527");
|
byte[] postTxState = Hex.decode("7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527");
|
||||||
byte[] cumGas = Hex.decode("0272");
|
byte[] cumGas = Hex.decode("0272");
|
||||||
|
|
||||||
TransactionRecipe tr = new TransactionRecipe(tx, postTxState, cumGas);
|
TransactionReceipt tr = new TransactionReceipt(tx, postTxState, cumGas);
|
||||||
|
|
||||||
Trie trie = new Trie(new MockDB());
|
Trie trie = new Trie(new MockDB());
|
||||||
trie.update(RLP.encodeByte((byte)0), tr.getEncoded());
|
trie.update(RLP.encodeInt(0), tr.getEncoded());
|
||||||
System.out.println(Hex.toHexString(trie.getRootHash()));
|
String txTrieRoot = Hex.toHexString(trie.getRootHash());
|
||||||
|
System.out.println(txTrieRoot);
|
||||||
Assert.assertEquals(expected, Hex.toHexString(trie.getRootHash()));
|
assertEquals(expected, txTrieRoot);
|
||||||
|
|
||||||
|
|
||||||
/* *** GROSS DATA ***
|
/* *** GROSS DATA ***
|
||||||
|
|
||||||
|
@ -100,7 +97,7 @@ public class StateTest {
|
||||||
extraData=null
|
extraData=null
|
||||||
nonce=0000000000000000000000000000000000000000000000005d439960040e4505
|
nonce=0000000000000000000000000000000000000000000000005d439960040e4505
|
||||||
|
|
||||||
TransactionRecipe[
|
TransactionReceipt[
|
||||||
TransactionData [ hash=1ee6fa3149a5e9c09b54009eb6e108aaa7ecd79483d57eedcf2dff93a1505588 nonce=null,
|
TransactionData [ hash=1ee6fa3149a5e9c09b54009eb6e108aaa7ecd79483d57eedcf2dff93a1505588 nonce=null,
|
||||||
gasPrice=09184e72a000, gas=03e8, receiveAddress=0000000000000000000000000000000000000000, value=03e8,
|
gasPrice=09184e72a000, gas=03e8, receiveAddress=0000000000000000000000000000000000000000, value=03e8,
|
||||||
data=60016000546006601160003960066000f261778e600054, signatureV=27,
|
data=60016000546006601160003960066000f261778e600054, signatureV=27,
|
||||||
|
|
|
@ -150,6 +150,42 @@ public class RLPTest {
|
||||||
assertArrayEquals(expected5, data);
|
assertArrayEquals(expected5, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test /** encode int */
|
||||||
|
public void testEncodeInt(){
|
||||||
|
|
||||||
|
byte[] expected = {(byte)0x80};
|
||||||
|
byte[] data = RLP.encodeInt(0);
|
||||||
|
assertArrayEquals(expected, data);
|
||||||
|
|
||||||
|
byte[] expected2 = {(byte)0x78};
|
||||||
|
data = RLP.encodeInt(120);
|
||||||
|
assertArrayEquals(expected2, data);
|
||||||
|
|
||||||
|
byte[] expected3 = {(byte)0x81, (byte)0x7F};
|
||||||
|
data = RLP.encodeInt(127);
|
||||||
|
assertArrayEquals(expected3, data);
|
||||||
|
|
||||||
|
byte[] expected4 = {(byte)0x82, (byte)0x76, (byte)0x5F};
|
||||||
|
data = RLP.encodeInt(30303);
|
||||||
|
assertArrayEquals(expected4, data);
|
||||||
|
|
||||||
|
byte[] expected5 = {(byte)0x82, (byte)0x4E, (byte)0xEA};
|
||||||
|
data = RLP.encodeInt(20202);
|
||||||
|
assertArrayEquals(expected5, data);
|
||||||
|
|
||||||
|
byte[] expected6 = {(byte)0x83, 1, 0, 0};
|
||||||
|
data = RLP.encodeInt(65536);
|
||||||
|
assertArrayEquals(expected6, data);
|
||||||
|
|
||||||
|
byte[] expected7 = {(byte)0x80};
|
||||||
|
data = RLP.encodeInt(Integer.MIN_VALUE);
|
||||||
|
assertArrayEquals(expected7, data);
|
||||||
|
|
||||||
|
byte[] expected8 = {(byte)0x84, (byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF};
|
||||||
|
data = RLP.encodeInt(Integer.MAX_VALUE);
|
||||||
|
assertArrayEquals(expected8, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Test /** encode BigInteger */
|
@Test /** encode BigInteger */
|
||||||
public void test6(){
|
public void test6(){
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ public class DataWordTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddPerformance() {
|
public void testAddPerformance() {
|
||||||
boolean enabled = true;
|
boolean enabled = false;
|
||||||
|
|
||||||
if(enabled) {
|
if(enabled) {
|
||||||
byte[] one = new byte[] { 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
|
byte[] one = new byte[] { 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
|
||||||
|
@ -68,4 +68,24 @@ public class DataWordTest {
|
||||||
// y.add2(new DataWord(three));
|
// y.add2(new DataWord(three));
|
||||||
// System.out.println(Hex.toHexString(y.data));
|
// System.out.println(Hex.toHexString(y.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMod() {
|
||||||
|
String expected = "000000000000000000000000000000000000000000000000000000000000001a";
|
||||||
|
|
||||||
|
byte[] one = new byte[32];
|
||||||
|
one[31] = 0x1e; // 0x000000000000000000000000000000000000000000000000000000000000001e
|
||||||
|
|
||||||
|
byte[] two = new byte[32];
|
||||||
|
for (int i = 0; i < two.length; i++) {
|
||||||
|
two[i] = (byte) 0xff;
|
||||||
|
}
|
||||||
|
two[31] = 0x56; // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56
|
||||||
|
|
||||||
|
DataWord x = new DataWord(one);// System.out.println(x.value());
|
||||||
|
DataWord y = new DataWord(two);// System.out.println(y.value());
|
||||||
|
y.mod(x);
|
||||||
|
assertEquals(32, y.data.length);
|
||||||
|
assertEquals(expected, Hex.toHexString(y.data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue