Repair Clique Proposer Selection (#339)

Clique Proposer Selection would choose an incorrect peer
when a signer was removed from the pool, as the algorithm worked
purely on the block count.

The algorithm has now been updated to ensure the next proposer is
incrementally the next signer in the ordered list, based on the
parent's proposer
tmohay 6 years ago committed by GitHub
parent 566a4bf76e
commit b8dbfd50fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueBlockHashing.java
  2. 29
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueProposerSelector.java
  3. 20
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueDifficultyCalculatorTest.java
  4. 28
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java
  5. 71
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueProposerSelectorTest.java
  6. 78
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/headervalidationrules/CliqueDifficultyValidationRuleTest.java
  7. 13
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java
  8. 13
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java
  9. 4
      consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/ValidatorProvider.java
  10. 6
      consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteTally.java
  11. 4
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/network/IbftNetworkPeersTest.java

@ -50,7 +50,7 @@ public class CliqueBlockHashing {
final BlockHeader header, final CliqueExtraData cliqueExtraData) {
if (!cliqueExtraData.getProposerSeal().isPresent()) {
throw new IllegalArgumentException(
"Supplied cliqueExtraData does not include a proposer " + "seal");
"Supplied cliqueExtraData does not include a proposer seal.");
}
final Hash proposerHash = calculateDataHashForProposerSeal(header, cliqueExtraData);
return Util.signatureToAddress(cliqueExtraData.getProposerSeal().get(), proposerHash);

@ -14,13 +14,14 @@ package tech.pegasys.pantheon.consensus.clique.blockcreation;
import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.consensus.clique.CliqueBlockInterface;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.SortedSet;
/**
* Responsible for determining which member of the validator pool should create the next block.
@ -31,6 +32,7 @@ import java.util.List;
public class CliqueProposerSelector {
private final VoteTallyCache voteTallyCache;
private final CliqueBlockInterface blockInterface = new CliqueBlockInterface();
public CliqueProposerSelector(final VoteTallyCache voteTallyCache) {
checkNotNull(voteTallyCache);
@ -46,11 +48,26 @@ public class CliqueProposerSelector {
public Address selectProposerForNextBlock(final BlockHeader parentHeader) {
final VoteTally parentVoteTally = voteTallyCache.getVoteTallyAtBlock(parentHeader);
final List<Address> validatorSet = new ArrayList<>(parentVoteTally.getCurrentValidators());
final NavigableSet<Address> validatorSet = parentVoteTally.getCurrentValidators();
final long nextBlockNumber = parentHeader.getNumber() + 1L;
final int indexIntoValidators = (int) (nextBlockNumber % validatorSet.size());
Address prevBlockProposer = validatorSet.first();
if (parentHeader.getNumber() != BlockHeader.GENESIS_BLOCK_NUMBER) {
prevBlockProposer = blockInterface.getProposerOfBlock(parentHeader);
}
return validatorSet.get(indexIntoValidators);
return selectNextProposer(prevBlockProposer, validatorSet);
}
private Address selectNextProposer(
final Address prevBlockProposer, final NavigableSet<Address> validatorSet) {
final SortedSet<Address> latterValidators = validatorSet.tailSet(prevBlockProposer, false);
if (latterValidators.isEmpty()) {
// i.e. prevBlockProposer was at the end of the validator list, so the right validator for
// the start of this round is the first.
return validatorSet.first();
} else {
// Else, use the first validator after the dropped entry.
return latterValidators.first();
}
}
}

@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.clique.TestHelpers.createCliqueSignedBlockHeader;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
@ -57,25 +58,30 @@ public class CliqueDifficultyCalculatorTest {
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer, null);
cliqueProtocolContext = new ProtocolContext<>(null, null, cliqueContext);
blockHeaderBuilder = new BlockHeaderTestFixture();
blockHeaderBuilder.number(1);
}
@Test
public void inTurnValidatorProducesDifficultyOfTwo() {
public void outTurnValidatorProducesDifficultyOfOne() {
// The proposer created the last block, so the next block must be a difficulty of 1.
final CliqueDifficultyCalculator calculator = new CliqueDifficultyCalculator(localAddr);
final BlockHeader parentHeader = blockHeaderBuilder.number(1).buildHeader();
BlockHeader parentHeader =
createCliqueSignedBlockHeader(blockHeaderBuilder, proposerKeyPair, validatorList);
assertThat(calculator.nextDifficulty(0, parentHeader, cliqueProtocolContext))
.isEqualTo(BigInteger.valueOf(2));
.isEqualTo(BigInteger.valueOf(1));
}
@Test
public void outTurnValidatorProducesDifficultyOfOne() {
final CliqueDifficultyCalculator calculator = new CliqueDifficultyCalculator(localAddr);
public void inTurnValidatorCreatesDifficultyOfTwo() {
final CliqueDifficultyCalculator calculator =
new CliqueDifficultyCalculator(validatorList.get(1)); // i.e. not the proposer.
final BlockHeader parentHeader = blockHeaderBuilder.number(2).buildHeader();
BlockHeader parentHeader =
createCliqueSignedBlockHeader(blockHeaderBuilder, proposerKeyPair, validatorList);
assertThat(calculator.nextDifficulty(0, parentHeader, cliqueProtocolContext))
.isEqualTo(BigInteger.valueOf(1));
.isEqualTo(BigInteger.valueOf(2));
}
}

@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.clique.TestHelpers.createCliqueSignedBlockHeader;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally;
@ -37,7 +38,8 @@ import org.junit.Test;
public class CliqueBlockSchedulerTest {
private final KeyPair proposerKeyPair = KeyPair.generate();
private Address localAddr;
private Address localAddr = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
private Address otherAddr = AddressHelpers.calculateAddressWithRespectTo(localAddr, 1);
private final List<Address> validatorList = Lists.newArrayList();
private VoteTallyCache voteTallyCache;
@ -45,10 +47,9 @@ public class CliqueBlockSchedulerTest {
@Before
public void setup() {
localAddr = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
validatorList.add(localAddr);
validatorList.add(AddressHelpers.calculateAddressWithRespectTo(localAddr, 1));
validatorList.add(otherAddr);
voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
@ -63,12 +64,11 @@ public class CliqueBlockSchedulerTest {
final long secondsBetweenBlocks = 5L;
when(clock.millis()).thenReturn(currentSecondsSinceEpoch * 1000);
final CliqueBlockScheduler scheduler =
new CliqueBlockScheduler(clock, voteTallyCache, localAddr, secondsBetweenBlocks);
new CliqueBlockScheduler(clock, voteTallyCache, otherAddr, secondsBetweenBlocks);
// There are 2 validators, therefore block 2 will put localAddr as the in-turn voter, therefore
// parent block should be number 1.
blockHeaderBuilder.number(1).timestamp(currentSecondsSinceEpoch);
final BlockHeader parentHeader =
blockHeaderBuilder.number(1).timestamp(currentSecondsSinceEpoch).buildHeader();
createCliqueSignedBlockHeader(blockHeaderBuilder, proposerKeyPair, validatorList);
final BlockCreationTimeResult result = scheduler.getNextTimestamp(parentHeader);
@ -86,10 +86,9 @@ public class CliqueBlockSchedulerTest {
final CliqueBlockScheduler scheduler =
new CliqueBlockScheduler(clock, voteTallyCache, localAddr, secondsBetweenBlocks);
// There are 2 validators, therefore block 3 will put localAddr as the out-turn voter, therefore
// parent block should be number 2.
blockHeaderBuilder.number(2).timestamp(currentSecondsSinceEpoch);
final BlockHeader parentHeader =
blockHeaderBuilder.number(2).timestamp(currentSecondsSinceEpoch).buildHeader();
createCliqueSignedBlockHeader(blockHeaderBuilder, proposerKeyPair, validatorList);
final BlockCreationTimeResult result = scheduler.getNextTimestamp(parentHeader);
@ -105,16 +104,13 @@ public class CliqueBlockSchedulerTest {
final long secondsBetweenBlocks = 5L;
when(clock.millis()).thenReturn(currentSecondsSinceEpoch * 1000);
final CliqueBlockScheduler scheduler =
new CliqueBlockScheduler(clock, voteTallyCache, localAddr, secondsBetweenBlocks);
new CliqueBlockScheduler(clock, voteTallyCache, otherAddr, secondsBetweenBlocks);
// There are 2 validators, therefore block 2 will put localAddr as the in-turn voter, therefore
// parent block should be number 1.
blockHeaderBuilder.number(1).timestamp(currentSecondsSinceEpoch - secondsBetweenBlocks);
final BlockHeader parentHeader =
blockHeaderBuilder
.number(1)
.timestamp(currentSecondsSinceEpoch - secondsBetweenBlocks)
.buildHeader();
createCliqueSignedBlockHeader(blockHeaderBuilder, proposerKeyPair, validatorList);
final BlockCreationTimeResult result = scheduler.getNextTimestamp(parentHeader);
assertThat(result.getTimestampForHeader()).isEqualTo(currentSecondsSinceEpoch);

@ -17,46 +17,87 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.TestHelpers;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.Util;
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
public class CliqueProposerSelectorTest {
private final KeyPair proposerKey = KeyPair.generate();
private final Address proposerAddress = Util.publicKeyToAddress(proposerKey.getPublicKey());
private final List<Address> validatorList =
Arrays.asList(
AddressHelpers.ofValue(1),
AddressHelpers.ofValue(2),
AddressHelpers.ofValue(3),
AddressHelpers.ofValue(4));
Lists.newArrayList(
AddressHelpers.calculateAddressWithRespectTo(proposerAddress, -1),
proposerAddress,
AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 1),
AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 2));
private final VoteTally voteTally = new VoteTally(validatorList);
private VoteTallyCache voteTallyCache;
private final BlockHeaderTestFixture headerBuilderFixture = new BlockHeaderTestFixture();
@Before
public void setup() {
voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(voteTally);
headerBuilderFixture.number(2);
}
@Test
public void proposerForABlockIsBasedOnModBlockNumber() {
public void firstBlockAfterGenesisIsTheSecondValidator() {
final BlockHeaderTestFixture headerBuilderFixture = new BlockHeaderTestFixture();
final CliqueProposerSelector selector = new CliqueProposerSelector(voteTallyCache);
headerBuilderFixture.number(0);
assertThat(selector.selectProposerForNextBlock(headerBuilderFixture.buildHeader()))
.isEqualTo(validatorList.get(1));
}
@Test
public void selectsNextProposerInValidatorSet() {
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilderFixture, proposerKey, validatorList);
final CliqueProposerSelector selector = new CliqueProposerSelector(voteTallyCache);
// Proposer is at index 1, so the next proposer is at index 2
assertThat(selector.selectProposerForNextBlock(parentHeader)).isEqualTo(validatorList.get(2));
}
@Test
public void selectsNextIndexWhenProposerIsNotInValidatorsForBlock() {
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilderFixture, proposerKey, validatorList);
final CliqueProposerSelector selector = new CliqueProposerSelector(voteTallyCache);
validatorList.remove(proposerAddress);
// As the proposer was removed (index 1), the next proposer should also be index 1
assertThat(selector.selectProposerForNextBlock(parentHeader)).isEqualTo(validatorList.get(1));
}
@Test
public void singleValidatorFindsItselfAsNextProposer() {
final List<Address> localValidators = Lists.newArrayList(proposerAddress);
final VoteTally localVoteTally = new VoteTally(localValidators);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(localVoteTally);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilderFixture, proposerKey, validatorList);
final CliqueProposerSelector selector = new CliqueProposerSelector(voteTallyCache);
for (int prevBlockNumber = 0; prevBlockNumber < 10; prevBlockNumber++) {
headerBuilderFixture.number(prevBlockNumber);
final CliqueProposerSelector selector = new CliqueProposerSelector(voteTallyCache);
final Address nextProposer =
selector.selectProposerForNextBlock(headerBuilderFixture.buildHeader());
assertThat(nextProposer)
.isEqualTo(validatorList.get((prevBlockNumber + 1) % validatorList.size()));
}
assertThat(selector.selectProposerForNextBlock(parentHeader)).isEqualTo(proposerAddress);
}
}

@ -17,23 +17,17 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.CliqueBlockHashing;
import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.TestHelpers;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.uint.UInt256;
import java.util.List;
@ -45,15 +39,15 @@ import org.junit.Test;
public class CliqueDifficultyValidationRuleTest {
private final KeyPair proposerKeyPair = KeyPair.generate();
private final KeyPair otherKeyPair = KeyPair.generate();
private final List<Address> validatorList = Lists.newArrayList();
private ProtocolContext<CliqueContext> cliqueProtocolContext;
private BlockHeaderTestFixture blockHeaderBuilder;
@Before
public void setup() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(AddressHelpers.calculateAddressWithRespectTo(localAddress, 1));
validatorList.add(Util.publicKeyToAddress(proposerKeyPair.getPublicKey()));
validatorList.add(Util.publicKeyToAddress(otherKeyPair.getPublicKey()));
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
@ -62,29 +56,7 @@ public class CliqueDifficultyValidationRuleTest {
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer, null);
cliqueProtocolContext = new ProtocolContext<>(null, null, cliqueContext);
blockHeaderBuilder = new BlockHeaderTestFixture();
}
private BlockHeader createCliqueSignedBlock(final BlockHeaderTestFixture blockHeaderBuilder) {
final CliqueExtraData unsignedExtraData =
new CliqueExtraData(BytesValue.wrap(new byte[32]), null, validatorList);
blockHeaderBuilder.extraData(unsignedExtraData.encode());
final Hash signingHash =
CliqueBlockHashing.calculateDataHashForProposerSeal(
blockHeaderBuilder.buildHeader(), unsignedExtraData);
final Signature proposerSignature = SECP256K1.sign(signingHash, proposerKeyPair);
final CliqueExtraData signedExtraData =
new CliqueExtraData(
unsignedExtraData.getVanityData(),
proposerSignature,
unsignedExtraData.getValidators());
blockHeaderBuilder.extraData(signedExtraData.encode());
return blockHeaderBuilder.buildHeader();
blockHeaderBuilder.number(2);
}
@Test
@ -92,11 +64,13 @@ public class CliqueDifficultyValidationRuleTest {
final long IN_TURN_BLOCK_NUMBER = validatorList.size(); // i.e. proposer is 'in turn'
final UInt256 REPORTED_DIFFICULTY = UInt256.of(2);
blockHeaderBuilder.number(IN_TURN_BLOCK_NUMBER - 1L);
final BlockHeader parentHeader = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(blockHeaderBuilder, otherKeyPair, validatorList);
blockHeaderBuilder.number(IN_TURN_BLOCK_NUMBER).difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader newBlock =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
final CliqueDifficultyValidationRule diffValidationRule = new CliqueDifficultyValidationRule();
assertThat(diffValidationRule.validate(newBlock, parentHeader, cliqueProtocolContext)).isTrue();
@ -107,11 +81,14 @@ public class CliqueDifficultyValidationRuleTest {
final long OUT_OF_TURN_BLOCK_NUMBER = validatorList.size() - 1L;
final UInt256 REPORTED_DIFFICULTY = UInt256.of(1);
blockHeaderBuilder.number(OUT_OF_TURN_BLOCK_NUMBER - 1L);
final BlockHeader parentHeader = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
blockHeaderBuilder.number(OUT_OF_TURN_BLOCK_NUMBER).difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader newBlock =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
final CliqueDifficultyValidationRule diffValidationRule = new CliqueDifficultyValidationRule();
assertThat(diffValidationRule.validate(newBlock, parentHeader, cliqueProtocolContext)).isTrue();
@ -119,14 +96,16 @@ public class CliqueDifficultyValidationRuleTest {
@Test
public void isFalseIfOutTurnValidatorSuppliesDifficultyOfTwo() {
final long OUT_OF_TURN_BLOCK_NUMBER = validatorList.size() - 1L;
final UInt256 REPORTED_DIFFICULTY = UInt256.of(2);
blockHeaderBuilder.number(OUT_OF_TURN_BLOCK_NUMBER - 1L);
final BlockHeader parentHeader = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
blockHeaderBuilder.number(OUT_OF_TURN_BLOCK_NUMBER).difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock = createCliqueSignedBlock(blockHeaderBuilder);
blockHeaderBuilder.difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
final CliqueDifficultyValidationRule diffValidationRule = new CliqueDifficultyValidationRule();
assertThat(diffValidationRule.validate(newBlock, parentHeader, cliqueProtocolContext))
@ -135,14 +114,15 @@ public class CliqueDifficultyValidationRuleTest {
@Test
public void isFalseIfInTurnValidatorSuppliesDifficultyOfOne() {
final long IN_TURN_BLOCK_NUMBER = validatorList.size();
final UInt256 REPORTED_DIFFICULTY = UInt256.of(1);
blockHeaderBuilder.number(IN_TURN_BLOCK_NUMBER - 1L);
final BlockHeader parentHeader = createCliqueSignedBlock(blockHeaderBuilder);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(blockHeaderBuilder, otherKeyPair, validatorList);
blockHeaderBuilder.number(IN_TURN_BLOCK_NUMBER).difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock = createCliqueSignedBlock(blockHeaderBuilder);
blockHeaderBuilder.difficulty(REPORTED_DIFFICULTY);
final BlockHeader newBlock =
TestHelpers.createCliqueSignedBlockHeader(
blockHeaderBuilder, proposerKeyPair, validatorList);
final CliqueDifficultyValidationRule diffValidationRule = new CliqueDifficultyValidationRule();
assertThat(diffValidationRule.validate(newBlock, parentHeader, cliqueProtocolContext))

@ -37,7 +37,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessRe
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.List;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.TreeSet;
import org.assertj.core.api.AssertionsForClassTypes;
import org.bouncycastle.util.encoders.Hex;
@ -52,7 +54,7 @@ public class CliqueGetSignersAtHashTest {
private CliqueGetSignersAtHash method;
private BlockHeader blockHeader;
private List<Address> validators;
private NavigableSet<Address> validators;
private List<String> validatorsAsStrings;
@Mock private BlockchainQueries blockchainQueries;
@ -75,10 +77,11 @@ public class CliqueGetSignersAtHashTest {
blockHeader = blockHeaderTestFixture.extraData(bufferToInject).buildHeader();
validators =
asList(
fromHexString("0x42eb768f2244c8811c63729a21a3569731535f06"),
fromHexString("0x7ffc57839b00206d1ad20c69a1981b489f772031"),
fromHexString("0xb279182d99e65703f0076e4812653aab85fca0f0"));
new TreeSet<>(
asList(
fromHexString("0x42eb768f2244c8811c63729a21a3569731535f06"),
fromHexString("0x7ffc57839b00206d1ad20c69a1981b489f772031"),
fromHexString("0xb279182d99e65703f0076e4812653aab85fca0f0")));
validatorsAsStrings = validators.stream().map(Object::toString).collect(toList());
}

@ -36,7 +36,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessRe
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.List;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.TreeSet;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Before;
@ -49,7 +51,7 @@ import org.mockito.junit.MockitoJUnitRunner;
public class CliqueGetSignersTest {
private CliqueGetSigners method;
private BlockHeader blockHeader;
private List<Address> validators;
private NavigableSet<Address> validators;
private List<String> validatorAsStrings;
@Mock private BlockchainQueries blockchainQueries;
@ -69,10 +71,11 @@ public class CliqueGetSignersTest {
blockHeader = blockHeaderTestFixture.extraData(bufferToInject).buildHeader();
validators =
asList(
fromHexString("0x42eb768f2244c8811c63729a21a3569731535f06"),
fromHexString("0x7ffc57839b00206d1ad20c69a1981b489f772031"),
fromHexString("0xb279182d99e65703f0076e4812653aab85fca0f0"));
new TreeSet<>(
asList(
fromHexString("0x42eb768f2244c8811c63729a21a3569731535f06"),
fromHexString("0x7ffc57839b00206d1ad20c69a1981b489f772031"),
fromHexString("0xb279182d99e65703f0076e4812653aab85fca0f0")));
validatorAsStrings = validators.stream().map(Object::toString).collect(toList());
}

@ -14,10 +14,10 @@ package tech.pegasys.pantheon.consensus.common;
import tech.pegasys.pantheon.ethereum.core.Address;
import java.util.Collection;
import java.util.NavigableSet;
public interface ValidatorProvider {
// Returns the current list of validators
Collection<Address> getCurrentValidators();
NavigableSet<Address> getCurrentValidators();
}

@ -20,9 +20,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import com.google.common.collect.Maps;
@ -30,7 +30,7 @@ import com.google.common.collect.Maps;
/** Tracks the current list of validators and votes to add or drop validators. */
public class VoteTally implements ValidatorProvider {
private final SortedSet<Address> currentValidators;
private final NavigableSet<Address> currentValidators;
private final Map<Address, Set<Address>> addVotesBySubject;
private final Map<Address, Set<Address>> removeVotesBySubject;
@ -108,7 +108,7 @@ public class VoteTally implements ValidatorProvider {
}
@Override
public Collection<Address> getCurrentValidators() {
public NavigableSet<Address> getCurrentValidators() {
return currentValidators;
}

@ -32,6 +32,8 @@ import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.math.BigInteger;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import com.google.common.collect.Lists;
import org.junit.Before;
@ -42,7 +44,7 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class IbftNetworkPeersTest {
private final List<Address> validators = Lists.newArrayList();
private final NavigableSet<Address> validators = new TreeSet<>();
private final List<PublicKey> publicKeys = Lists.newArrayList();
private final List<PeerConnection> peerConnections = Lists.newArrayList();

Loading…
Cancel
Save