Skip to content

Commit

Permalink
Qbft validation selection was incorrectly being applied for non valid…
Browse files Browse the repository at this point in the history
…ator selection mode transitions

Signed-off-by: Jason Frame <jasonwframe@gmail.com>
  • Loading branch information
jframe committed Oct 12, 2021
1 parent a30c314 commit 772a428
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ public void ensureBlockRewardAndMiningBeneficiaryInProtocolSpecMatchConfig() {
final ProtocolSchedule schedule = createProtocolSchedule();
final ProtocolSpec spec = schedule.getByBlockNumber(1);

spec.getBlockReward();

assertThat(spec.getBlockReward()).isEqualTo(Wei.of(arbitraryBlockReward));
assertThat(spec.getMiningBeneficiaryCalculator().calculateBeneficiary(null))
.isEqualTo(Address.fromHexString(miningBeneficiary));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,8 @@ protected Supplier<BlockHeaderValidator.Builder> createForkBlockHeaderRuleset(
return () ->
QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(
config.getBftConfigOptions().getBlockPeriodSeconds(),
qbftFork
.getValidatorSelectionMode()
.filter(m -> m == VALIDATOR_SELECTION_MODE.CONTRACT)
.isPresent());
qbftFork.getValidatorSelectionMode().stream()
.allMatch(m -> m == VALIDATOR_SELECTION_MODE.CONTRACT));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package org.hyperledger.besu.consensus.qbft;

import static java.util.Collections.singletonList;

import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataFixture;
import org.hyperledger.besu.consensus.common.bft.Vote;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.Util;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;

public class QbftBlockHeaderUtils {

@FunctionalInterface
public interface HeaderModifier {

void update(BlockHeaderTestFixture blockHeaderTestFixture);
}

public static BlockHeaderTestFixture createPresetHeaderBuilder(
final long number,
final NodeKey proposerNodeKey,
final List<Address> validators,
final BlockHeader parent) {
return createPresetHeaderBuilder(number, proposerNodeKey, validators, parent, null);
}

public static BlockHeaderTestFixture createPresetHeaderBuilderForContractMode(
final long number,
final NodeKey proposerNodeKey,
final BlockHeader parent,
final HeaderModifier modifier) {
final BlockHeaderTestFixture builder = new BlockHeaderTestFixture();
final QbftExtraDataCodec qbftExtraDataEncoder = new QbftExtraDataCodec();
populateDefaultBlockHeader(
number, proposerNodeKey, parent, modifier, builder, qbftExtraDataEncoder);

final BftExtraData bftExtraData =
BftExtraDataFixture.createExtraData(
builder.buildHeader(),
Bytes.wrap(new byte[BftExtraDataCodec.EXTRA_VANITY_LENGTH]),
Optional.empty(),
Collections.emptyList(),
singletonList(proposerNodeKey),
0x2A,
qbftExtraDataEncoder);

builder.extraData(qbftExtraDataEncoder.encode(bftExtraData));
return builder;
}

public static BlockHeaderTestFixture createPresetHeaderBuilder(
final long number,
final NodeKey proposerNodeKey,
final List<Address> validators,
final BlockHeader parent,
final HeaderModifier modifier) {
final BlockHeaderTestFixture builder = new BlockHeaderTestFixture();
final QbftExtraDataCodec qbftExtraDataEncoder = new QbftExtraDataCodec();
populateDefaultBlockHeader(
number, proposerNodeKey, parent, modifier, builder, qbftExtraDataEncoder);

final BftExtraData bftExtraData =
BftExtraDataFixture.createExtraData(
builder.buildHeader(),
Bytes.wrap(new byte[BftExtraDataCodec.EXTRA_VANITY_LENGTH]),
Optional.of(Vote.authVote(Address.fromHexString("1"))),
validators,
singletonList(proposerNodeKey),
0x2A,
qbftExtraDataEncoder);

builder.extraData(qbftExtraDataEncoder.encode(bftExtraData));
return builder;
}

private static void populateDefaultBlockHeader(
final long number,
final NodeKey proposerNodeKey,
final BlockHeader parent,
final HeaderModifier modifier,
final BlockHeaderTestFixture builder,
final QbftExtraDataCodec qbftExtraDataEncoder) {
if (parent != null) {
builder.parentHash(parent.getHash());
}
builder.number(number);
builder.gasLimit(5000);
builder.timestamp(6000 * number);
builder.mixHash(
Hash.fromHexString("0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365"));
builder.difficulty(Difficulty.ONE);
builder.coinbase(Util.publicKeyToAddress(proposerNodeKey.getPublicKey()));
builder.blockHeaderFunctions(BftBlockHeaderFunctions.forCommittedSeal(qbftExtraDataEncoder));

if (modifier != null) {
modifier.update(builder);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,20 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.consensus.common.bft.BftContextBuilder.setupContextWithBftExtraDataEncoder;

import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataFixture;
import org.hyperledger.besu.consensus.common.bft.Vote;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;
import org.junit.Test;

public class QbftBlockHeaderValidationRulesetFactoryTest {
Expand All @@ -61,9 +53,11 @@ public void bftValidateHeaderPasses() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.buildHeader();

final BlockHeaderValidator validator =
QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(5, false).build();
Expand All @@ -82,9 +76,12 @@ public void bftValidateHeaderFailsWhenExtraDataDoesntContainValidatorList() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, emptyList(), parentHeader).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(
2, proposerNodeKey, emptyList(), parentHeader)
.buildHeader();

final BlockHeaderValidator validator =
QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(5, false).build();
Expand All @@ -106,9 +103,10 @@ public void bftValidateHeaderFailsOnCoinbaseData() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.coinbase(nonProposerAddress)
.buildHeader();

Expand All @@ -129,9 +127,10 @@ public void bftValidateHeaderIgnoresNonceValue() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(
QbftBlockHeaderUtils.createPresetHeaderBuilder(
2, proposerNodeKey, validators, parentHeader, builder -> builder.nonce(3))
.buildHeader();

Expand All @@ -152,9 +151,10 @@ public void bftValidateHeaderFailsOnTimestamp() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.timestamp(100)
.buildHeader();

Expand All @@ -175,9 +175,10 @@ public void bftValidateHeaderFailsOnMixHash() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(
QbftBlockHeaderUtils.createPresetHeaderBuilder(
2,
proposerNodeKey,
validators,
Expand All @@ -202,9 +203,10 @@ public void bftValidateHeaderIgnoresOmmersValue() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(
QbftBlockHeaderUtils.createPresetHeaderBuilder(
2,
proposerNodeKey,
validators,
Expand All @@ -229,9 +231,10 @@ public void bftValidateHeaderFailsOnDifficulty() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.difficulty(Difficulty.of(5))
.buildHeader();

Expand All @@ -252,9 +255,11 @@ public void bftValidateHeaderFailsOnAncestor() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, null)
.buildHeader();

final BlockHeaderValidator validator =
QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(5, false).build();
Expand All @@ -273,9 +278,10 @@ public void bftValidateHeaderFailsOnGasUsage() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.gasLimit(5_000)
.gasUsed(6_000)
.buildHeader();
Expand All @@ -297,9 +303,10 @@ public void bftValidateHeaderFailsOnGasLimitRange() {
final List<Address> validators = singletonList(proposerAddress);

final BlockHeader parentHeader =
getPresetHeaderBuilder(1, proposerNodeKey, validators, null).buildHeader();
QbftBlockHeaderUtils.createPresetHeaderBuilder(1, proposerNodeKey, validators, null)
.buildHeader();
final BlockHeader blockHeader =
getPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
QbftBlockHeaderUtils.createPresetHeaderBuilder(2, proposerNodeKey, validators, parentHeader)
.gasLimit(4999)
.buildHeader();

Expand All @@ -311,57 +318,4 @@ public void bftValidateHeaderFailsOnGasLimitRange() {
blockHeader, parentHeader, protocolContext(validators), HeaderValidationMode.FULL))
.isFalse();
}

private BlockHeaderTestFixture getPresetHeaderBuilder(
final long number,
final NodeKey proposerNodeKey,
final List<Address> validators,
final BlockHeader parent) {
return getPresetHeaderBuilder(number, proposerNodeKey, validators, parent, null);
}

private BlockHeaderTestFixture getPresetHeaderBuilder(
final long number,
final NodeKey proposerNodeKey,
final List<Address> validators,
final BlockHeader parent,
final HeaderModifier modifier) {
final BlockHeaderTestFixture builder = new BlockHeaderTestFixture();
final QbftExtraDataCodec qbftExtraDataEncoder = new QbftExtraDataCodec();

if (parent != null) {
builder.parentHash(parent.getHash());
}
builder.number(number);
builder.gasLimit(5000);
builder.timestamp(6000 * number);
builder.mixHash(
Hash.fromHexString("0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365"));
builder.difficulty(Difficulty.ONE);
builder.coinbase(Util.publicKeyToAddress(proposerNodeKey.getPublicKey()));
builder.blockHeaderFunctions(BftBlockHeaderFunctions.forCommittedSeal(qbftExtraDataEncoder));

if (modifier != null) {
modifier.update(builder);
}

final BftExtraData bftExtraData =
BftExtraDataFixture.createExtraData(
builder.buildHeader(),
Bytes.wrap(new byte[BftExtraDataCodec.EXTRA_VANITY_LENGTH]),
Optional.of(Vote.authVote(Address.fromHexString("1"))),
validators,
singletonList(proposerNodeKey),
0x2A,
qbftExtraDataEncoder);

builder.extraData(qbftExtraDataEncoder.encode(bftExtraData));
return builder;
}

@FunctionalInterface
public interface HeaderModifier {

void update(BlockHeaderTestFixture blockHeaderTestFixture);
}
}
Loading

0 comments on commit 772a428

Please sign in to comment.