Coverage Summary for Class: BlockHeaderBuilder (org.ethereum.core)

Class Class, % Method, % Line, %
BlockHeaderBuilder 100% (1/1) 47.6% (20/42) 55.2% (58/105)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2020 RSK Labs Ltd. 4  * 5  * This program is free software: you can redistribute it and/or modify 6  * it under the terms of the GNU Lesser General Public License as published by 7  * the Free Software Foundation, either version 3 of the License, or 8  * (at your option) any later version. 9  * 10  * This program is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU Lesser General Public License for more details. 14  * 15  * You should have received a copy of the GNU Lesser General Public License 16  * along with this program. If not, see <http://www.gnu.org/licenses/>. 17  */ 18  19 package org.ethereum.core; 20  21 import co.rsk.core.BlockDifficulty; 22 import co.rsk.core.Coin; 23 import co.rsk.core.RskAddress; 24 import co.rsk.crypto.Keccak256; 25 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 26 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 27 import org.ethereum.crypto.HashUtil; 28 import org.ethereum.util.RLP; 29  30 import javax.annotation.Nullable; 31 import java.math.BigInteger; 32 import java.util.Arrays; 33  34 import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; 35  36 public class BlockHeaderBuilder { 37  38  private static final byte[] EMPTY_LIST_HASH = HashUtil.keccak256(RLP.encodeList()); 39  40  private byte[] parentHash; 41  private byte[] unclesHash; 42  private RskAddress coinbase; 43  private byte[] stateRoot; 44  private byte[] txTrieRoot; 45  private byte[] receiptTrieRoot; 46  private byte[] logsBloom; 47  private BlockDifficulty difficulty; 48  private long timestamp; 49  private long number; 50  private byte[] gasLimit; 51  private long gasUsed; 52  private Coin paidFees; 53  54  private byte[] extraData; 55  private byte[] bitcoinMergedMiningHeader; 56  private byte[] bitcoinMergedMiningMerkleProof; 57  private byte[] bitcoinMergedMiningCoinbaseTransaction; 58  private byte[] mergedMiningForkDetectionData; 59  private byte[] ummRoot; 60  61  private Coin minimumGasPrice; 62  private int uncleCount; 63  64  private boolean useRskip92Encoding; 65  private boolean includeForkDetectionData; 66  67  private final ActivationConfig activationConfig; 68  69  private boolean createConsensusCompliantHeader; 70  private boolean createUmmCompliantHeader; 71  72  public BlockHeaderBuilder(ActivationConfig activationConfig) { 73  this.activationConfig = activationConfig; 74  createConsensusCompliantHeader = true; 75  createUmmCompliantHeader = true; 76  } 77  78  public BlockHeaderBuilder setCreateConsensusCompliantHeader(boolean createConsensusCompliantHeader) { 79  this.createConsensusCompliantHeader = createConsensusCompliantHeader; 80  return this; 81  } 82  83  public BlockHeaderBuilder setCreateUmmCompliantHeader(boolean createUmmCompliantHeader) { 84  this.createUmmCompliantHeader = createUmmCompliantHeader; 85  return this; 86  } 87  88  public BlockHeaderBuilder setStateRoot(byte[] stateRoot) { 89  this.stateRoot = copy(stateRoot); 90  return this; 91  } 92  93  public BlockHeaderBuilder setDifficulty(BlockDifficulty difficulty) { 94  this.difficulty = difficulty; 95  return this; 96  } 97  98  public BlockHeaderBuilder setPaidFees(Coin paidFees) { 99  this.paidFees = paidFees; 100  return this; 101  } 102  103  public BlockHeaderBuilder setGasUsed(long gasUsed) { 104  this.gasUsed = gasUsed; 105  return this; 106  } 107  108  public BlockHeaderBuilder setLogsBloom(byte[] logsBloom) { 109  this.logsBloom = copy(logsBloom); 110  return this; 111  } 112  113  public BlockHeaderBuilder setBitcoinMergedMiningHeader(byte[] bitcoinMergedMiningHeader) { 114  this.bitcoinMergedMiningHeader = copy(bitcoinMergedMiningHeader); 115  return this; 116  } 117  118  public BlockHeaderBuilder setBitcoinMergedMiningMerkleProof(byte[] bitcoinMergedMiningMerkleProof) { 119  this.bitcoinMergedMiningMerkleProof = copy(bitcoinMergedMiningMerkleProof); 120  return this; 121  } 122  123  public BlockHeaderBuilder setBitcoinMergedMiningCoinbaseTransaction(byte[] bitcoinMergedMiningCoinbaseTransaction) { 124  this.bitcoinMergedMiningCoinbaseTransaction = copy(bitcoinMergedMiningCoinbaseTransaction); 125  return this; 126  } 127  128  public BlockHeaderBuilder setTxTrieRoot(byte[] txTrieRoot) { 129  this.txTrieRoot = copy(txTrieRoot); 130  return this; 131  } 132  133  public BlockHeaderBuilder setEmptyTxTrieRoot() { 134  this.txTrieRoot = EMPTY_TRIE_HASH; 135  return this; 136  } 137  138  public BlockHeaderBuilder setReceiptTrieRoot(byte[] receiptTrieRoot) { 139  this.receiptTrieRoot = copy(receiptTrieRoot); 140  return this; 141  } 142  143  public BlockHeaderBuilder setTimestamp(long timestamp) { 144  this.timestamp = timestamp; 145  return this; 146  } 147  148  public BlockHeaderBuilder setNumber(long number) { 149  this.number = number; 150  return this; 151  } 152  153  public BlockHeaderBuilder setGasLimit(byte[] gasLimit) { 154  this.gasLimit = copy(gasLimit); 155  return this; 156  } 157  158  public BlockHeaderBuilder setExtraData(byte[] extraData) { 159  this.extraData = copy(extraData); 160  return this; 161  } 162  163  public BlockHeaderBuilder setMergedMiningForkDetectionData(byte[] mergedMiningForkDetectionData) { 164  this.mergedMiningForkDetectionData = copy(mergedMiningForkDetectionData); 165  return this; 166  } 167  168  public BlockHeaderBuilder setMinimumGasPrice(Coin minimumGasPrice) { 169  this.minimumGasPrice = minimumGasPrice; 170  return this; 171  } 172  173  public BlockHeaderBuilder setUncleCount(int uncleCount) { 174  this.uncleCount = uncleCount; 175  return this; 176  } 177  178  public BlockHeaderBuilder setUseRskip92Encoding(boolean useRskip92Encoding) { 179  this.useRskip92Encoding = useRskip92Encoding; 180  return this; 181  } 182  183  public BlockHeaderBuilder setIncludeForkDetectionData(boolean includeForkDetectionData) { 184  this.includeForkDetectionData = includeForkDetectionData; 185  return this; 186  } 187  188  public BlockHeaderBuilder setParentHashFromKeccak256(Keccak256 parentHash) { 189  this.parentHash = copy(parentHash); 190  return this; 191  } 192  193  public BlockHeaderBuilder setParentHash(byte[] parentHash) { 194  this.parentHash = copy(parentHash); 195  return this; 196  } 197  198  public BlockHeaderBuilder setEmptyUnclesHash() { 199  this.unclesHash = EMPTY_LIST_HASH; 200  return this; 201  } 202  203  public BlockHeaderBuilder setUnclesHash(byte[] unclesHash) { 204  this.unclesHash = copy(unclesHash); 205  return this; 206  } 207  208  public BlockHeaderBuilder setCoinbase(RskAddress coinbase) { 209  this.coinbase = coinbase; 210  return this; 211  } 212  213  public BlockHeaderBuilder setDifficultyFromBytes(@Nullable byte[] data) { 214  // This is to make it compatible with RLP.parseBlockDifficulty() which was previously 215  // user (but I think it was wrongly included in the RLP class, because these arguments 216  // do not come from any RLP parsing). 217  if (data != null) { 218  difficulty = new BlockDifficulty(new BigInteger(data)); 219  } else { 220  difficulty = null; 221  } 222  return this; 223  } 224  225  public BlockHeaderBuilder setEmptyMergedMiningForkDetectionData() { 226  mergedMiningForkDetectionData = new byte[12]; 227  return this; 228  } 229  230  public BlockHeaderBuilder setEmptyExtraData() { 231  extraData = new byte[]{}; 232  return this; 233  } 234  235  public BlockHeaderBuilder setEmptyLogsBloom() { 236  logsBloom = copy(new Bloom().getData()); 237  return this; 238  } 239  240  public BlockHeaderBuilder setEmptyStateRoot() { 241  stateRoot = EMPTY_TRIE_HASH; 242  return this; 243  } 244  245  public BlockHeaderBuilder setEmptyReceiptTrieRoot() { 246  receiptTrieRoot = EMPTY_TRIE_HASH; 247  return this; 248  } 249  250  public BlockHeaderBuilder setUmmRoot(byte[] ummRoot) { 251  this.ummRoot = copy(ummRoot, null); 252  return this; 253  } 254  255  private void initializeWithDefaultValues() { 256  extraData = normalizeValue(extraData, new byte[0]); 257  bitcoinMergedMiningHeader = normalizeValue(bitcoinMergedMiningHeader, new byte[0]); 258  bitcoinMergedMiningMerkleProof = normalizeValue(bitcoinMergedMiningMerkleProof, new byte[0]); 259  bitcoinMergedMiningCoinbaseTransaction = normalizeValue(bitcoinMergedMiningCoinbaseTransaction, new byte[0]); 260  261  unclesHash = normalizeValue(unclesHash, EMPTY_LIST_HASH); 262  coinbase = normalizeValue(coinbase, RskAddress.nullAddress()); 263  stateRoot = normalizeValue(stateRoot, EMPTY_TRIE_HASH); 264  txTrieRoot = normalizeValue(txTrieRoot, EMPTY_TRIE_HASH); 265  receiptTrieRoot = normalizeValue(receiptTrieRoot, EMPTY_TRIE_HASH); 266  logsBloom = normalizeValue(logsBloom, new Bloom().getData()); 267  paidFees = normalizeValue(paidFees, Coin.ZERO); 268  minimumGasPrice = normalizeValue(minimumGasPrice, Coin.ZERO); 269  270  mergedMiningForkDetectionData = normalizeValue(mergedMiningForkDetectionData, new byte[12]); 271  } 272  273  private <T> T normalizeValue(T value, T defaultValue) { 274  return value == null ? defaultValue : value; 275  } 276  277  private byte[] copy(Keccak256 hash) { 278  return copy(hash.getBytes()); 279  } 280  281  private byte[] copy(byte[] bytes) { 282  return copy(bytes, new byte[0]); 283  } 284  285  private byte[] copy(byte[] bytes, byte[] defaultValue) { 286  if (bytes == null) { 287  return defaultValue; 288  } 289  290  return Arrays.copyOf(bytes, bytes.length); 291  } 292  293  public BlockHeader build() { 294  // Initial null values in some fields are replaced by empty 295  // arrays 296  initializeWithDefaultValues(); 297  298  if (createConsensusCompliantHeader) { 299  useRskip92Encoding = activationConfig.isActive(ConsensusRule.RSKIP92, number); 300  includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, number) && 301  mergedMiningForkDetectionData.length > 0; 302  } 303  304  if (createUmmCompliantHeader) { 305  if (activationConfig.isActive(ConsensusRule.RSKIPUMM, number)) { 306  if (ummRoot == null) { 307  ummRoot = new byte[0]; 308  } 309  } 310  } 311  312  return new BlockHeader( 313  parentHash, unclesHash, coinbase, 314  stateRoot, txTrieRoot, receiptTrieRoot, 315  logsBloom, difficulty, number, 316  gasLimit, gasUsed, timestamp, extraData, paidFees, 317  bitcoinMergedMiningHeader, 318  bitcoinMergedMiningMerkleProof, 319  bitcoinMergedMiningCoinbaseTransaction, 320  mergedMiningForkDetectionData, 321  minimumGasPrice, uncleCount, 322  false, useRskip92Encoding, 323  includeForkDetectionData, ummRoot 324  ); 325  } 326 }