From 4e313a368935035ee705a75bdfe8da8f04cbb499 Mon Sep 17 00:00:00 2001 From: tmohay <37158202+rain-on@users.noreply.github.com> Date: Wed, 10 Oct 2018 13:14:31 +1100 Subject: [PATCH] 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. --- .../consensus/clique/CliqueHelpers.java | 4 + .../blockcreation/CliqueBlockMiner.java | 42 +++ .../clique/NodeCanProduceNextBlockTest.java | 286 ++++++++++++++++++ .../SignerRateLimitValidationRuleTest.java | 254 +--------------- ...lockMinerTest.java => BlockMinerTest.java} | 6 +- 5 files changed, 336 insertions(+), 256 deletions(-) create mode 100644 consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java create mode 100644 consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java rename ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/{EthHashBlockMinerTest.java => BlockMinerTest.java} (97%) diff --git a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/CliqueHelpers.java b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/CliqueHelpers.java index 6e60a0750d..3da7ce566c 100755 --- a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/CliqueHelpers.java +++ b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/CliqueHelpers.java @@ -37,6 +37,10 @@ public class CliqueHelpers { final VoteTally validatorProvider = protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parent); + if (!validatorProvider.getCurrentValidators().contains(candidate)) { + return false; + } + final int minimumUnsignedPastBlocks = minimumBlocksSincePreviousSigning(validatorProvider); final Blockchain blockchain = protocolContext.getBlockchain(); diff --git a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java new file mode 100644 index 0000000000..ef5f3c46c2 --- /dev/null +++ b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java @@ -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 { + + private final Address localAddress; + + public CliqueBlockMiner( + final CliqueBlockCreator blockCreator, + final ProtocolSchedule protocolSchedule, + final ProtocolContext protocolContext, + final Subscribers 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. + } +} diff --git a/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java b/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java new file mode 100644 index 0000000000..ce5f1b8827 --- /dev/null +++ b/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java @@ -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
validatorList = Lists.newArrayList(); + private final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); + private ProtocolContext 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(); + } +} diff --git a/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/headervalidationrules/SignerRateLimitValidationRuleTest.java b/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/headervalidationrules/SignerRateLimitValidationRuleTest.java index 0da9c01d6e..118e19fb07 100755 --- a/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/headervalidationrules/SignerRateLimitValidationRuleTest.java +++ b/consensus/clique/src/test/java/net/consensys/pantheon/consensus/clique/headervalidationrules/SignerRateLimitValidationRuleTest.java @@ -1,258 +1,6 @@ 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 { - private final KeyPair proposerKeyPair = KeyPair.generate(); - private final KeyPair otherNodeKeyPair = KeyPair.generate(); - private final List
validatorList = Lists.newArrayList(); - private final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); - private ProtocolContext 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."); - } + // Implicitly conducted by NodeCanProduceNextBlockTest. } diff --git a/ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/EthHashBlockMinerTest.java b/ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/BlockMinerTest.java similarity index 97% rename from ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/EthHashBlockMinerTest.java rename to ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/BlockMinerTest.java index 18171283b7..44f16335a5 100755 --- a/ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/EthHashBlockMinerTest.java +++ b/ethereum/core/src/test/java/net/consensys/pantheon/ethereum/blockcreation/BlockMinerTest.java @@ -23,7 +23,7 @@ import net.consensys.pantheon.util.Subscribers; import com.google.common.collect.Lists; import org.junit.Test; -public class EthHashBlockMinerTest { +public class BlockMinerTest { @Test @SuppressWarnings("unchecked") @@ -50,7 +50,7 @@ public class EthHashBlockMinerTest { final MinedBlockObserver observer = mock(MinedBlockObserver.class); final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class); when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L); - final EthHashBlockMiner miner = + final BlockMiner miner = new EthHashBlockMiner( blockCreator, protocolSchedule, @@ -88,7 +88,7 @@ public class EthHashBlockMinerTest { final MinedBlockObserver observer = mock(MinedBlockObserver.class); final DefaultBlockScheduler scheduler = mock(DefaultBlockScheduler.class); when(scheduler.waitUntilNextBlockCanBeMined(any())).thenReturn(5L); - final EthHashBlockMiner miner = + final BlockMiner miner = new EthHashBlockMiner( blockCreator, protocolSchedule,