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

Class Class, % Method, % Line, %
BlockFactory 100% (1/1) 25% (3/12) 6.8% (6/88)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2019 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.config.MiningConfig; 22 import co.rsk.core.BlockDifficulty; 23 import co.rsk.core.Coin; 24 import co.rsk.core.RskAddress; 25 import co.rsk.remasc.RemascTransaction; 26 import org.bouncycastle.util.BigIntegers; 27 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 28 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 29 import org.ethereum.util.RLP; 30 import org.ethereum.util.RLPElement; 31 import org.ethereum.util.RLPList; 32  33 import java.math.BigInteger; 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.List; 37  38 import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; 39  40 public class BlockFactory { 41  private static final int RLP_HEADER_SIZE = 17; 42  private static final int RLP_HEADER_SIZE_WITH_MERGED_MINING = 20; 43  44  private final ActivationConfig activationConfig; 45  46  public BlockFactory(ActivationConfig activationConfig) { 47  this.activationConfig = activationConfig; 48  } 49  50  public BlockHeaderBuilder getBlockHeaderBuilder() { 51  return new BlockHeaderBuilder(activationConfig); 52  } 53  54  public Block cloneBlockForModification(Block block) { 55  return decodeBlock(block.getEncoded(), false); 56  } 57  58  public Block decodeBlock(byte[] rawData) { 59  return decodeBlock(rawData, true); 60  } 61  62  private Block decodeBlock(byte[] rawData, boolean sealed) { 63  RLPList block = RLP.decodeList(rawData); 64  if (block.size() != 3) { 65  throw new IllegalArgumentException("A block must have 3 exactly items"); 66  } 67  68  RLPList rlpHeader = (RLPList) block.get(0); 69  BlockHeader header = decodeHeader(rlpHeader, sealed); 70  71  List<Transaction> transactionList = parseTxs((RLPList) block.get(1)); 72  73  RLPList uncleHeadersRlp = (RLPList) block.get(2); 74  75  List<BlockHeader> uncleList = new ArrayList<>(); 76  77  for (int k = 0; k < uncleHeadersRlp.size(); k++) { 78  RLPElement element = uncleHeadersRlp.get(k); 79  BlockHeader uncleHeader = decodeHeader((RLPList)element, sealed); 80  uncleList.add(uncleHeader); 81  } 82  83  return newBlock(header, transactionList, uncleList, sealed); 84  } 85  86  public Block newBlock(BlockHeader header, List<Transaction> transactionList, List<BlockHeader> uncleList) { 87  return newBlock(header, transactionList, uncleList, true); 88  } 89  90  public Block newBlock(BlockHeader header, List<Transaction> transactionList, List<BlockHeader> uncleList, boolean sealed) { 91  boolean isRskip126Enabled = activationConfig.isActive(ConsensusRule.RSKIP126, header.getNumber()); 92  return new Block(header, transactionList, uncleList, isRskip126Enabled, sealed); 93  } 94  95  public BlockHeader decodeHeader(byte[] encoded) { 96  return decodeHeader(RLP.decodeList(encoded), true); 97  } 98  99  private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { 100  byte[] parentHash = rlpHeader.get(0).getRLPData(); 101  byte[] unclesHash = rlpHeader.get(1).getRLPData(); 102  byte[] coinBaseBytes = rlpHeader.get(2).getRLPData(); 103  RskAddress coinbase = RLP.parseRskAddress(coinBaseBytes); 104  byte[] stateRoot = rlpHeader.get(3).getRLPData(); 105  if (stateRoot == null) { 106  stateRoot = EMPTY_TRIE_HASH; 107  } 108  109  byte[] txTrieRoot = rlpHeader.get(4).getRLPData(); 110  if (txTrieRoot == null) { 111  txTrieRoot = EMPTY_TRIE_HASH; 112  } 113  114  byte[] receiptTrieRoot = rlpHeader.get(5).getRLPData(); 115  if (receiptTrieRoot == null) { 116  receiptTrieRoot = EMPTY_TRIE_HASH; 117  } 118  119  byte[] logsBloom = rlpHeader.get(6).getRLPData(); 120  byte[] difficultyBytes = rlpHeader.get(7).getRLPData(); 121  BlockDifficulty difficulty = RLP.parseBlockDifficulty(difficultyBytes); 122  123  byte[] nrBytes = rlpHeader.get(8).getRLPData(); 124  byte[] glBytes = rlpHeader.get(9).getRLPData(); 125  byte[] guBytes = rlpHeader.get(10).getRLPData(); 126  byte[] tsBytes = rlpHeader.get(11).getRLPData(); 127  128  long blockNumber = parseBigInteger(nrBytes).longValueExact(); 129  130  long gasUsed = parseBigInteger(guBytes).longValueExact(); 131  long timestamp = parseBigInteger(tsBytes).longValueExact(); 132  133  byte[] extraData = rlpHeader.get(12).getRLPData(); 134  135  Coin paidFees = RLP.parseCoin(rlpHeader.get(13).getRLPData()); 136  byte[] minimumGasPriceBytes = rlpHeader.get(14).getRLPData(); 137  Coin minimumGasPrice = RLP.parseSignedCoinNonNullZero(minimumGasPriceBytes); 138  139  if (!canBeDecoded(rlpHeader, blockNumber)) { 140  throw new IllegalArgumentException(String.format( 141  "A block header must have 16/17 elements or 19/20 including merged-mining fields but it had %d", 142  rlpHeader.size() 143  )); 144  } 145  146  int r = 15; 147  148  boolean isUmm = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber); 149  150  boolean includeUncleCount = isUmm || 151  // sizes prior to UMM activation 152  rlpHeader.size() == (RLP_HEADER_SIZE-1) || rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING-1); 153  154  int uncleCount = 0; 155  if (includeUncleCount) { 156  byte[] ucBytes = rlpHeader.get(r++).getRLPData(); 157  uncleCount = parseBigInteger(ucBytes).intValueExact(); 158  } 159  160  byte[] ummRoot = null; 161  if (isUmm) { 162  ummRoot = rlpHeader.get(r++).getRLPRawData(); 163  } 164  165  byte[] bitcoinMergedMiningHeader = null; 166  byte[] bitcoinMergedMiningMerkleProof = null; 167  byte[] bitcoinMergedMiningCoinbaseTransaction = null; 168  if (rlpHeader.size() > r) { 169  bitcoinMergedMiningHeader = rlpHeader.get(r++).getRLPData(); 170  bitcoinMergedMiningMerkleProof = rlpHeader.get(r++).getRLPRawData(); 171  bitcoinMergedMiningCoinbaseTransaction = rlpHeader.get(r++).getRLPData(); 172  } 173  174  boolean useRskip92Encoding = activationConfig.isActive(ConsensusRule.RSKIP92, blockNumber); 175  boolean includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, blockNumber) && 176  blockNumber >= MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION; 177  178  if (blockNumber == Genesis.NUMBER) { 179  return new GenesisHeader( 180  parentHash, 181  unclesHash, 182  logsBloom, 183  difficultyBytes, 184  blockNumber, 185  glBytes, 186  gasUsed, 187  timestamp, 188  extraData, 189  bitcoinMergedMiningHeader, 190  bitcoinMergedMiningMerkleProof, 191  bitcoinMergedMiningCoinbaseTransaction, 192  minimumGasPriceBytes, 193  useRskip92Encoding, 194  coinBaseBytes, 195  stateRoot); 196  } 197  198  return new BlockHeader( 199  parentHash, unclesHash, coinbase, stateRoot, 200  txTrieRoot, receiptTrieRoot, logsBloom, difficulty, 201  blockNumber, glBytes, gasUsed, timestamp, extraData, 202  paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, 203  bitcoinMergedMiningCoinbaseTransaction, new byte[0], 204  minimumGasPrice, uncleCount, sealed, useRskip92Encoding, includeForkDetectionData, 205  ummRoot 206  ); 207  } 208  209  private boolean canBeDecoded(RLPList rlpHeader, long blockNumber) { 210  int preUmmHeaderSizeAdjustment = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber) ? 0 : 1; 211  212  return rlpHeader.size() == (RLP_HEADER_SIZE - preUmmHeaderSizeAdjustment) || 213  rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING - preUmmHeaderSizeAdjustment); 214  } 215  216  private static BigInteger parseBigInteger(byte[] bytes) { 217  return bytes == null ? BigInteger.ZERO : BigIntegers.fromUnsignedByteArray(bytes); 218  } 219  220  private static List<Transaction> parseTxs(RLPList txTransactions) { 221  List<Transaction> parsedTxs = new ArrayList<>(); 222  223  for (int i = 0; i < txTransactions.size(); i++) { 224  RLPElement transactionRaw = txTransactions.get(i); 225  Transaction tx = new ImmutableTransaction(transactionRaw.getRLPData()); 226  227  if (tx.isRemascTransaction(i, txTransactions.size())) { 228  // It is the remasc transaction 229  tx = new RemascTransaction(transactionRaw.getRLPData()); 230  } 231  parsedTxs.add(tx); 232  } 233  234  return Collections.unmodifiableList(parsedTxs); 235  } 236 }