Coverage Summary for Class: BlockTimeStampValidationRule (co.rsk.validators)

Class Class, % Method, % Line, %
BlockTimeStampValidationRule 0% (0/1) 0% (0/10) 0% (0/47)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 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.validators; 20  21 import co.rsk.bitcoinj.core.BtcBlock; 22 import co.rsk.bitcoinj.core.NetworkParameters; 23 import co.rsk.bitcoinj.params.RegTestParams; 24 import co.rsk.util.TimeProvider; 25 import org.ethereum.config.Constants; 26 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 27 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 28 import org.ethereum.core.Block; 29 import org.ethereum.core.BlockHeader; 30 import org.slf4j.Logger; 31 import org.slf4j.LoggerFactory; 32  33 import javax.annotation.Nonnull; 34 import javax.annotation.Nullable; 35 import java.util.Objects; 36  37 /** 38  * Created by mario on 23/01/17. 39  */ 40 public class BlockTimeStampValidationRule implements BlockParentDependantValidationRule, BlockHeaderParentDependantValidationRule, BlockValidationRule, BlockHeaderValidationRule { 41  42  private static final Logger logger = LoggerFactory.getLogger("blockvalidator"); 43  44  private static final long MAX_TIMESTAMPS_DIFF_IN_SECS = Constants.getMaxTimestampsDiffInSecs(); 45  46  private final int validPeriodLength; 47  private final ActivationConfig activationConfig; 48  private final TimeProvider timeProvider; 49  private final NetworkParameters bitcoinNetworkParameters; 50  51  public BlockTimeStampValidationRule(int validPeriodLength, ActivationConfig activationConfig, 52  TimeProvider timeProvider, NetworkParameters bitcoinNetworkParameters) { 53  this.validPeriodLength = validPeriodLength; 54  this.activationConfig = Objects.requireNonNull(activationConfig); 55  this.timeProvider = Objects.requireNonNull(timeProvider); 56  this.bitcoinNetworkParameters = Objects.requireNonNull(bitcoinNetworkParameters); 57  } 58  59  public BlockTimeStampValidationRule(int validPeriodLength, ActivationConfig activationConfig, TimeProvider timeProvider) { 60  this(validPeriodLength, activationConfig, timeProvider, RegTestParams.get()); 61  } 62  63  public BlockTimeStampValidationRule(int validPeriodLength, ActivationConfig activationConfig) { 64  this(validPeriodLength, activationConfig, System::currentTimeMillis, RegTestParams.get()); 65  } 66  67  @Override 68  public boolean isValid(Block block) { 69  return isValid(block.getHeader()); 70  } 71  72  @Override 73  public boolean isValid(BlockHeader header) { 74  if (this.validPeriodLength == 0) { 75  return true; 76  } 77  78  final long currentTime = timeProvider.currentTimeMillis() / 1000L; 79  final long blockTime = header.getTimestamp(); 80  81  boolean result = blockTime - currentTime <= this.validPeriodLength; 82  83  if (!result) { 84  logger.warn("Error validating block. Invalid timestamp {}.", blockTime); 85  } 86  87  return result && isBitcoinTimestampValid(header); 88  } 89  90  @Override 91  public boolean isValid(BlockHeader header, Block parent) { 92  if (this.validPeriodLength == 0) { 93  return true; 94  } 95  96  boolean result = this.isValid(header); 97  98  final long blockTime = header.getTimestamp(); 99  final long parentTime = parent.getTimestamp(); 100  result = result && (blockTime > parentTime); 101  102  if (!result) { 103  logger.warn("Error validating block. Invalid timestamp {} for parent timestamp {}", blockTime, parentTime); 104  } 105  106  return result; 107  } 108  109  @Override 110  public boolean isValid(Block block, Block parent) { 111  return isValid(block.getHeader(), parent); 112  } 113  114  private boolean isBitcoinTimestampValid(BlockHeader header) { 115  if (!activationConfig.isActive(ConsensusRule.RSKIP179, header.getNumber())) { 116  return true; 117  } 118  119  byte[] bitcoinMergedMiningHeader = header.getBitcoinMergedMiningHeader(); 120  if (bitcoinMergedMiningHeader == null) { 121  return false; 122  } 123  124  BtcBlock btcBlock = makeBlock(bitcoinMergedMiningHeader); 125  if (btcBlock == null) { 126  return false; 127  } 128  129  long bitcoinTimestampInSecs = btcBlock.getTimeSeconds(); 130  131  long rskTimestampInSecs = header.getTimestamp(); 132  133  boolean valid = Math.abs(bitcoinTimestampInSecs - rskTimestampInSecs) < MAX_TIMESTAMPS_DIFF_IN_SECS; 134  135  if (!valid) { 136  logger.warn("Error validating block. RSK block timestamp {} and BTC block timestamp {} differ by more than {} secs.", 137  rskTimestampInSecs, bitcoinTimestampInSecs, MAX_TIMESTAMPS_DIFF_IN_SECS); 138  } 139  140  return valid; 141  } 142  143  @Nullable 144  private BtcBlock makeBlock(@Nonnull byte[] bitcoinMergedMiningHeader) { 145  try { 146  return bitcoinNetworkParameters.getDefaultSerializer().makeBlock(bitcoinMergedMiningHeader); 147  } catch (RuntimeException e) { 148  logger.error("Cannot make a BTC block from `{}`", bitcoinMergedMiningHeader, e); 149  return null; 150  } 151  } 152 }