org.ethereum.core.BlockHeader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ethereumj-core Show documentation
Show all versions of ethereumj-core Show documentation
Java implementation of the Ethereum protocol adapted to use for Hedera Smart Contract Service
The newest version!
/*
* Copyright (c) [2016] [ ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see .
*/
package org.ethereum.core;
import org.ethereum.config.BlockchainNetConfig;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.*;
import org.spongycastle.util.Arrays;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
import static org.ethereum.crypto.HashUtil.EMPTY_LIST_HASH;
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
import static org.ethereum.util.ByteUtil.toHexString;
/**
* Block header is a value object containing
* the basic information of a block
*/
public class BlockHeader {
public static final int NONCE_LENGTH = 8;
public static final int HASH_LENGTH = 32;
public static final int ADDRESS_LENGTH = 20;
public static final int MAX_HEADER_SIZE = 800;
/* 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 in the transaction
* list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_recipe)]
* of the block */
private byte[] txTrieRoot;
/* 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_recipe)]
* of the block */
private byte[] receiptTrieRoot;
/* The Bloom filter composed from indexable information
* (logger address and log topics) contained in each log entry
* from the receipt of each transaction in the transactions list */
private byte[] logsBloom;
/* 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 current limit of gas expenditure per block */
private byte[] gasLimit;
/* A scalar value equal to the total gas used in transactions in this block */
private long gasUsed;
private byte[] mixHash;
/* 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 byte[] hashCache;
public BlockHeader(byte[] encoded) {
this((RLPList) RLP.decode2(encoded).get(0));
}
public BlockHeader(RLPList rlpHeader) {
this.parentHash = rlpHeader.get(0).getRLPData();
this.unclesHash = rlpHeader.get(1).getRLPData();
this.coinbase = rlpHeader.get(2).getRLPData();
this.stateRoot = rlpHeader.get(3).getRLPData();
this.txTrieRoot = rlpHeader.get(4).getRLPData();
if (this.txTrieRoot == null)
this.txTrieRoot = EMPTY_TRIE_HASH;
this.receiptTrieRoot = rlpHeader.get(5).getRLPData();
if (this.receiptTrieRoot == null)
this.receiptTrieRoot = EMPTY_TRIE_HASH;
this.logsBloom = rlpHeader.get(6).getRLPData();
this.difficulty = rlpHeader.get(7).getRLPData();
byte[] nrBytes = rlpHeader.get(8).getRLPData();
byte[] glBytes = rlpHeader.get(9).getRLPData();
byte[] guBytes = rlpHeader.get(10).getRLPData();
byte[] tsBytes = rlpHeader.get(11).getRLPData();
this.number = ByteUtil.byteArrayToLong(nrBytes);
this.gasLimit = glBytes;
this.gasUsed = ByteUtil.byteArrayToLong(guBytes);
this.timestamp = ByteUtil.byteArrayToLong(tsBytes);
this.extraData = rlpHeader.get(12).getRLPData();
this.mixHash = rlpHeader.get(13).getRLPData();
this.nonce = rlpHeader.get(14).getRLPData();
}
public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
byte[] logsBloom, byte[] difficulty, long number,
byte[] gasLimit, long gasUsed, long timestamp,
byte[] extraData, byte[] mixHash, byte[] nonce) {
this.parentHash = parentHash;
this.unclesHash = unclesHash;
this.coinbase = coinbase;
this.logsBloom = logsBloom;
this.difficulty = difficulty;
this.number = number;
this.gasLimit = gasLimit;
this.gasUsed = gasUsed;
this.timestamp = timestamp;
this.extraData = extraData;
this.mixHash = mixHash;
this.nonce = nonce;
this.stateRoot = EMPTY_TRIE_HASH;
}
public boolean isGenesis() {
return this.getNumber() == Genesis.NUMBER;
}
public byte[] getParentHash() {
return parentHash;
}
public byte[] getUnclesHash() {
return unclesHash;
}
public void setUnclesHash(byte[] unclesHash) {
this.unclesHash = unclesHash;
hashCache = null;
}
public byte[] getCoinbase() {
return coinbase;
}
public void setCoinbase(byte[] coinbase) {
this.coinbase = coinbase;
hashCache = null;
}
public byte[] getStateRoot() {
return stateRoot;
}
public void setStateRoot(byte[] stateRoot) {
this.stateRoot = stateRoot;
hashCache = null;
}
public byte[] getTxTrieRoot() {
return txTrieRoot;
}
public void setReceiptsRoot(byte[] receiptTrieRoot) {
this.receiptTrieRoot = receiptTrieRoot;
hashCache = null;
}
public byte[] getReceiptsRoot() {
return receiptTrieRoot;
}
public void setTransactionsRoot(byte[] stateRoot) {
this.txTrieRoot = stateRoot;
hashCache = null;
}
public byte[] getLogsBloom() {
return logsBloom;
}
public byte[] getDifficulty() {
return difficulty;
}
public BigInteger getDifficultyBI() {
return new BigInteger(1, difficulty);
}
public void setDifficulty(byte[] difficulty) {
this.difficulty = difficulty;
hashCache = null;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
hashCache = null;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
hashCache = null;
}
public byte[] getGasLimit() {
return gasLimit;
}
public void setGasLimit(byte[] gasLimit) {
this.gasLimit = gasLimit;
hashCache = null;
}
public long getGasUsed() {
return gasUsed;
}
public void setGasUsed(long gasUsed) {
this.gasUsed = gasUsed;
hashCache = null;
}
public byte[] getMixHash() {
return mixHash;
}
public void setMixHash(byte[] mixHash) {
this.mixHash = mixHash;
hashCache = null;
}
public byte[] getExtraData() {
return extraData;
}
public byte[] getNonce() {
return nonce;
}
public void setNonce(byte[] nonce) {
this.nonce = nonce;
hashCache = null;
}
public void setLogsBloom(byte[] logsBloom) {
this.logsBloom = logsBloom;
hashCache = null;
}
public void setExtraData(byte[] extraData) {
this.extraData = extraData;
hashCache = null;
}
public byte[] getHash() {
if (hashCache == null) {
hashCache = HashUtil.sha3(getEncoded());
}
return hashCache;
}
public byte[] getEncoded() {
return this.getEncoded(true); // with nonce
}
public byte[] getEncodedWithoutNonce() {
return this.getEncoded(false);
}
public byte[] getEncoded(boolean withNonce) {
byte[] parentHash = RLP.encodeElement(this.parentHash);
byte[] unclesHash = RLP.encodeElement(this.unclesHash);
byte[] coinbase = RLP.encodeElement(this.coinbase);
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
if (txTrieRoot == null) this.txTrieRoot = EMPTY_TRIE_HASH;
byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot);
if (receiptTrieRoot == null) this.receiptTrieRoot = EMPTY_TRIE_HASH;
byte[] receiptTrieRoot = RLP.encodeElement(this.receiptTrieRoot);
byte[] logsBloom = RLP.encodeElement(this.logsBloom);
byte[] difficulty = RLP.encodeBigInteger(new BigInteger(1, this.difficulty));
byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number));
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed));
byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp));
byte[] extraData = RLP.encodeElement(this.extraData);
if (withNonce) {
byte[] mixHash = RLP.encodeElement(this.mixHash);
byte[] nonce = RLP.encodeElement(this.nonce);
return RLP.encodeList(parentHash, unclesHash, coinbase,
stateRoot, txTrieRoot, receiptTrieRoot, logsBloom, difficulty, number,
gasLimit, gasUsed, timestamp, extraData, mixHash, nonce);
} else {
return RLP.encodeList(parentHash, unclesHash, coinbase,
stateRoot, txTrieRoot, receiptTrieRoot, logsBloom, difficulty, number,
gasLimit, gasUsed, timestamp, extraData);
}
}
public byte[] getUnclesEncoded(List uncleList) {
byte[][] unclesEncoded = new byte[uncleList.size()][];
int i = 0;
for (BlockHeader uncle : uncleList) {
unclesEncoded[i] = uncle.getEncoded();
++i;
}
return RLP.encodeList(unclesEncoded);
}
public byte[] getPowBoundary() {
return BigIntegers.asUnsignedByteArray(32, BigInteger.ONE.shiftLeft(256).divide(getDifficultyBI()));
}
public byte[] calcPowValue() {
// nonce bytes are expected in Little Endian order, reverting
byte[] nonceReverted = Arrays.reverse(nonce);
byte[] hashWithoutNonce = HashUtil.sha3(getEncodedWithoutNonce());
byte[] seed = Arrays.concatenate(hashWithoutNonce, nonceReverted);
byte[] seedHash = HashUtil.sha512(seed);
byte[] concat = Arrays.concatenate(seedHash, mixHash);
return HashUtil.sha3(concat);
}
public BigInteger calcDifficulty(BlockchainNetConfig config, BlockHeader parent) {
return config.getConfigForBlock(getNumber()).
calcDifficulty(this, parent);
}
public boolean hasUncles() {
return !FastByteComparisons.equal(unclesHash, EMPTY_LIST_HASH);
}
public String toString() {
return toStringWithSuffix("\n");
}
private String toStringWithSuffix(final String suffix) {
StringBuilder toStringBuff = new StringBuilder();
toStringBuff.append(" hash=").append(toHexString(getHash())).append(suffix);
toStringBuff.append(" parentHash=").append(toHexString(parentHash)).append(suffix);
toStringBuff.append(" unclesHash=").append(toHexString(unclesHash)).append(suffix);
toStringBuff.append(" coinbase=").append(toHexString(coinbase)).append(suffix);
toStringBuff.append(" stateRoot=").append(toHexString(stateRoot)).append(suffix);
toStringBuff.append(" txTrieHash=").append(toHexString(txTrieRoot)).append(suffix);
toStringBuff.append(" receiptsTrieHash=").append(toHexString(receiptTrieRoot)).append(suffix);
toStringBuff.append(" difficulty=").append(toHexString(difficulty)).append(suffix);
toStringBuff.append(" number=").append(number).append(suffix);
// toStringBuff.append(" gasLimit=").append(gasLimit).append(suffix);
toStringBuff.append(" gasLimit=").append(toHexString(gasLimit)).append(suffix);
toStringBuff.append(" gasUsed=").append(gasUsed).append(suffix);
toStringBuff.append(" timestamp=").append(timestamp).append(" (").append(Utils.longToDateTime(timestamp)).append(")").append(suffix);
toStringBuff.append(" extraData=").append(toHexString(extraData)).append(suffix);
toStringBuff.append(" mixHash=").append(toHexString(mixHash)).append(suffix);
toStringBuff.append(" nonce=").append(toHexString(nonce)).append(suffix);
return toStringBuff.toString();
}
public String toFlatString() {
return toStringWithSuffix("");
}
public String getShortDescr() {
return "#" + getNumber() + " (" + Hex.toHexString(getHash()).substring(0,6) + " <~ "
+ Hex.toHexString(getParentHash()).substring(0,6) + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlockHeader that = (BlockHeader) o;
return FastByteComparisons.equal(getHash(), that.getHash());
}
@Override
public int hashCode() {
return Arrays.hashCode(getHash());
}
}