Clique Block Miner added (#11)

Responsible for mining a block if the local  node address
is a validator, and has not recently mined a block.

This has necessitated a slight rework of helper functions,
and shuffling of tests.
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
tmohay 6 years ago committed by GitHub
parent 217750b5f0
commit a754f57c01
  1. 4
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/CliqueHelpers.java
  2. 42
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java
  3. 286
      consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java
  4. 254
      consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/headervalidationrules/SignerRateLimitValidationRuleTest.java
  5. 6
      ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/BlockMinerTest.java

@ -37,6 +37,10 @@ public class CliqueHelpers {
final VoteTally validatorProvider = final VoteTally validatorProvider =
protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parent); protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parent);
if (!validatorProvider.getCurrentValidators().contains(candidate)) {
return false;
}
final int minimumUnsignedPastBlocks = minimumBlocksSincePreviousSigning(validatorProvider); final int minimumUnsignedPastBlocks = minimumBlocksSincePreviousSigning(validatorProvider);
final Blockchain blockchain = protocolContext.getBlockchain(); final Blockchain blockchain = protocolContext.getBlockchain();

@ -0,0 +1,42 @@
package net.consensys.pantheon.consensus.clique.blockcreation;
import net.consensys.pantheon.consensus.clique.CliqueContext;
import net.consensys.pantheon.consensus.clique.CliqueHelpers;
import net.consensys.pantheon.consensus.common.ValidatorProvider;
import net.consensys.pantheon.ethereum.ProtocolContext;
import net.consensys.pantheon.ethereum.blockcreation.AbstractBlockScheduler;
import net.consensys.pantheon.ethereum.blockcreation.BlockMiner;
import net.consensys.pantheon.ethereum.blockcreation.MiningCoordinator.MinedBlockObserver;
import net.consensys.pantheon.ethereum.core.Address;
import net.consensys.pantheon.ethereum.core.BlockHeader;
import net.consensys.pantheon.ethereum.mainnet.ProtocolSchedule;
import net.consensys.pantheon.util.Subscribers;
public class CliqueBlockMiner extends BlockMiner<CliqueContext, CliqueBlockCreator> {
private final Address localAddress;
public CliqueBlockMiner(
final CliqueBlockCreator blockCreator,
final ProtocolSchedule<CliqueContext> protocolSchedule,
final ProtocolContext<CliqueContext> protocolContext,
final Subscribers<MinedBlockObserver> observers,
final AbstractBlockScheduler scheduler,
final BlockHeader parentHeader,
final Address localAddress) {
super(blockCreator, protocolSchedule, protocolContext, observers, scheduler, parentHeader);
this.localAddress = localAddress;
}
@Override
protected boolean mineBlock() throws InterruptedException {
ValidatorProvider validators =
protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parentHeader);
if (CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, protocolContext, parentHeader)) {
return super.mineBlock();
}
return true; // terminate mining.
}
}

@ -0,0 +1,286 @@
package net.consensys.pantheon.consensus.clique;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import net.consensys.pantheon.consensus.clique.headervalidationrules.SignerRateLimitValidationRule;
import net.consensys.pantheon.consensus.common.VoteProposer;
import net.consensys.pantheon.consensus.common.VoteTally;
import net.consensys.pantheon.crypto.SECP256K1.KeyPair;
import net.consensys.pantheon.ethereum.ProtocolContext;
import net.consensys.pantheon.ethereum.core.Address;
import net.consensys.pantheon.ethereum.core.AddressHelpers;
import net.consensys.pantheon.ethereum.core.Block;
import net.consensys.pantheon.ethereum.core.BlockBody;
import net.consensys.pantheon.ethereum.core.BlockHeader;
import net.consensys.pantheon.ethereum.core.BlockHeaderTestFixture;
import net.consensys.pantheon.ethereum.core.Hash;
import net.consensys.pantheon.ethereum.core.Util;
import net.consensys.pantheon.ethereum.db.DefaultMutableBlockchain;
import net.consensys.pantheon.ethereum.mainnet.MainnetBlockHashFunction;
import net.consensys.pantheon.services.kvstore.InMemoryKeyValueStorage;
import net.consensys.pantheon.services.kvstore.KeyValueStorage;
import java.util.List;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
public class NodeCanProduceNextBlockTest {
private final KeyPair proposerKeyPair = KeyPair.generate();
private Address localAddress;
private final KeyPair otherNodeKeyPair = KeyPair.generate();
private final List<Address> validatorList = Lists.newArrayList();
private final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
private ProtocolContext<CliqueContext> cliqueProtocolContext;
DefaultMutableBlockchain blockChain;
private Block genesisBlock;
private Block createEmptyBlock(final KeyPair blockSigner) {
final BlockHeader header =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, blockSigner, validatorList);
return new Block(header, new BlockBody(Lists.newArrayList(), Lists.newArrayList()));
}
@Before
public void setup() {
localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
validatorList.add(localAddress);
}
@Test
public void networkWithOneValidatorIsAllowedToCreateConsecutiveBlocks() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.number(1).parentHash(genesisBlock.getHash());
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_1.getHeader()))
.isTrue();
}
@Test
public void networkWithTwoValidatorsIsAllowedToProduceBlockIfNotPreviousBlockProposer() {
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(otherNodeKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.number(1).parentHash(genesisBlock.getHash());
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
headerBuilder.number(2).parentHash(block_1.getHash());
final Block block_2 = createEmptyBlock(otherNodeKeyPair);
blockChain.appendBlock(block_2, Lists.newArrayList());
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_1.getHeader()))
.isFalse();
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_2.getHeader()))
.isTrue();
}
@Test
public void networkWithTwoValidatorsIsNotAllowedToProduceBlockIfIsPreviousBlockProposer() {
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(genesisBlock.getHash()).number(1);
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
headerBuilder.parentHash(block_1.getHeader().getHash()).number(2);
final BlockHeader block_2 =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThat(validationRule.validate(block_2, block_1.getHeader(), cliqueProtocolContext))
.isFalse();
}
@Test
public void withThreeValidatorsMustHaveOneBlockBetweenSignings() {
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(otherAddress);
validatorList.add(AddressHelpers.ofValue(1));
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(genesisBlock.getHash()).number(1);
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
headerBuilder.parentHash(block_1.getHash()).number(2);
final Block block_2 = createEmptyBlock(otherNodeKeyPair);
blockChain.appendBlock(block_2, Lists.newArrayList());
headerBuilder.parentHash(block_2.getHash()).number(3);
final Block block_3 = createEmptyBlock(otherNodeKeyPair);
blockChain.appendBlock(block_3, Lists.newArrayList());
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_1.getHeader()))
.isFalse();
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_2.getHeader()))
.isTrue();
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_3.getHeader()))
.isTrue();
}
@Test
public void signerIsValidIfInsufficientBlocksExistInHistory() {
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(otherAddress);
validatorList.add(AddressHelpers.ofValue(1));
validatorList.add(AddressHelpers.ofValue(2));
validatorList.add(AddressHelpers.ofValue(3));
// Should require 2 blocks between signings.
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(genesisBlock.getHash()).number(1);
final Block block_1 = createEmptyBlock(otherNodeKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, genesisBlock.getHeader()))
.isTrue();
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, block_1.getHeader()))
.isTrue();
}
@Test
public void exceptionIsThrownIfOnAnOrphanedChain() {
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(Hash.ZERO).number(3);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, otherNodeKeyPair, validatorList);
assertThatThrownBy(
() ->
CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, cliqueProtocolContext, parentHeader))
.isInstanceOf(RuntimeException.class)
.hasMessage("The block was on a orphaned chain.");
}
@Test
public void nonValidatorIsNotAllowedToCreateABlock() {
genesisBlock = createEmptyBlock(otherNodeKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(Hash.ZERO).number(3);
final BlockHeader parentHeader = headerBuilder.buildHeader();
assertThat(
CliqueHelpers.addressIsAllowedToProduceNextBlock(
AddressHelpers.ofValue(1), cliqueProtocolContext, parentHeader))
.isFalse();
}
}

@ -1,258 +1,6 @@
package net.consensys.pantheon.consensus.clique.headervalidationrules; package net.consensys.pantheon.consensus.clique.headervalidationrules;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import net.consensys.pantheon.consensus.clique.CliqueContext;
import net.consensys.pantheon.consensus.clique.TestHelpers;
import net.consensys.pantheon.consensus.clique.VoteTallyCache;
import net.consensys.pantheon.consensus.common.VoteProposer;
import net.consensys.pantheon.consensus.common.VoteTally;
import net.consensys.pantheon.crypto.SECP256K1.KeyPair;
import net.consensys.pantheon.ethereum.ProtocolContext;
import net.consensys.pantheon.ethereum.core.Address;
import net.consensys.pantheon.ethereum.core.AddressHelpers;
import net.consensys.pantheon.ethereum.core.Block;
import net.consensys.pantheon.ethereum.core.BlockBody;
import net.consensys.pantheon.ethereum.core.BlockHeader;
import net.consensys.pantheon.ethereum.core.BlockHeaderTestFixture;
import net.consensys.pantheon.ethereum.core.Hash;
import net.consensys.pantheon.ethereum.core.Util;
import net.consensys.pantheon.ethereum.db.DefaultMutableBlockchain;
import net.consensys.pantheon.ethereum.mainnet.MainnetBlockHashFunction;
import net.consensys.pantheon.services.kvstore.InMemoryKeyValueStorage;
import net.consensys.pantheon.services.kvstore.KeyValueStorage;
import java.util.List;
import com.google.common.collect.Lists;
import org.junit.Test;
public class SignerRateLimitValidationRuleTest { public class SignerRateLimitValidationRuleTest {
private final KeyPair proposerKeyPair = KeyPair.generate(); // Implicitly conducted by NodeCanProduceNextBlockTest.
private final KeyPair otherNodeKeyPair = KeyPair.generate();
private final List<Address> validatorList = Lists.newArrayList();
private final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
private ProtocolContext<CliqueContext> cliqueProtocolContext;
DefaultMutableBlockchain blockChain;
private Block genesisBlock;
private Block createEmptyBlock(final KeyPair blockSigner) {
final BlockHeader header =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, blockSigner, validatorList);
return new Block(header, new BlockBody(Lists.newArrayList(), Lists.newArrayList()));
}
@Test
public void networkWithOneValidatorIsAllowedToCreateConsecutiveBlocks() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
validatorList.add(localAddress);
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
final BlockHeader nextBlockHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThat(
validationRule.validate(
nextBlockHeader, genesisBlock.getHeader(), cliqueProtocolContext))
.isTrue();
}
@Test
public void networkWithTwoValidatorsIsAllowedToProduceBlockIfNotPreviousBlockProposer() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(otherNodeKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
final BlockHeader nextBlockHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThat(
validationRule.validate(
nextBlockHeader, genesisBlock.getHeader(), cliqueProtocolContext))
.isTrue();
}
@Test
public void networkWithTwoValidatorsIsNotAllowedToProduceBlockIfIsPreviousBlockProposer() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(genesisBlock.getHash()).number(1);
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
headerBuilder.parentHash(block_1.getHeader().getHash()).number(2);
final BlockHeader block_2 =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThat(validationRule.validate(block_2, block_1.getHeader(), cliqueProtocolContext))
.isFalse();
}
@Test
public void withThreeValidatorsMustHaveOneBlockBetweenSignings() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(otherAddress);
validatorList.add(AddressHelpers.ofValue(1));
genesisBlock = createEmptyBlock(proposerKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(genesisBlock.getHash()).number(1);
final Block block_1 = createEmptyBlock(proposerKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
headerBuilder.parentHash(block_1.getHash()).number(2);
final Block block_2 = createEmptyBlock(otherNodeKeyPair);
blockChain.appendBlock(block_1, Lists.newArrayList());
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
BlockHeader nextBlockHeader;
// Should not be able to proposer ontop of Block_1 (which has the same sealer)
headerBuilder.parentHash(block_1.getHash()).number(2);
nextBlockHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
assertThat(validationRule.validate(nextBlockHeader, block_1.getHeader(), cliqueProtocolContext))
.isFalse();
headerBuilder.parentHash(block_1.getHash()).number(3);
nextBlockHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
assertThat(validationRule.validate(nextBlockHeader, block_2.getHeader(), cliqueProtocolContext))
.isTrue();
}
@Test
public void signerIsValidIfInsufficientBlocksExistInHistory() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(otherAddress);
validatorList.add(AddressHelpers.ofValue(1));
genesisBlock = createEmptyBlock(otherNodeKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
final BlockHeader nextBlockHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThat(
validationRule.validate(
nextBlockHeader, genesisBlock.getHeader(), cliqueProtocolContext))
.isTrue();
}
@Test
public void exceptionIsThrownIfOnAnOrphanedChain() {
final Address localAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey());
final Address otherAddress = Util.publicKeyToAddress(otherNodeKeyPair.getPublicKey());
validatorList.add(localAddress);
validatorList.add(otherAddress);
genesisBlock = createEmptyBlock(otherNodeKeyPair);
final KeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
blockChain =
new DefaultMutableBlockchain(
genesisBlock, keyValueStorage, MainnetBlockHashFunction::createHash);
final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
when(voteTallyCache.getVoteTallyAtBlock(any())).thenReturn(new VoteTally(validatorList));
final VoteProposer voteProposer = new VoteProposer();
final CliqueContext cliqueContext = new CliqueContext(voteTallyCache, voteProposer);
cliqueProtocolContext = new ProtocolContext<>(blockChain, null, cliqueContext);
headerBuilder.parentHash(Hash.ZERO).number(4);
final BlockHeader nextBlock =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, proposerKeyPair, validatorList);
headerBuilder.parentHash(Hash.ZERO).number(3);
final BlockHeader parentHeader =
TestHelpers.createCliqueSignedBlockHeader(headerBuilder, otherNodeKeyPair, validatorList);
final SignerRateLimitValidationRule validationRule = new SignerRateLimitValidationRule();
assertThatThrownBy(
() -> validationRule.validate(nextBlock, parentHeader, cliqueProtocolContext))
.isInstanceOf(RuntimeException.class)
.hasMessage("The block was on a orphaned chain.");
}
} }

@ -23,7 +23,7 @@ import net.consensys.pantheon.util.Subscribers;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.junit.Test; import org.junit.Test;
public class EthHashBlockMinerTest { public class BlockMinerTest {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -50,7 +50,7 @@ public class EthHashBlockMinerTest {
final MinedBlockObserver observer = mock(MinedBlockObserver.class); final MinedBlockObserver observer = mock(MinedBlockObserver.class);
final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class); final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class);
when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L); when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L);
final EthHashBlockMiner miner = final BlockMiner<Void, EthHashBlockCreator> miner =
new EthHashBlockMiner( new EthHashBlockMiner(
blockCreator, blockCreator,
protocolSchedule, protocolSchedule,
@ -88,7 +88,7 @@ public class EthHashBlockMinerTest {
final MinedBlockObserver observer = mock(MinedBlockObserver.class); final MinedBlockObserver observer = mock(MinedBlockObserver.class);
final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class); final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class);
when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L); when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L);
final EthHashBlockMiner miner = final BlockMiner<Void, EthHashBlockCreator> miner =
new EthHashBlockMiner( new EthHashBlockMiner(
blockCreator, blockCreator,
protocolSchedule, protocolSchedule,
Loading…
Cancel
Save