Coverage Summary for Class: ForkDetectionDataCalculator (co.rsk.mine)

Class Class, % Method, % Line, %
ForkDetectionDataCalculator 0% (0/1) 0% (0/7) 0% (0/40)


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 co.rsk.mine; 20  21 import co.rsk.bitcoinj.core.Context; 22 import co.rsk.bitcoinj.core.NetworkParameters; 23 import co.rsk.bitcoinj.params.RegTestParams; 24 import co.rsk.core.types.ints.Uint8; 25 import org.ethereum.core.Block; 26 import org.ethereum.core.BlockHeader; 27  28 import java.nio.ByteBuffer; 29 import java.util.List; 30 import java.util.stream.Collectors; 31 import java.util.stream.IntStream; 32  33 public class ForkDetectionDataCalculator { 34  35  private static final int CPV_SIZE = 7; 36  37  private static final int CPV_JUMP_FACTOR = 64; 38  39  private static final int NUMBER_OF_UNCLES = 32; 40  41  // + 1 because genesis block can't be used since it does not contain a valid BTC header 42  private static final int MIN_MAINCHAIN_SIZE = CPV_SIZE * CPV_JUMP_FACTOR + 1; 43  44  private NetworkParameters params; 45  46  public ForkDetectionDataCalculator(){ 47  this.params = RegTestParams.get(); 48  new Context(params); 49  } 50  51  public byte[] calculate(List<Block> mainchainBlocks) { 52  if (mainchainBlocks.size() < MIN_MAINCHAIN_SIZE) { 53  return new byte[0]; 54  } 55  56  List<BlockHeader> mainchainBlockHeaders = mainchainBlocks 57  .stream() 58  .map(Block::getHeader) 59  .collect(Collectors.toList()); 60  61  return calculateWithBlockHeaders(mainchainBlockHeaders); 62  } 63  64  public byte[] calculateWithBlockHeaders(List<BlockHeader> mainchainBlockHeaders) { 65  if (mainchainBlockHeaders.size() < MIN_MAINCHAIN_SIZE) { 66  return new byte[0]; 67  } 68  69  byte[] forkDetectionData = new byte[12]; 70  71  byte[] commitToParentsVector = buildCommitToParentsVector(mainchainBlockHeaders); 72  System.arraycopy(commitToParentsVector, 0, forkDetectionData, 0, 7); 73  74  Uint8 numberOfUncles = getNumberOfUncles(mainchainBlockHeaders); 75  forkDetectionData[7] = numberOfUncles.asByte(); 76  77  byte[] blockBeingMinedHeight = getBlockBeingMinedHeight(mainchainBlockHeaders); 78  System.arraycopy(blockBeingMinedHeight, 0, forkDetectionData, 8, 4); 79  80  return forkDetectionData; 81  } 82  83  private byte[] buildCommitToParentsVector(List<BlockHeader> mainchainBlocks) { 84  long bestBlockHeight = mainchainBlocks.get(0).getNumber(); 85  long cpvStartHeight = (bestBlockHeight / CPV_JUMP_FACTOR) * CPV_JUMP_FACTOR; 86  87  byte[] commitToParentsVector = new byte[CPV_SIZE]; 88  for(int i = 0; i < CPV_SIZE; i++){ 89  long currentCpvElement = bestBlockHeight - cpvStartHeight + i * CPV_JUMP_FACTOR; 90  BlockHeader blockHeader = mainchainBlocks.get((int)currentCpvElement); 91  byte[] bitcoinBlock = blockHeader.getBitcoinMergedMiningHeader(); 92  93  byte[] bitcoinBlockHash = params.getDefaultSerializer().makeBlock(bitcoinBlock).getHash().getBytes(); 94  byte leastSignificantByte = bitcoinBlockHash[bitcoinBlockHash.length - 1]; 95  96  commitToParentsVector[i] = leastSignificantByte; 97  } 98  99  return commitToParentsVector; 100  } 101  102  private Uint8 getNumberOfUncles(List<BlockHeader> mainchainBlocks) { 103  int sum = IntStream 104  .range(0, NUMBER_OF_UNCLES) 105  .map(i -> mainchainBlocks.get(i).getUncleCount()).sum(); 106  107  final int maxUint = Uint8.MAX_VALUE.intValue(); 108  if (sum > maxUint) { 109  return new Uint8(maxUint); 110  } 111  112  return new Uint8(sum); 113  } 114  115  private byte[] getBlockBeingMinedHeight(List<BlockHeader> mainchainBlocks) { 116  long blockBeingMinedHeight = mainchainBlocks.get(0).getNumber() + 1; 117  return ByteBuffer.allocate(4).putInt((int)blockBeingMinedHeight).array(); 118  } 119 }