[NC-1711] Ommer blocks should be considered valid even when they are from the future (#92)

* eliminate black for relevant tests

* partition TimestampValidationRule

* adapt existing tests

* further adaptions of status quo

* create creator

* adding ommer validator

* resolving builder sequence

* remove blank lines, fix comment

* rename classes

* remove unnecessary blank lines
S. Matthew English 6 years ago committed by GitHub
parent ee6186815b
commit ef50390398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/BlockHeaderValidationRulesetFactory.java
  2. 1
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecs.java
  3. 6
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java
  4. 1
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSpecs.java
  5. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockBodyValidator.java
  6. 19
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidator.java
  7. 1
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java
  8. 14
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpec.java
  9. 13
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java
  10. 58
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java
  11. 35
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java
  12. 36
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java
  13. 4
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/BlockchainReferenceTestTools.java
  14. 2
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java

@ -25,7 +25,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.AncestryVali
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent;
public class BlockHeaderValidationRulesetFactory { public class BlockHeaderValidationRulesetFactory {
@ -46,7 +47,8 @@ public class BlockHeaderValidationRulesetFactory {
.addRule(new AncestryValidationRule()) .addRule(new AncestryValidationRule())
.addRule(new GasUsageValidationRule()) .addRule(new GasUsageValidationRule())
.addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL)) .addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL))
.addRule(new TimestampValidationRule(10, secondsBetweenBlocks)) .addRule(new TimestampBoundedByFutureParameter(10))
.addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks))
.addRule(new ConstantFieldValidationRule<>("MixHash", BlockHeader::getMixHash, Hash.ZERO)) .addRule(new ConstantFieldValidationRule<>("MixHash", BlockHeader::getMixHash, Hash.ZERO))
.addRule( .addRule(
new ConstantFieldValidationRule<>( new ConstantFieldValidationRule<>(

@ -71,6 +71,7 @@ public class CliqueProtocolSpecs {
final EpochManager epochManager = new EpochManager(epochLength); final EpochManager epochManager = new EpochManager(epochLength);
return specBuilder return specBuilder
.<CliqueContext>changeConsensusContextType( .<CliqueContext>changeConsensusContextType(
difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager),
difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager),
MainnetBlockBodyValidator::new, MainnetBlockBodyValidator::new,
MainnetBlockImporter::new, MainnetBlockImporter::new,

@ -21,7 +21,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.AncestryVali
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
public class IbftBlockHeaderValidationRulesetFactory { public class IbftBlockHeaderValidationRulesetFactory {
@ -56,7 +57,8 @@ public class IbftBlockHeaderValidationRulesetFactory {
.addRule(new AncestryValidationRule()) .addRule(new AncestryValidationRule())
.addRule(new GasUsageValidationRule()) .addRule(new GasUsageValidationRule())
.addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL)) .addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL))
.addRule(new TimestampValidationRule(1, secondsBetweenBlocks)) .addRule(new TimestampBoundedByFutureParameter(1))
.addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks))
.addRule( .addRule(
new ConstantFieldValidationRule<>( new ConstantFieldValidationRule<>(
"MixHash", BlockHeader::getMixHash, IbftHelpers.EXPECTED_MIX_HASH)) "MixHash", BlockHeader::getMixHash, IbftHelpers.EXPECTED_MIX_HASH))

@ -44,6 +44,7 @@ public class IbftProtocolSpecs {
final EpochManager epochManager = new EpochManager(epochLength); final EpochManager epochManager = new EpochManager(epochLength);
return MainnetProtocolSpecs.spuriousDragonDefinition(chainId) return MainnetProtocolSpecs.spuriousDragonDefinition(chainId)
.<IbftContext>changeConsensusContextType( .<IbftContext>changeConsensusContextType(
difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks),
difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks),
MainnetBlockBodyValidator::new, MainnetBlockBodyValidator::new,
(blockHeaderValidator, blockBodyValidator, blockProcessor) -> (blockHeaderValidator, blockBodyValidator, blockProcessor) ->

@ -219,7 +219,7 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
final HeaderValidationMode ommerValidationMode) { final HeaderValidationMode ommerValidationMode) {
final ProtocolSpec<C> protocolSpec = protocolSchedule.getByBlockNumber(ommer.getNumber()); final ProtocolSpec<C> protocolSpec = protocolSchedule.getByBlockNumber(ommer.getNumber());
if (!protocolSpec if (!protocolSpec
.getBlockHeaderValidator() .getOmmerHeaderValidator()
.validateHeader(ommer, context, ommerValidationMode)) { .validateHeader(ommer, context, ommerValidationMode)) {
return false; return false;
} }

@ -20,7 +20,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ExtraDataMax
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.GasUsageValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ProofOfWorkValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.ProofOfWorkValidationRule;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter;
import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
public final class MainnetBlockHeaderValidator { public final class MainnetBlockHeaderValidator {
@ -46,6 +47,19 @@ public final class MainnetBlockHeaderValidator {
.build(); .build();
} }
static BlockHeaderValidator<Void> createOmmerValidator(
final DifficultyCalculator<Void> difficultyCalculator) {
return new BlockHeaderValidator.Builder<Void>()
.addRule(new CalculatedDifficultyValidationRule<>(difficultyCalculator))
.addRule(new AncestryValidationRule())
.addRule(new GasLimitRangeAndDeltaValidationRule(MIN_GAS_LIMIT, MAX_GAS_LIMIT))
.addRule(new GasUsageValidationRule())
.addRule(new TimestampMoreRecentThanParent(MINIMUM_SECONDS_SINCE_PARENT))
.addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES))
.addRule(new ProofOfWorkValidationRule())
.build();
}
private static BlockHeaderValidator.Builder<Void> createValidator( private static BlockHeaderValidator.Builder<Void> createValidator(
final DifficultyCalculator<Void> difficultyCalculator) { final DifficultyCalculator<Void> difficultyCalculator) {
return new BlockHeaderValidator.Builder<Void>() return new BlockHeaderValidator.Builder<Void>()
@ -53,7 +67,8 @@ public final class MainnetBlockHeaderValidator {
.addRule(new AncestryValidationRule()) .addRule(new AncestryValidationRule())
.addRule(new GasLimitRangeAndDeltaValidationRule(MIN_GAS_LIMIT, MAX_GAS_LIMIT)) .addRule(new GasLimitRangeAndDeltaValidationRule(MIN_GAS_LIMIT, MAX_GAS_LIMIT))
.addRule(new GasUsageValidationRule()) .addRule(new GasUsageValidationRule())
.addRule(new TimestampValidationRule(TIMESTAMP_TOLERANCE_S, MINIMUM_SECONDS_SINCE_PARENT)) .addRule(new TimestampMoreRecentThanParent(MINIMUM_SECONDS_SINCE_PARENT))
.addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S))
.addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES))
.addRule(new ProofOfWorkValidationRule()); .addRule(new ProofOfWorkValidationRule());
} }

@ -82,6 +82,7 @@ public abstract class MainnetProtocolSpecs {
false)) false))
.difficultyCalculator(MainnetDifficultyCalculators.FRONTIER) .difficultyCalculator(MainnetDifficultyCalculators.FRONTIER)
.blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::create) .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::create)
.ommerHeaderValidatorBuilder(MainnetBlockHeaderValidator::createOmmerValidator)
.blockBodyValidatorBuilder(MainnetBlockBodyValidator::new) .blockBodyValidatorBuilder(MainnetBlockBodyValidator::new)
.transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory) .transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory)
.blockReward(FRONTIER_BLOCK_REWARD) .blockReward(FRONTIER_BLOCK_REWARD)

@ -30,6 +30,8 @@ public class ProtocolSpec<C> {
private final BlockHeaderValidator<C> blockHeaderValidator; private final BlockHeaderValidator<C> blockHeaderValidator;
private final BlockHeaderValidator<C> ommerHeaderValidator;
private final BlockBodyValidator<C> blockBodyValidator; private final BlockBodyValidator<C> blockBodyValidator;
private final BlockImporter<C> blockImporter; private final BlockImporter<C> blockImporter;
@ -54,6 +56,7 @@ public class ProtocolSpec<C> {
* @param transactionValidator the transaction validator to use * @param transactionValidator the transaction validator to use
* @param transactionProcessor the transaction processor to use * @param transactionProcessor the transaction processor to use
* @param blockHeaderValidator the block header validator to use * @param blockHeaderValidator the block header validator to use
* @param ommerHeaderValidator the rules used to validate an ommer
* @param blockBodyValidator the block body validator to use * @param blockBodyValidator the block body validator to use
* @param blockProcessor the block processor to use * @param blockProcessor the block processor to use
* @param blockImporter the block importer to use * @param blockImporter the block importer to use
@ -70,6 +73,7 @@ public class ProtocolSpec<C> {
final TransactionValidator transactionValidator, final TransactionValidator transactionValidator,
final TransactionProcessor transactionProcessor, final TransactionProcessor transactionProcessor,
final BlockHeaderValidator<C> blockHeaderValidator, final BlockHeaderValidator<C> blockHeaderValidator,
final BlockHeaderValidator<C> ommerHeaderValidator,
final BlockBodyValidator<C> blockBodyValidator, final BlockBodyValidator<C> blockBodyValidator,
final BlockProcessor blockProcessor, final BlockProcessor blockProcessor,
final BlockImporter<C> blockImporter, final BlockImporter<C> blockImporter,
@ -84,6 +88,7 @@ public class ProtocolSpec<C> {
this.transactionValidator = transactionValidator; this.transactionValidator = transactionValidator;
this.transactionProcessor = transactionProcessor; this.transactionProcessor = transactionProcessor;
this.blockHeaderValidator = blockHeaderValidator; this.blockHeaderValidator = blockHeaderValidator;
this.ommerHeaderValidator = ommerHeaderValidator;
this.blockBodyValidator = blockBodyValidator; this.blockBodyValidator = blockBodyValidator;
this.blockProcessor = blockProcessor; this.blockProcessor = blockProcessor;
this.blockImporter = blockImporter; this.blockImporter = blockImporter;
@ -148,6 +153,15 @@ public class ProtocolSpec<C> {
return blockHeaderValidator; return blockHeaderValidator;
} }
/**
* Returns the block ommer header validator used in this specification.
*
* @return the block ommer header validator
*/
public BlockHeaderValidator<C> getOmmerHeaderValidator() {
return ommerHeaderValidator;
}
/** /**
* Returns the block body validator used in this specification. * Returns the block body validator used in this specification.
* *

@ -34,6 +34,7 @@ public class ProtocolSpecBuilder<T> {
private Function<GasCalculator, EVM> evmBuilder; private Function<GasCalculator, EVM> evmBuilder;
private Function<GasCalculator, TransactionValidator> transactionValidatorBuilder; private Function<GasCalculator, TransactionValidator> transactionValidatorBuilder;
private Function<DifficultyCalculator<T>, BlockHeaderValidator<T>> blockHeaderValidatorBuilder; private Function<DifficultyCalculator<T>, BlockHeaderValidator<T>> blockHeaderValidatorBuilder;
private Function<DifficultyCalculator<T>, BlockHeaderValidator<T>> ommerHeaderValidatorBuilder;
private Function<ProtocolSchedule<T>, BlockBodyValidator<T>> blockBodyValidatorBuilder; private Function<ProtocolSchedule<T>, BlockBodyValidator<T>> blockBodyValidatorBuilder;
private BiFunction<GasCalculator, EVM, AbstractMessageProcessor> contractCreationProcessorBuilder; private BiFunction<GasCalculator, EVM, AbstractMessageProcessor> contractCreationProcessorBuilder;
private Function<GasCalculator, PrecompileContractRegistry> precompileContractRegistryBuilder; private Function<GasCalculator, PrecompileContractRegistry> precompileContractRegistryBuilder;
@ -91,6 +92,13 @@ public class ProtocolSpecBuilder<T> {
return this; return this;
} }
public ProtocolSpecBuilder<T> ommerHeaderValidatorBuilder(
final Function<DifficultyCalculator<T>, BlockHeaderValidator<T>>
ommerHeaderValidatorBuilder) {
this.ommerHeaderValidatorBuilder = ommerHeaderValidatorBuilder;
return this;
}
public ProtocolSpecBuilder<T> blockBodyValidatorBuilder( public ProtocolSpecBuilder<T> blockBodyValidatorBuilder(
final Function<ProtocolSchedule<T>, BlockBodyValidator<T>> blockBodyValidatorBuilder) { final Function<ProtocolSchedule<T>, BlockBodyValidator<T>> blockBodyValidatorBuilder) {
this.blockBodyValidatorBuilder = blockBodyValidatorBuilder; this.blockBodyValidatorBuilder = blockBodyValidatorBuilder;
@ -154,6 +162,7 @@ public class ProtocolSpecBuilder<T> {
public <R> ProtocolSpecBuilder<R> changeConsensusContextType( public <R> ProtocolSpecBuilder<R> changeConsensusContextType(
final Function<DifficultyCalculator<R>, BlockHeaderValidator<R>> blockHeaderValidatorBuilder, final Function<DifficultyCalculator<R>, BlockHeaderValidator<R>> blockHeaderValidatorBuilder,
final Function<DifficultyCalculator<R>, BlockHeaderValidator<R>> ommerHeaderValidatorBuilder,
final Function<ProtocolSchedule<R>, BlockBodyValidator<R>> blockBodyValidatorBuilder, final Function<ProtocolSchedule<R>, BlockBodyValidator<R>> blockBodyValidatorBuilder,
final BlockImporterBuilder<R> blockImporterBuilder, final BlockImporterBuilder<R> blockImporterBuilder,
final DifficultyCalculator<R> difficultyCalculator) { final DifficultyCalculator<R> difficultyCalculator) {
@ -166,6 +175,7 @@ public class ProtocolSpecBuilder<T> {
.messageCallProcessorBuilder(messageCallProcessorBuilder) .messageCallProcessorBuilder(messageCallProcessorBuilder)
.transactionProcessorBuilder(transactionProcessorBuilder) .transactionProcessorBuilder(transactionProcessorBuilder)
.blockHeaderValidatorBuilder(blockHeaderValidatorBuilder) .blockHeaderValidatorBuilder(blockHeaderValidatorBuilder)
.ommerHeaderValidatorBuilder(ommerHeaderValidatorBuilder)
.blockBodyValidatorBuilder(blockBodyValidatorBuilder) .blockBodyValidatorBuilder(blockBodyValidatorBuilder)
.blockProcessorBuilder(blockProcessorBuilder) .blockProcessorBuilder(blockProcessorBuilder)
.blockImporterBuilder(blockImporterBuilder) .blockImporterBuilder(blockImporterBuilder)
@ -214,6 +224,8 @@ public class ProtocolSpecBuilder<T> {
gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor); gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor);
final BlockHeaderValidator<T> blockHeaderValidator = final BlockHeaderValidator<T> blockHeaderValidator =
blockHeaderValidatorBuilder.apply(difficultyCalculator); blockHeaderValidatorBuilder.apply(difficultyCalculator);
final BlockHeaderValidator<T> ommerHeaderValidator =
ommerHeaderValidatorBuilder.apply(difficultyCalculator);
final BlockBodyValidator<T> blockBodyValidator = final BlockBodyValidator<T> blockBodyValidator =
blockBodyValidatorBuilder.apply(protocolSchedule); blockBodyValidatorBuilder.apply(protocolSchedule);
final BlockProcessor blockProcessor = final BlockProcessor blockProcessor =
@ -230,6 +242,7 @@ public class ProtocolSpecBuilder<T> {
transactionValidator, transactionValidator,
transactionProcessor, transactionProcessor,
blockHeaderValidator, blockHeaderValidator,
ommerHeaderValidator,
blockBodyValidator, blockBodyValidator,
blockProcessor, blockProcessor,
blockImporter, blockImporter,

@ -0,0 +1,58 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.DetachedBlockHeaderValidationRule;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Responsible for ensuring the timestamp of a block is not more than "acceptableClockDriftSeconds'
* into the future.
*/
public class TimestampBoundedByFutureParameter implements DetachedBlockHeaderValidationRule {
private final Logger LOG = LogManager.getLogger();
private final long acceptableClockDriftSeconds;
public TimestampBoundedByFutureParameter(final long acceptableClockDriftSeconds) {
this.acceptableClockDriftSeconds = acceptableClockDriftSeconds;
}
@Override
public boolean validate(final BlockHeader header, final BlockHeader parent) {
return validateTimestamp(header.getTimestamp());
}
private boolean validateTimestamp(final long timestamp) {
return validateHeaderNotAheadOfCurrentSystemTime(timestamp);
}
private boolean validateHeaderNotAheadOfCurrentSystemTime(final long timestamp) {
final long timestampMargin =
TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
+ acceptableClockDriftSeconds;
if (Long.compareUnsigned(timestamp, timestampMargin) > 0) {
LOG.trace(
"Invalid block header: timestamp {} is greater than the timestamp margin {}",
timestamp,
timestampMargin);
return false;
}
return true;
}
}

@ -17,25 +17,17 @@ import static com.google.common.base.Preconditions.checkArgument;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.DetachedBlockHeaderValidationRule; import tech.pegasys.pantheon.ethereum.mainnet.DetachedBlockHeaderValidationRule;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
/** /** Responsible for ensuring the timestamp of a block is newer than its parent. */
* Responsible for ensuring the timestamp of a block is newer than its parent, but also that it has public class TimestampMoreRecentThanParent implements DetachedBlockHeaderValidationRule {
* a timestamp not more than "acceptableClockDriftSeconds' into the future.
*/
public class TimestampValidationRule implements DetachedBlockHeaderValidationRule {
private final Logger LOG = LogManager.getLogger(TimestampValidationRule.class); private final Logger LOG = LogManager.getLogger();
private final long acceptableClockDriftSeconds;
private final long minimumSecondsSinceParent; private final long minimumSecondsSinceParent;
public TimestampValidationRule( public TimestampMoreRecentThanParent(final long minimumSecondsSinceParent) {
final long acceptableClockDriftSeconds, final long minimumSecondsSinceParent) {
checkArgument(minimumSecondsSinceParent >= 0, "minimumSecondsSinceParent must be positive"); checkArgument(minimumSecondsSinceParent >= 0, "minimumSecondsSinceParent must be positive");
this.acceptableClockDriftSeconds = acceptableClockDriftSeconds;
this.minimumSecondsSinceParent = minimumSecondsSinceParent; this.minimumSecondsSinceParent = minimumSecondsSinceParent;
} }
@ -45,10 +37,7 @@ public class TimestampValidationRule implements DetachedBlockHeaderValidationRul
} }
private boolean validateTimestamp(final long timestamp, final long parentTimestamp) { private boolean validateTimestamp(final long timestamp, final long parentTimestamp) {
boolean result = validateHeaderSufficientlyAheadOfParent(timestamp, parentTimestamp); return validateHeaderSufficientlyAheadOfParent(timestamp, parentTimestamp);
result &= validateHeaderNotAheadOfCurrentSystemTime(timestamp);
return result;
} }
private boolean validateHeaderSufficientlyAheadOfParent( private boolean validateHeaderSufficientlyAheadOfParent(
@ -63,18 +52,4 @@ public class TimestampValidationRule implements DetachedBlockHeaderValidationRul
return true; return true;
} }
private boolean validateHeaderNotAheadOfCurrentSystemTime(final long timestamp) {
final long timestampMargin =
TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
+ acceptableClockDriftSeconds;
if (Long.compareUnsigned(timestamp, timestampMargin) > 0) {
LOG.trace(
"Invalid block header: timestamp {} is greater than the timestamp margin {}",
timestamp,
timestampMargin);
return false;
}
return true;
}
} }

@ -26,7 +26,8 @@ public class TimestampValidationRuleTest {
@Test @Test
public void headerTimestampSufficientlyFarIntoFutureVadidatesSuccessfully() { public void headerTimestampSufficientlyFarIntoFutureVadidatesSuccessfully() {
final TimestampValidationRule uut = new TimestampValidationRule(0, 10); final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0);
final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10);
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@ -37,18 +38,20 @@ public class TimestampValidationRuleTest {
headerBuilder.timestamp(parent.getTimestamp() + 11); headerBuilder.timestamp(parent.getTimestamp() + 11);
final BlockHeader header = headerBuilder.buildHeader(); final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut.validate(header, parent)).isTrue(); assertThat(uut00.validate(header, parent)).isTrue();
assertThat(uut01.validate(header, parent)).isTrue();
} }
@Test @Test
public void headerTimestampDifferenceMustBePositive() { public void headerTimestampDifferenceMustBePositive() {
Assertions.assertThatThrownBy(() -> new TimestampValidationRule(0, -1)) Assertions.assertThatThrownBy(() -> new TimestampMoreRecentThanParent(-1))
.hasMessage("minimumSecondsSinceParent must be positive"); .hasMessage("minimumSecondsSinceParent must be positive");
} }
@Test @Test
public void headerTimestampTooCloseToParentFailsValidation() { public void headerTimestampTooCloseToParentFailsValidation() {
final TimestampValidationRule uut = new TimestampValidationRule(0, 10); final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0);
final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10);
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@ -59,12 +62,14 @@ public class TimestampValidationRuleTest {
headerBuilder.timestamp(parent.getTimestamp() + 1); headerBuilder.timestamp(parent.getTimestamp() + 1);
final BlockHeader header = headerBuilder.buildHeader(); final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut.validate(header, parent)).isFalse(); assertThat(uut00.validate(header, parent)).isTrue();
assertThat(uut01.validate(header, parent)).isFalse();
} }
@Test @Test
public void headerTimestampIsBehindParentFailsValidation() { public void headerTimestampIsBehindParentFailsValidation() {
final TimestampValidationRule uut = new TimestampValidationRule(0, 10); final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0);
final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10);
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@ -75,13 +80,17 @@ public class TimestampValidationRuleTest {
headerBuilder.timestamp(parent.getTimestamp() - 11); headerBuilder.timestamp(parent.getTimestamp() - 11);
final BlockHeader header = headerBuilder.buildHeader(); final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut.validate(header, parent)).isFalse(); assertThat(uut00.validate(header, parent)).isTrue();
assertThat(uut01.validate(header, parent)).isFalse();
} }
@Test @Test
public void headerNewerThanCurrentSystemFailsValidation() { public void headerNewerThanCurrentSystemFailsValidation() {
final long acceptableClockDrift = 5; final long acceptableClockDrift = 5;
final TimestampValidationRule uut = new TimestampValidationRule(acceptableClockDrift, 10);
final TimestampBoundedByFutureParameter uut00 =
new TimestampBoundedByFutureParameter(acceptableClockDrift);
final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10);
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@ -94,13 +103,17 @@ public class TimestampValidationRuleTest {
headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift + 1); headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift + 1);
final BlockHeader header = headerBuilder.buildHeader(); final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut.validate(header, parent)).isFalse(); assertThat(uut00.validate(header, parent)).isFalse();
assertThat(uut01.validate(header, parent)).isFalse();
} }
@Test @Test
public void futureHeadersAreValidIfTimestampWithinTolerance() { public void futureHeadersAreValidIfTimestampWithinTolerance() {
final long acceptableClockDrift = 5; final long acceptableClockDrift = 5;
final TimestampValidationRule uut = new TimestampValidationRule(acceptableClockDrift, 10);
final TimestampBoundedByFutureParameter uut00 =
new TimestampBoundedByFutureParameter(acceptableClockDrift);
final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10);
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@ -114,6 +127,7 @@ public class TimestampValidationRuleTest {
headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift - 1); headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift - 1);
final BlockHeader header = headerBuilder.buildHeader(); final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut.validate(header, parent)).isFalse(); assertThat(uut00.validate(header, parent)).isTrue();
assertThat(uut01.validate(header, parent)).isFalse();
} }
} }

@ -66,10 +66,6 @@ public class BlockchainReferenceTestTools {
// Consumes a huge amount of memory // Consumes a huge amount of memory
params.blacklist("static_Call1MB1024Calldepth_d1g0v0_(Byzantium|Constantinople)"); params.blacklist("static_Call1MB1024Calldepth_d1g0v0_(Byzantium|Constantinople)");
// Pantheon is incorrectly rejecting Uncle block timestamps in the future
params.blacklist("futureUncleTimestampDifficultyDrop2");
params.blacklist("futureUncleTimestampDifficultyDrop");
// Needs investigation // Needs investigation
params.blacklist("RevertInCreateInInit_d0g0v0_Byzantium"); params.blacklist("RevertInCreateInInit_d0g0v0_Byzantium");
params.blacklist("RevertInCreateInInit_d0g0v0_Constantinople"); params.blacklist("RevertInCreateInInit_d0g0v0_Constantinople");

@ -88,6 +88,7 @@ public class EthGetTransactionReceiptTest {
null, null,
null, null,
null, null,
null,
TransactionReceiptType.ROOT, TransactionReceiptType.ROOT,
BlockHeader::getCoinbase); BlockHeader::getCoinbase);
private final ProtocolSpec<Void> statusTransactionTypeSpec = private final ProtocolSpec<Void> statusTransactionTypeSpec =
@ -104,6 +105,7 @@ public class EthGetTransactionReceiptTest {
null, null,
null, null,
null, null,
null,
TransactionReceiptType.STATUS, TransactionReceiptType.STATUS,
BlockHeader::getCoinbase); BlockHeader::getCoinbase);

Loading…
Cancel
Save