IBFT to use VoteTallyCache (#907)

It was identified during a demonstration that Pantheon, when running
in IBFT would show a "Bad Block Import" when a validator was added or
removed from the validator pool.

It was determined this was due to IBFT maintaining a single, 'global'
copy of the curent list of validators, which was updated when a block
was imported - thus when a block which had been imported vi IBFT
was then received via Eth block propogation, the validator list would
not align with the global list (as it had been updated in the IBFT
import).

The solution has been to utilise the VoteTallyCache as used in the
Clique implementation.
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Trent Mohay 6 years ago committed by GitHub
parent 84d998130e
commit 6a71c66ad5
  1. 1
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueContext.java
  2. 1
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueHelpers.java
  3. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockScheduler.java
  4. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueProposerSelector.java
  5. 5
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java
  6. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSigners.java
  7. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java
  8. 1
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueDifficultyCalculatorTest.java
  9. 1
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/NodeCanProduceNextBlockTest.java
  10. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java
  11. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java
  12. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  13. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinatorTest.java
  14. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueProposerSelectorTest.java
  15. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/headervalidationrules/CliqueDifficultyValidationRuleTest.java
  16. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/headervalidationrules/CliqueExtraDataValidationRuleTest.java
  17. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java
  18. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java
  19. 17
      consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteTallyCache.java
  20. 33
      consensus/common/src/test/java/tech/pegasys/pantheon/consensus/common/VoteTallyCacheTest.java
  21. 2
      consensus/ibft/build.gradle
  22. 17
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java
  23. 68
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockImporter.java
  24. 12
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftContext.java
  25. 12
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java
  26. 11
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorFactory.java
  27. 71
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/ProposerSelector.java
  28. 5
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftCoinbaseValidationRule.java
  29. 5
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftCommitSealsValidationRule.java
  30. 34
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftValidatorsValidationRule.java
  31. 17
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/network/ValidatorPeers.java
  32. 5
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftBlockHeightManager.java
  33. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftBlockHeightManagerFactory.java
  34. 14
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftFinalState.java
  35. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftRoundFactory.java
  36. 38
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/validation/MessageValidatorFactory.java
  37. 40
      consensus/ibft/src/test-support/java/tech/pegasys/pantheon/consensus/ibft/IbftContextBuilder.java
  38. 28
      consensus/ibft/src/test-support/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolContextFixture.java
  39. 8
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java
  40. 107
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockImporterTest.java
  41. 4
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorTest.java
  42. 49
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/ProposerSelectorTest.java
  43. 8
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftCoinbaseValidationRuleTest.java
  44. 19
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftCommitSealsValidationRuleTest.java
  45. 16
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/headervalidationrules/IbftValidatorsValidationRuleTest.java
  46. 21
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/network/ValidatorPeersTest.java
  47. 9
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java
  48. 7
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftRoundTest.java
  49. 7
      consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java
  50. 37
      consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/headervalidationrules/IbftExtraDataValidationRule.java
  51. 24
      consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactoryTest.java
  52. 4
      consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java
  53. 26
      consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/headervalidationrules/IbftExtraDataValidationRuleTest.java
  54. 13
      pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
  55. 13
      pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java
  56. 22
      pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
  57. 4
      pantheon/src/main/java/tech/pegasys/pantheon/util/BlockImporter.java

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.consensus.clique;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
/** /**
* Holds the data which lives "in parallel" with the importation of blocks etc. when using the * Holds the data which lives "in parallel" with the importation of blocks etc. when using the

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.consensus.clique;
import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueProposerSelector; import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueProposerSelector;
import tech.pegasys.pantheon.consensus.common.ValidatorProvider; import tech.pegasys.pantheon.consensus.common.ValidatorProvider;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;

@ -12,8 +12,8 @@
*/ */
package tech.pegasys.pantheon.consensus.clique.blockcreation; package tech.pegasys.pantheon.consensus.clique.blockcreation;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.ValidatorProvider; import tech.pegasys.pantheon.consensus.common.ValidatorProvider;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.blockcreation.DefaultBlockScheduler; import tech.pegasys.pantheon.ethereum.blockcreation.DefaultBlockScheduler;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;

@ -14,8 +14,8 @@ package tech.pegasys.pantheon.consensus.clique.blockcreation;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;

@ -14,7 +14,6 @@ package tech.pegasys.pantheon.consensus.clique.jsonrpc;
import tech.pegasys.pantheon.consensus.clique.CliqueBlockInterface; import tech.pegasys.pantheon.consensus.clique.CliqueBlockInterface;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSigners; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSigners;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSignersAtHash; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSignersAtHash;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueProposals; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueProposals;
@ -22,6 +21,7 @@ import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.Discard;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.Propose; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.Propose;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
@ -73,6 +73,7 @@ public class CliqueJsonRpcMethodsFactory {
final EpochManager epochManager = context.getConsensusState().getEpochManager(); final EpochManager epochManager = context.getConsensusState().getEpochManager();
final VoteTallyUpdater voteTallyUpdater = final VoteTallyUpdater voteTallyUpdater =
new VoteTallyUpdater(epochManager, new CliqueBlockInterface()); new VoteTallyUpdater(epochManager, new CliqueBlockInterface());
return new VoteTallyCache(blockchain, voteTallyUpdater, epochManager); return new VoteTallyCache(
blockchain, voteTallyUpdater, epochManager, new CliqueBlockInterface());
} }
} }

@ -12,7 +12,7 @@
*/ */
package tech.pegasys.pantheon.consensus.clique.jsonrpc.methods; package tech.pegasys.pantheon.consensus.clique.jsonrpc.methods;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod;

@ -12,7 +12,7 @@
*/ */
package tech.pegasys.pantheon.consensus.clique.jsonrpc.methods; package tech.pegasys.pantheon.consensus.clique.jsonrpc.methods;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;

@ -19,6 +19,7 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;

@ -22,6 +22,7 @@ import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.create
import tech.pegasys.pantheon.consensus.clique.headervalidationrules.SignerRateLimitValidationRule; import tech.pegasys.pantheon.consensus.clique.headervalidationrules.SignerRateLimitValidationRule;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;

@ -26,10 +26,10 @@ import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.CliqueHelpers; import tech.pegasys.pantheon.consensus.clique.CliqueHelpers;
import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule;
import tech.pegasys.pantheon.consensus.clique.TestHelpers; import tech.pegasys.pantheon.consensus.clique.TestHelpers;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.GenesisState; import tech.pegasys.pantheon.ethereum.chain.GenesisState;

@ -17,8 +17,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler.BlockCreationTimeResult; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler.BlockCreationTimeResult;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;

@ -22,10 +22,10 @@ import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;

@ -25,8 +25,8 @@ import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.create
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueMiningTracker; import tech.pegasys.pantheon.consensus.clique.CliqueMiningTracker;
import tech.pegasys.pantheon.consensus.clique.TestHelpers; 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.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;

@ -17,8 +17,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.AddressHelpers; import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;

@ -20,9 +20,9 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.CliqueBlockHashing; import tech.pegasys.pantheon.consensus.clique.CliqueBlockHashing;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1; import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.crypto.SECP256K1.Signature;

@ -20,9 +20,9 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.TestHelpers; import tech.pegasys.pantheon.consensus.clique.TestHelpers;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;

@ -19,8 +19,8 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.core.Address.fromHexString; import static tech.pegasys.pantheon.ethereum.core.Address.fromHexString;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;

@ -19,8 +19,8 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.core.Address.fromHexString; import static tech.pegasys.pantheon.ethereum.core.Address.fromHexString;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;

@ -10,13 +10,10 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.consensus.clique; package tech.pegasys.pantheon.consensus.common;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
@ -37,17 +34,26 @@ public class VoteTallyCache {
private final Cache<Hash, VoteTally> voteTallyCache = private final Cache<Hash, VoteTally> voteTallyCache =
CacheBuilder.newBuilder().maximumSize(100).build(); CacheBuilder.newBuilder().maximumSize(100).build();
private BlockInterface blockInterface;
public VoteTallyCache( public VoteTallyCache(
final Blockchain blockchain, final Blockchain blockchain,
final VoteTallyUpdater voteTallyUpdater, final VoteTallyUpdater voteTallyUpdater,
final EpochManager epochManager) { final EpochManager epochManager,
final BlockInterface blockInterface) {
checkNotNull(blockchain); checkNotNull(blockchain);
checkNotNull(voteTallyUpdater); checkNotNull(voteTallyUpdater);
checkNotNull(epochManager); checkNotNull(epochManager);
checkNotNull(blockInterface);
this.blockchain = blockchain; this.blockchain = blockchain;
this.voteTallyUpdater = voteTallyUpdater; this.voteTallyUpdater = voteTallyUpdater;
this.epochManager = epochManager; this.epochManager = epochManager;
this.blockInterface = blockInterface;
}
public VoteTally getVoteTallyAtHead() {
return getVoteTallyAfterBlock(blockchain.getChainHeadHeader());
} }
/** /**
@ -94,7 +100,6 @@ public class VoteTallyCache {
private VoteTally getValidatorsAfter(final BlockHeader header) { private VoteTally getValidatorsAfter(final BlockHeader header) {
if (epochManager.isEpochBlock(header.getNumber())) { if (epochManager.isEpochBlock(header.getNumber())) {
final CliqueBlockInterface blockInterface = new CliqueBlockInterface();
return new VoteTally(blockInterface.validatorsInBlock(header)); return new VoteTally(blockInterface.validatorsInBlock(header));
} }

@ -10,7 +10,7 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.consensus.clique; package tech.pegasys.pantheon.consensus.common;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -24,11 +24,6 @@ import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.common.VoteType.DROP; import static tech.pegasys.pantheon.consensus.common.VoteType.DROP;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain;
import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.ValidatorVote;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.AddressHelpers; import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
@ -39,7 +34,6 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -52,7 +46,7 @@ import org.mockito.ArgumentCaptor;
public class VoteTallyCacheTest { public class VoteTallyCacheTest {
BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); private final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
private Block createEmptyBlock(final long blockNumber, final Hash parentHash) { private Block createEmptyBlock(final long blockNumber, final Hash parentHash) {
headerBuilder.number(blockNumber).parentHash(parentHash).coinbase(AddressHelpers.ofValue(0)); headerBuilder.number(blockNumber).parentHash(parentHash).coinbase(AddressHelpers.ofValue(0));
@ -60,24 +54,21 @@ public class VoteTallyCacheTest {
headerBuilder.buildHeader(), new BlockBody(Lists.emptyList(), Lists.emptyList())); headerBuilder.buildHeader(), new BlockBody(Lists.emptyList(), Lists.emptyList()));
} }
MutableBlockchain blockChain; private MutableBlockchain blockChain;
private Block genesisBlock; private Block genesisBlock;
private Block block_1; private Block block_1;
private Block block_2; private Block block_2;
private final List<Address> validators = Lists.newArrayList(); private final List<Address> validators = Lists.newArrayList();
private final BlockInterface blockInterface = mock(BlockInterface.class);
@Before @Before
public void constructThreeBlockChain() { public void constructThreeBlockChain() {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
validators.add(AddressHelpers.ofValue(i)); validators.add(AddressHelpers.ofValue(i));
} }
headerBuilder.extraData( headerBuilder.extraData(BytesValue.wrap(new byte[32]));
new CliqueExtraData(
BytesValue.wrap(new byte[32]),
Signature.create(BigInteger.TEN, BigInteger.TEN, (byte) 1),
validators)
.encode());
genesisBlock = createEmptyBlock(0, Hash.ZERO); genesisBlock = createEmptyBlock(0, Hash.ZERO);
@ -88,13 +79,15 @@ public class VoteTallyCacheTest {
blockChain.appendBlock(block_1, Lists.emptyList()); blockChain.appendBlock(block_1, Lists.emptyList());
blockChain.appendBlock(block_2, Lists.emptyList()); blockChain.appendBlock(block_2, Lists.emptyList());
when(blockInterface.validatorsInBlock(any())).thenReturn(validators);
} }
@Test @Test
public void parentBlockVoteTallysAreCachedWhenChildVoteTallyRequested() { public void parentBlockVoteTallysAreCachedWhenChildVoteTallyRequested() {
final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class); final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class);
final VoteTallyCache cache = final VoteTallyCache cache =
new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000)); new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000), blockInterface);
// The votetallyUpdater should be invoked for the requested block, and all parents including // The votetallyUpdater should be invoked for the requested block, and all parents including
// the epoch (genesis) block. // the epoch (genesis) block.
@ -120,7 +113,7 @@ public class VoteTallyCacheTest {
public void exceptionThrownIfNoParentBlockExists() { public void exceptionThrownIfNoParentBlockExists() {
final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class); final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class);
final VoteTallyCache cache = final VoteTallyCache cache =
new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000)); new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000), blockInterface);
final Block orphanBlock = createEmptyBlock(4, Hash.ZERO); final Block orphanBlock = createEmptyBlock(4, Hash.ZERO);
@ -134,7 +127,7 @@ public class VoteTallyCacheTest {
public void walkBackStopsWhenACachedVoteTallyIsFound() { public void walkBackStopsWhenACachedVoteTallyIsFound() {
final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class); final VoteTallyUpdater tallyUpdater = mock(VoteTallyUpdater.class);
final VoteTallyCache cache = final VoteTallyCache cache =
new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000)); new VoteTallyCache(blockChain, tallyUpdater, new EpochManager(30_000), blockInterface);
// Load the Cache up to block_2 // Load the Cache up to block_2
cache.getVoteTallyAfterBlock(block_2.getHeader()); cache.getVoteTallyAfterBlock(block_2.getHeader());
@ -159,7 +152,6 @@ public class VoteTallyCacheTest {
@Test @Test
public void integrationTestingVotesBeingApplied() { public void integrationTestingVotesBeingApplied() {
final EpochManager epochManager = new EpochManager(30_000); final EpochManager epochManager = new EpochManager(30_000);
final CliqueBlockInterface blockInterface = mock(CliqueBlockInterface.class);
final VoteTallyUpdater tallyUpdater = new VoteTallyUpdater(epochManager, blockInterface); final VoteTallyUpdater tallyUpdater = new VoteTallyUpdater(epochManager, blockInterface);
when(blockInterface.extractVoteFromHeader(block_1.getHeader())) when(blockInterface.extractVoteFromHeader(block_1.getHeader()))
@ -168,7 +160,8 @@ public class VoteTallyCacheTest {
when(blockInterface.extractVoteFromHeader(block_2.getHeader())) when(blockInterface.extractVoteFromHeader(block_2.getHeader()))
.thenReturn(Optional.of(new ValidatorVote(DROP, validators.get(1), validators.get(2)))); .thenReturn(Optional.of(new ValidatorVote(DROP, validators.get(1), validators.get(2))));
final VoteTallyCache cache = new VoteTallyCache(blockChain, tallyUpdater, epochManager); final VoteTallyCache cache =
new VoteTallyCache(blockChain, tallyUpdater, epochManager, blockInterface);
VoteTally voteTally = cache.getVoteTallyAfterBlock(block_1.getHeader()); VoteTally voteTally = cache.getVoteTallyAfterBlock(block_1.getHeader());
assertThat(voteTally.getValidators()).containsAll(validators); assertThat(voteTally.getValidators()).containsAll(validators);

@ -55,6 +55,8 @@ dependencies {
testImplementation 'org.awaitility:awaitility' testImplementation 'org.awaitility:awaitility'
testImplementation 'org.assertj:assertj-core' testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core' testImplementation 'org.mockito:mockito-core'
testSupportImplementation 'org.mockito:mockito-core'
} }

@ -21,7 +21,7 @@ import tech.pegasys.pantheon.config.StubGenesisConfigOptions;
import tech.pegasys.pantheon.consensus.common.BlockInterface; import tech.pegasys.pantheon.consensus.common.BlockInterface;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.consensus.ibft.BlockTimer; import tech.pegasys.pantheon.consensus.ibft.BlockTimer;
import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer; import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer;
@ -249,14 +249,19 @@ public class TestContextBuilder {
final EpochManager epochManager = new EpochManager(EPOCH_LENGTH); final EpochManager epochManager = new EpochManager(EPOCH_LENGTH);
final BlockInterface blockInterface = new IbftBlockInterface(); final BlockInterface blockInterface = new IbftBlockInterface();
final VoteTally voteTally =
new VoteTallyUpdater(epochManager, blockInterface).buildVoteTallyFromBlockchain(blockChain); final VoteTallyCache voteTallyCache =
new VoteTallyCache(
blockChain,
new VoteTallyUpdater(epochManager, blockInterface),
epochManager,
new IbftBlockInterface());
final VoteProposer voteProposer = new VoteProposer(); final VoteProposer voteProposer = new VoteProposer();
final ProtocolContext<IbftContext> protocolContext = final ProtocolContext<IbftContext> protocolContext =
new ProtocolContext<>( new ProtocolContext<>(
blockChain, worldStateArchive, new IbftContext(voteTally, voteProposer)); blockChain, worldStateArchive, new IbftContext(voteTallyCache, voteProposer));
final IbftBlockCreatorFactory blockCreatorFactory = final IbftBlockCreatorFactory blockCreatorFactory =
new IbftBlockCreatorFactory( new IbftBlockCreatorFactory(
@ -268,11 +273,11 @@ public class TestContextBuilder {
Util.publicKeyToAddress(nodeKeys.getPublicKey())); Util.publicKeyToAddress(nodeKeys.getPublicKey()));
final ProposerSelector proposerSelector = final ProposerSelector proposerSelector =
new ProposerSelector(blockChain, voteTally, blockInterface, true); new ProposerSelector(blockChain, blockInterface, true);
final IbftFinalState finalState = final IbftFinalState finalState =
new IbftFinalState( new IbftFinalState(
voteTally, protocolContext.getConsensusState().getVoteTallyCache(),
nodeKeys, nodeKeys,
Util.publicKeyToAddress(nodeKeys.getPublicKey()), Util.publicKeyToAddress(nodeKeys.getPublicKey()),
proposerSelector, proposerSelector,

@ -1,68 +0,0 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.consensus.ibft;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockImporter;
import tech.pegasys.pantheon.ethereum.core.TransactionReceipt;
import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode;
import java.util.List;
/**
* The IBFT BlockImporter implementation. Adds votes to VoteTally as blocks are added to the chain.
*/
public class IbftBlockImporter implements BlockImporter<IbftContext> {
private final BlockImporter<IbftContext> delegate;
private final VoteTallyUpdater voteTallyUpdater;
public IbftBlockImporter(
final BlockImporter<IbftContext> delegate, final VoteTallyUpdater voteTallyUpdater) {
this.delegate = delegate;
this.voteTallyUpdater = voteTallyUpdater;
}
@Override
public boolean importBlock(
final ProtocolContext<IbftContext> context,
final Block block,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode) {
final boolean result =
delegate.importBlock(context, block, headerValidationMode, ommerValidationMode);
updateVoteTally(result, block.getHeader(), context);
return result;
}
@Override
public boolean fastImportBlock(
final ProtocolContext<IbftContext> context,
final Block block,
final List<TransactionReceipt> receipts,
final HeaderValidationMode headerValidationMode) {
final boolean result = delegate.fastImportBlock(context, block, receipts, headerValidationMode);
updateVoteTally(result, block.getHeader(), context);
return result;
}
private void updateVoteTally(
final boolean result, final BlockHeader header, final ProtocolContext<IbftContext> context) {
if (result) {
voteTallyUpdater.updateForBlock(header, context.getConsensusState().getVoteTally());
}
}
}

@ -13,21 +13,21 @@
package tech.pegasys.pantheon.consensus.ibft; package tech.pegasys.pantheon.consensus.ibft;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
/** Holds the IBFT specific mutable state. */ /** Holds the IBFT specific mutable state. */
public class IbftContext { public class IbftContext {
private final VoteTally voteTally; private final VoteTallyCache voteTallyCache;
private final VoteProposer voteProposer; private final VoteProposer voteProposer;
public IbftContext(final VoteTally voteTally, final VoteProposer voteProposer) { public IbftContext(final VoteTallyCache voteTallyCache, final VoteProposer voteProposer) {
this.voteTally = voteTally; this.voteTallyCache = voteTallyCache;
this.voteProposer = voteProposer; this.voteProposer = voteProposer;
} }
public VoteTally getVoteTally() { public VoteTallyCache getVoteTallyCache() {
return voteTally; return voteTallyCache;
} }
public VoteProposer getVoteProposer() { public VoteProposer getVoteProposer() {

@ -17,7 +17,6 @@ import static tech.pegasys.pantheon.consensus.ibft.IbftBlockHeaderValidationRule
import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.config.IbftConfigOptions; import tech.pegasys.pantheon.config.IbftConfigOptions;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.ethereum.MainnetBlockValidator; import tech.pegasys.pantheon.ethereum.MainnetBlockValidator;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
@ -43,25 +42,20 @@ public class IbftProtocolSchedule {
return new ProtocolScheduleBuilder<>( return new ProtocolScheduleBuilder<>(
config, config,
DEFAULT_CHAIN_ID, DEFAULT_CHAIN_ID,
builder -> applyIbftChanges(blockPeriod, epochManager, builder), builder -> applyIbftChanges(blockPeriod, builder),
PrivacyParameters.noPrivacy()) PrivacyParameters.noPrivacy())
.createProtocolSchedule(); .createProtocolSchedule();
} }
private static ProtocolSpecBuilder<IbftContext> applyIbftChanges( private static ProtocolSpecBuilder<IbftContext> applyIbftChanges(
final long secondsBetweenBlocks, final long secondsBetweenBlocks, final ProtocolSpecBuilder<Void> builder) {
final EpochManager epochManager,
final ProtocolSpecBuilder<Void> builder) {
return builder return builder
.<IbftContext>changeConsensusContextType( .<IbftContext>changeConsensusContextType(
difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks),
difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks),
MainnetBlockBodyValidator::new, MainnetBlockBodyValidator::new,
MainnetBlockValidator::new, MainnetBlockValidator::new,
(blockValidator) -> MainnetBlockImporter::new,
new IbftBlockImporter(
new MainnetBlockImporter<>(blockValidator),
new VoteTallyUpdater(epochManager, new IbftBlockInterface())),
(time, parent, protocolContext) -> BigInteger.ONE) (time, parent, protocolContext) -> BigInteger.ONE)
.blockReward(Wei.ZERO) .blockReward(Wei.ZERO)
.blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain); .blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain);

@ -63,7 +63,7 @@ public class IbftBlockCreatorFactory {
public IbftBlockCreator create(final BlockHeader parentHeader, final int round) { public IbftBlockCreator create(final BlockHeader parentHeader, final int round) {
return new IbftBlockCreator( return new IbftBlockCreator(
localAddress, localAddress,
ph -> createExtraData(round), ph -> createExtraData(round, ph),
pendingTransactions, pendingTransactions,
protocolContext, protocolContext,
protocolSchedule, protocolSchedule,
@ -84,8 +84,13 @@ public class IbftBlockCreatorFactory {
return minTransactionGasPrice; return minTransactionGasPrice;
} }
public BytesValue createExtraData(final int round) { public BytesValue createExtraData(final int round, final BlockHeader parentHeader) {
final VoteTally voteTally = protocolContext.getConsensusState().getVoteTally(); final VoteTally voteTally =
protocolContext
.getConsensusState()
.getVoteTallyCache()
.getVoteTallyAfterBlock(parentHeader);
final Optional<ValidatorVote> proposal = final Optional<ValidatorVote> proposal =
protocolContext.getConsensusState().getVoteProposer().getVote(localAddress, voteTally); protocolContext.getConsensusState().getVoteProposer().getVote(localAddress, voteTally);

@ -22,6 +22,7 @@ import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.Optional; import java.util.Optional;
@ -46,9 +47,6 @@ public class ProposerSelector {
private final Blockchain blockchain; private final Blockchain blockchain;
/** Provides the current list of validators */
private final ValidatorProvider validators;
/** /**
* If set, will cause the proposer to change on successful addition of a block. Otherwise, the * If set, will cause the proposer to change on successful addition of a block. Otherwise, the
* previously successful proposer will propose the next block as well. * previously successful proposer will propose the next block as well.
@ -59,11 +57,9 @@ public class ProposerSelector {
public ProposerSelector( public ProposerSelector(
final Blockchain blockchain, final Blockchain blockchain,
final ValidatorProvider validators,
final BlockInterface blockInterface, final BlockInterface blockInterface,
final boolean changeEachBlock) { final boolean changeEachBlock) {
this.blockchain = blockchain; this.blockchain = blockchain;
this.validators = validators;
this.blockInterface = blockInterface; this.blockInterface = blockInterface;
this.changeEachBlock = changeEachBlock; this.changeEachBlock = changeEachBlock;
} }
@ -75,17 +71,24 @@ public class ProposerSelector {
* @return The address of the node which is to propose a block for the provided Round. * @return The address of the node which is to propose a block for the provided Round.
*/ */
public Address selectProposerForRound(final ConsensusRoundIdentifier roundIdentifier) { public Address selectProposerForRound(final ConsensusRoundIdentifier roundIdentifier) {
checkArgument(roundIdentifier.getRoundNumber() >= 0); checkArgument(roundIdentifier.getRoundNumber() >= 0);
checkArgument(roundIdentifier.getSequenceNumber() > 0); checkArgument(roundIdentifier.getSequenceNumber() > 0);
final long prevBlockNumber = roundIdentifier.getSequenceNumber() - 1; final long prevBlockNumber = roundIdentifier.getSequenceNumber() - 1;
final Address prevBlockProposer = getProposerOfBlock(prevBlockNumber); final Optional<BlockHeader> maybeParentHeader = blockchain.getBlockHeader(prevBlockNumber);
if (!maybeParentHeader.isPresent()) {
LOG.trace("Unable to determine proposer for requested block");
throw new RuntimeException("Unable to determine past proposer");
}
if (!validators.getValidators().contains(prevBlockProposer)) { final BlockHeader blockHeader = maybeParentHeader.get();
return handleMissingProposer(prevBlockProposer, roundIdentifier); final Address prevBlockProposer = blockInterface.getProposerOfBlock(blockHeader);
final Collection<Address> validatorsForRound = blockInterface.validatorsInBlock(blockHeader);
if (!validatorsForRound.contains(prevBlockProposer)) {
return handleMissingProposer(prevBlockProposer, validatorsForRound, roundIdentifier);
} else { } else {
return handleWithExistingProposer(prevBlockProposer, roundIdentifier); return handleWithExistingProposer(prevBlockProposer, validatorsForRound, roundIdentifier);
} }
} }
@ -96,8 +99,10 @@ public class ProposerSelector {
* <p>And validators will change from there. * <p>And validators will change from there.
*/ */
private Address handleMissingProposer( private Address handleMissingProposer(
final Address prevBlockProposer, final ConsensusRoundIdentifier roundIdentifier) { final Address prevBlockProposer,
final NavigableSet<Address> validatorSet = new TreeSet<>(validators.getValidators()); final Collection<Address> validatorsForRound,
final ConsensusRoundIdentifier roundIdentifier) {
final NavigableSet<Address> validatorSet = new TreeSet<>(validatorsForRound);
final SortedSet<Address> latterValidators = validatorSet.tailSet(prevBlockProposer, false); final SortedSet<Address> latterValidators = validatorSet.tailSet(prevBlockProposer, false);
final Address nextProposer; final Address nextProposer;
if (latterValidators.isEmpty()) { if (latterValidators.isEmpty()) {
@ -108,57 +113,37 @@ public class ProposerSelector {
// Else, use the first validator after the dropped entry. // Else, use the first validator after the dropped entry.
nextProposer = latterValidators.first(); nextProposer = latterValidators.first();
} }
return calculateRoundSpecificValidator(nextProposer, roundIdentifier.getRoundNumber()); return calculateRoundSpecificValidator(
nextProposer, validatorsForRound, roundIdentifier.getRoundNumber());
} }
/** /**
* If the previous Proposer is still a validator - determine what offset should be applied for the * If the previous Proposer is still a validator - determine what offset should be applied for the
* given round - factoring in a proposer change on the new block. * given round - factoring in a proposer change on the new block.
*
* @param prevBlockProposer
* @param roundIdentifier
* @return
*/ */
private Address handleWithExistingProposer( private Address handleWithExistingProposer(
final Address prevBlockProposer, final ConsensusRoundIdentifier roundIdentifier) { final Address prevBlockProposer,
final Collection<Address> validatorsForRound,
final ConsensusRoundIdentifier roundIdentifier) {
int indexOffsetFromPrevBlock = roundIdentifier.getRoundNumber(); int indexOffsetFromPrevBlock = roundIdentifier.getRoundNumber();
if (changeEachBlock) { if (changeEachBlock) {
indexOffsetFromPrevBlock += 1; indexOffsetFromPrevBlock += 1;
} }
return calculateRoundSpecificValidator(prevBlockProposer, indexOffsetFromPrevBlock); return calculateRoundSpecificValidator(
prevBlockProposer, validatorsForRound, indexOffsetFromPrevBlock);
} }
/** /**
* Given Round 0 of the given height should start from given proposer (baseProposer) - determine * Given Round 0 of the given height should start from given proposer (baseProposer) - determine
* which validator should be used given the indexOffset. * which validator should be used given the indexOffset.
*
* @param baseProposer
* @param indexOffset
* @return
*/ */
private Address calculateRoundSpecificValidator( private Address calculateRoundSpecificValidator(
final Address baseProposer, final int indexOffset) { final Address baseProposer,
final List<Address> currentValidatorList = new ArrayList<>(validators.getValidators()); final Collection<Address> validatorsForRound,
final int indexOffset) {
final List<Address> currentValidatorList = new ArrayList<>(validatorsForRound);
final int prevProposerIndex = currentValidatorList.indexOf(baseProposer); final int prevProposerIndex = currentValidatorList.indexOf(baseProposer);
final int roundValidatorIndex = (prevProposerIndex + indexOffset) % currentValidatorList.size(); final int roundValidatorIndex = (prevProposerIndex + indexOffset) % currentValidatorList.size();
return currentValidatorList.get(roundValidatorIndex); return currentValidatorList.get(roundValidatorIndex);
} }
/**
* Determines the proposer of an existing block, based on the proposer signature in the extra
* data.
*
* @param blockNumber The index of the block in the chain being queried.
* @return The unique identifier fo the node which proposed the block number in question.
*/
private Address getProposerOfBlock(final long blockNumber) {
final Optional<BlockHeader> maybeBlockHeader = blockchain.getBlockHeader(blockNumber);
if (maybeBlockHeader.isPresent()) {
final BlockHeader blockHeader = maybeBlockHeader.get();
return blockInterface.getProposerOfBlock(blockHeader);
} else {
LOG.trace("Unable to determine proposer for requested block");
throw new RuntimeException("Unable to determine past proposer");
}
}
} }

@ -38,8 +38,9 @@ public class IbftCoinbaseValidationRule implements AttachedBlockHeaderValidation
final BlockHeader parent, final BlockHeader parent,
final ProtocolContext<IbftContext> context) { final ProtocolContext<IbftContext> context) {
final ValidatorProvider validatorProvider = context.getConsensusState().getVoteTally(); final ValidatorProvider validatorProvider =
Address proposer = header.getCoinbase(); context.getConsensusState().getVoteTallyCache().getVoteTallyAfterBlock(parent);
final Address proposer = header.getCoinbase();
final Collection<Address> storedValidators = validatorProvider.getValidators(); final Collection<Address> storedValidators = validatorProvider.getValidators();

@ -47,12 +47,13 @@ public class IbftCommitSealsValidationRule
final BlockHeader header, final BlockHeader header,
final BlockHeader parent, final BlockHeader parent,
final ProtocolContext<IbftContext> protocolContext) { final ProtocolContext<IbftContext> protocolContext) {
final ValidatorProvider validatorProvider = protocolContext.getConsensusState().getVoteTally(); final ValidatorProvider validatorProvider =
protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAfterBlock(parent);
final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData()); final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData());
final List<Address> committers = final List<Address> committers =
IbftBlockHashing.recoverCommitterAddresses(header, ibftExtraData); IbftBlockHashing.recoverCommitterAddresses(header, ibftExtraData);
List<Address> committersWithoutDuplicates = new ArrayList<>(new HashSet<>(committers)); final List<Address> committersWithoutDuplicates = new ArrayList<>(new HashSet<>(committers));
if (committers.size() != committersWithoutDuplicates.size()) { if (committers.size() != committersWithoutDuplicates.size()) {
LOGGER.trace("Duplicated seals found in header."); LOGGER.trace("Duplicated seals found in header.");

@ -22,6 +22,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.AttachedBlockHeaderValidationRule;
import tech.pegasys.pantheon.ethereum.rlp.RLPException; import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import java.util.Collection; import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -41,29 +43,23 @@ public class IbftValidatorsValidationRule
final BlockHeader header, final BlockHeader header,
final BlockHeader parent, final BlockHeader parent,
final ProtocolContext<IbftContext> context) { final ProtocolContext<IbftContext> context) {
return validateExtraData(header, context);
}
/**
* Responsible for determining the validity of the extra data field. Ensures:
*
* <ul>
* <li>Bytes in the extra data field can be decoded as per IBFT specification
* <li>Validators in block matches that tracked in memory.
* </ul>
*
* @param header the block header containing the extraData to be validated.
* @return True if the extraData successfully produces an IstanbulExtraData object, false
* otherwise
*/
private boolean validateExtraData(
final BlockHeader header, final ProtocolContext<IbftContext> context) {
try { try {
final ValidatorProvider validatorProvider = context.getConsensusState().getVoteTally(); final ValidatorProvider validatorProvider =
context.getConsensusState().getVoteTallyCache().getVoteTallyAfterBlock(parent);
final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData()); final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData());
final Collection<Address> storedValidators = validatorProvider.getValidators(); final SortedSet<Address> sortedReportedValidators =
new TreeSet<>(ibftExtraData.getValidators());
if (!Iterables.elementsEqual(ibftExtraData.getValidators(), sortedReportedValidators)) {
LOGGER.trace(
"Validators are not sorted in ascending order. Expected {} but got {}.",
sortedReportedValidators,
ibftExtraData.getValidators());
return false;
}
final Collection<Address> storedValidators = validatorProvider.getValidators();
if (!Iterables.elementsEqual(ibftExtraData.getValidators(), storedValidators)) { if (!Iterables.elementsEqual(ibftExtraData.getValidators(), storedValidators)) {
LOGGER.trace( LOGGER.trace(
"Incorrect validators. Expected {} but got {}.", "Incorrect validators. Expected {} but got {}.",

@ -12,7 +12,7 @@
*/ */
package tech.pegasys.pantheon.consensus.ibft.network; package tech.pegasys.pantheon.consensus.ibft.network;
import tech.pegasys.pantheon.consensus.common.ValidatorProvider; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
@ -38,10 +38,10 @@ public class ValidatorPeers implements ValidatorMulticaster, PeerConnectionTrack
private static final String PROTOCOL_NAME = "IBF"; private static final String PROTOCOL_NAME = "IBF";
private final Map<Address, PeerConnection> peerConnections = Maps.newConcurrentMap(); private final Map<Address, PeerConnection> peerConnections = Maps.newConcurrentMap();
private final ValidatorProvider validatorProvider; private final VoteTallyCache voteTallyCache;
public ValidatorPeers(final ValidatorProvider validatorProvider) { public ValidatorPeers(final VoteTallyCache voteTallyCache) {
this.validatorProvider = validatorProvider; this.voteTallyCache = voteTallyCache;
} }
@Override @Override
@ -58,14 +58,13 @@ public class ValidatorPeers implements ValidatorMulticaster, PeerConnectionTrack
@Override @Override
public void send(final MessageData message) { public void send(final MessageData message) {
final Collection<Address> validators = validatorProvider.getValidators(); sendMessageToSpecificAddresses(getLatestValidators(), message);
sendMessageToSpecificAddresses(validators, message);
} }
@Override @Override
public void send(final MessageData message, final Collection<Address> blackList) { public void send(final MessageData message, final Collection<Address> blackList) {
final Collection<Address> includedValidators = final Collection<Address> includedValidators =
validatorProvider.getValidators().stream() getLatestValidators().stream()
.filter(a -> !blackList.contains(a)) .filter(a -> !blackList.contains(a))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
sendMessageToSpecificAddresses(includedValidators, message); sendMessageToSpecificAddresses(includedValidators, message);
@ -90,4 +89,8 @@ public class ValidatorPeers implements ValidatorMulticaster, PeerConnectionTrack
} }
}); });
} }
private Collection<Address> getLatestValidators() {
return voteTallyCache.getVoteTallyAtHead().getValidators();
}
} }

@ -90,14 +90,15 @@ public class IbftBlockHeightManager implements BlockHeightManager {
this.roundChangeManager = roundChangeManager; this.roundChangeManager = roundChangeManager;
this.finalState = finalState; this.finalState = finalState;
newRoundMessageValidator = messageValidatorFactory.createNewRoundValidator(getChainHeight()); newRoundMessageValidator =
messageValidatorFactory.createNewRoundValidator(getChainHeight(), parentHeader);
roundStateCreator = roundStateCreator =
(roundIdentifier) -> (roundIdentifier) ->
new RoundState( new RoundState(
roundIdentifier, roundIdentifier,
finalState.getQuorum(), finalState.getQuorum(),
messageValidatorFactory.createMessageValidator(roundIdentifier)); messageValidatorFactory.createMessageValidator(roundIdentifier, parentHeader));
} }
@Override @Override

@ -50,7 +50,7 @@ public class IbftBlockHeightManagerFactory {
new RoundChangeManager( new RoundChangeManager(
IbftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()), IbftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()),
messageValidatorFactory.createRoundChangeMessageValidator( messageValidatorFactory.createRoundChangeMessageValidator(
parentHeader.getNumber() + 1L)), parentHeader.getNumber() + 1L, parentHeader)),
roundFactory, roundFactory,
finalState.getClock(), finalState.getClock(),
messageValidatorFactory); messageValidatorFactory);

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.consensus.ibft.statemachine;
import static tech.pegasys.pantheon.consensus.ibft.IbftHelpers.calculateRequiredValidatorQuorum; import static tech.pegasys.pantheon.consensus.ibft.IbftHelpers.calculateRequiredValidatorQuorum;
import tech.pegasys.pantheon.consensus.common.ValidatorProvider; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.ibft.BlockTimer; import tech.pegasys.pantheon.consensus.ibft.BlockTimer;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.RoundTimer; import tech.pegasys.pantheon.consensus.ibft.RoundTimer;
@ -31,11 +31,10 @@ import java.util.Collection;
/** This is the full data set, or context, required for many of the aspects of the IBFT workflow. */ /** This is the full data set, or context, required for many of the aspects of the IBFT workflow. */
public class IbftFinalState { public class IbftFinalState {
private final ValidatorProvider validatorProvider; private final VoteTallyCache voteTallyCache;
private final KeyPair nodeKeys; private final KeyPair nodeKeys;
private final Address localAddress; private final Address localAddress;
private final ProposerSelector proposerSelector; private final ProposerSelector proposerSelector;
private final ValidatorMulticaster validatorMulticaster;
private final RoundTimer roundTimer; private final RoundTimer roundTimer;
private final BlockTimer blockTimer; private final BlockTimer blockTimer;
private final IbftBlockCreatorFactory blockCreatorFactory; private final IbftBlockCreatorFactory blockCreatorFactory;
@ -44,7 +43,7 @@ public class IbftFinalState {
private final Clock clock; private final Clock clock;
public IbftFinalState( public IbftFinalState(
final ValidatorProvider validatorProvider, final VoteTallyCache voteTallyCache,
final KeyPair nodeKeys, final KeyPair nodeKeys,
final Address localAddress, final Address localAddress,
final ProposerSelector proposerSelector, final ProposerSelector proposerSelector,
@ -54,11 +53,10 @@ public class IbftFinalState {
final IbftBlockCreatorFactory blockCreatorFactory, final IbftBlockCreatorFactory blockCreatorFactory,
final MessageFactory messageFactory, final MessageFactory messageFactory,
final Clock clock) { final Clock clock) {
this.validatorProvider = validatorProvider; this.voteTallyCache = voteTallyCache;
this.nodeKeys = nodeKeys; this.nodeKeys = nodeKeys;
this.localAddress = localAddress; this.localAddress = localAddress;
this.proposerSelector = proposerSelector; this.proposerSelector = proposerSelector;
this.validatorMulticaster = validatorMulticaster;
this.roundTimer = roundTimer; this.roundTimer = roundTimer;
this.blockTimer = blockTimer; this.blockTimer = blockTimer;
this.blockCreatorFactory = blockCreatorFactory; this.blockCreatorFactory = blockCreatorFactory;
@ -68,11 +66,11 @@ public class IbftFinalState {
} }
public int getQuorum() { public int getQuorum() {
return calculateRequiredValidatorQuorum(validatorProvider.getValidators().size()); return calculateRequiredValidatorQuorum(getValidators().size());
} }
public Collection<Address> getValidators() { public Collection<Address> getValidators() {
return validatorProvider.getValidators(); return voteTallyCache.getVoteTallyAtHead().getValidators();
} }
public KeyPair getNodeKeys() { public KeyPair getNodeKeys() {

@ -54,7 +54,7 @@ public class IbftRoundFactory {
new RoundState( new RoundState(
roundIdentifier, roundIdentifier,
finalState.getQuorum(), finalState.getQuorum(),
messageValidatorFactory.createMessageValidator(roundIdentifier)); messageValidatorFactory.createMessageValidator(roundIdentifier, parentHeader));
return createNewRoundWithState(parentHeader, roundState); return createNewRoundWithState(parentHeader, roundState);
} }

@ -21,6 +21,7 @@ import tech.pegasys.pantheon.consensus.ibft.blockcreation.ProposerSelector;
import tech.pegasys.pantheon.ethereum.BlockValidator; import tech.pegasys.pantheon.ethereum.BlockValidator;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import java.util.Collection; import java.util.Collection;
@ -40,33 +41,42 @@ public class MessageValidatorFactory {
this.protocolContext = protocolContext; this.protocolContext = protocolContext;
} }
private Collection<Address> getValidatorsAfterBlock(final BlockHeader parentHeader) {
return protocolContext
.getConsensusState()
.getVoteTallyCache()
.getVoteTallyAfterBlock(parentHeader)
.getValidators();
}
private SignedDataValidator createSignedDataValidator( private SignedDataValidator createSignedDataValidator(
final ConsensusRoundIdentifier roundIdentifier) { final ConsensusRoundIdentifier roundIdentifier, final BlockHeader parentHeader) {
return new SignedDataValidator( return new SignedDataValidator(
protocolContext.getConsensusState().getVoteTally().getValidators(), getValidatorsAfterBlock(parentHeader),
proposerSelector.selectProposerForRound(roundIdentifier), proposerSelector.selectProposerForRound(roundIdentifier),
roundIdentifier); roundIdentifier);
} }
public MessageValidator createMessageValidator(final ConsensusRoundIdentifier roundIdentifier) { public MessageValidator createMessageValidator(
final ConsensusRoundIdentifier roundIdentifier, final BlockHeader parentHeader) {
final BlockValidator<IbftContext> blockValidator = final BlockValidator<IbftContext> blockValidator =
protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockValidator(); protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockValidator();
return new MessageValidator( return new MessageValidator(
createSignedDataValidator(roundIdentifier), createSignedDataValidator(roundIdentifier, parentHeader),
new ProposalBlockConsistencyValidator(), new ProposalBlockConsistencyValidator(),
blockValidator, blockValidator,
protocolContext); protocolContext);
} }
public RoundChangeMessageValidator createRoundChangeMessageValidator(final long chainHeight) { public RoundChangeMessageValidator createRoundChangeMessageValidator(
final Collection<Address> validators = final long chainHeight, final BlockHeader parentHeader) {
protocolContext.getConsensusState().getVoteTally().getValidators(); final Collection<Address> validators = getValidatorsAfterBlock(parentHeader);
return new RoundChangeMessageValidator( return new RoundChangeMessageValidator(
new RoundChangePayloadValidator( new RoundChangePayloadValidator(
this::createSignedDataValidator, (roundIdentifier) -> createSignedDataValidator(roundIdentifier, parentHeader),
validators, validators,
prepareMessageCountForQuorum( prepareMessageCountForQuorum(
IbftHelpers.calculateRequiredValidatorQuorum(validators.size())), IbftHelpers.calculateRequiredValidatorQuorum(validators.size())),
@ -74,21 +84,23 @@ public class MessageValidatorFactory {
new ProposalBlockConsistencyValidator()); new ProposalBlockConsistencyValidator());
} }
public NewRoundMessageValidator createNewRoundValidator(final long chainHeight) { public NewRoundMessageValidator createNewRoundValidator(
final Collection<Address> validators = final long chainHeight, final BlockHeader parentHeader) {
protocolContext.getConsensusState().getVoteTally().getValidators(); final Collection<Address> validators = getValidatorsAfterBlock(parentHeader);
final BlockValidator<IbftContext> blockValidator = final BlockValidator<IbftContext> blockValidator =
protocolSchedule.getByBlockNumber(chainHeight).getBlockValidator(); protocolSchedule.getByBlockNumber(chainHeight).getBlockValidator();
final RoundChangeCertificateValidator roundChangeCertificateValidator = final RoundChangeCertificateValidator roundChangeCertificateValidator =
new RoundChangeCertificateValidator( new RoundChangeCertificateValidator(
validators, this::createSignedDataValidator, chainHeight); validators,
(roundIdentifier) -> createSignedDataValidator(roundIdentifier, parentHeader),
chainHeight);
return new NewRoundMessageValidator( return new NewRoundMessageValidator(
new NewRoundPayloadValidator( new NewRoundPayloadValidator(
proposerSelector, proposerSelector,
this::createSignedDataValidator, (roundIdentifier) -> createSignedDataValidator(roundIdentifier, parentHeader),
chainHeight, chainHeight,
roundChangeCertificateValidator), roundChangeCertificateValidator),
new ProposalBlockConsistencyValidator(), new ProposalBlockConsistencyValidator(),

@ -0,0 +1,40 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.consensus.ibft;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.ethereum.core.Address;
import java.util.Collection;
public class IbftContextBuilder {
public static IbftContext setupContextWithValidators(final Collection<Address> validators) {
final IbftContext ibftContext = mock(IbftContext.class, withSettings().lenient());
final VoteTallyCache mockCache = mock(VoteTallyCache.class, withSettings().lenient());
final VoteTally mockVoteTally = mock(VoteTally.class, withSettings().lenient());
when(ibftContext.getVoteTallyCache()).thenReturn(mockCache);
when(mockCache.getVoteTallyAfterBlock(any())).thenReturn(mockVoteTally);
when(mockVoteTally.getValidators()).thenReturn(validators);
when(ibftContext.getVoteProposer()).thenReturn(new VoteProposer());
return ibftContext;
}
}

@ -1,28 +0,0 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.consensus.ibft;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address;
import java.util.List;
public class IbftProtocolContextFixture {
public static ProtocolContext<IbftContext> protocolContext(final List<Address> validators) {
return new ProtocolContext<>(
null, null, new IbftContext(new VoteTally(validators), new VoteProposer()));
}
}

@ -15,9 +15,10 @@ package tech.pegasys.pantheon.consensus.ibft;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.consensus.ibft.IbftProtocolContextFixture.protocolContext; import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
@ -28,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -35,6 +37,10 @@ import org.junit.Test;
public class IbftBlockHeaderValidationRulesetFactoryTest { public class IbftBlockHeaderValidationRulesetFactoryTest {
private final ProtocolContext<IbftContext> protocolContext(final Collection<Address> validators) {
return new ProtocolContext<>(null, null, setupContextWithValidators(validators));
}
@Test @Test
public void ibftValidateHeaderPasses() { public void ibftValidateHeaderPasses() {
final KeyPair proposerKeyPair = KeyPair.generate(); final KeyPair proposerKeyPair = KeyPair.generate();

@ -1,107 +0,0 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.consensus.ibft;
import static java.util.Collections.emptyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockBody;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.BlockImporter;
import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import org.junit.Test;
public class IbftBlockImporterTest {
private final VoteTallyUpdater voteTallyUpdater = mock(VoteTallyUpdater.class);
private final VoteTally voteTally = mock(VoteTally.class);
private final VoteProposer voteProposer = mock(VoteProposer.class);
@SuppressWarnings("unchecked")
private final BlockImporter<IbftContext> delegate = mock(BlockImporter.class);
private final MutableBlockchain blockchain = mock(MutableBlockchain.class);
private final WorldStateArchive worldStateArchive = mock(WorldStateArchive.class);
private final ProtocolContext<IbftContext> context =
new ProtocolContext<>(
blockchain, worldStateArchive, new IbftContext(voteTally, voteProposer));
private final IbftBlockImporter importer = new IbftBlockImporter(delegate, voteTallyUpdater);
@Test
public void voteTallyNotUpdatedWhenBlockImportFails() {
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
final Block block =
new Block(headerBuilder.buildHeader(), new BlockBody(emptyList(), emptyList()));
when(delegate.importBlock(context, block, HeaderValidationMode.FULL, HeaderValidationMode.FULL))
.thenReturn(false);
importer.importBlock(context, block, HeaderValidationMode.FULL);
verifyZeroInteractions(voteTallyUpdater);
}
@Test
public void voteTallyNotUpdatedWhenFastBlockImportFails() {
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
final Block block =
new Block(headerBuilder.buildHeader(), new BlockBody(emptyList(), emptyList()));
when(delegate.fastImportBlock(context, block, emptyList(), HeaderValidationMode.LIGHT))
.thenReturn(false);
importer.fastImportBlock(context, block, emptyList(), HeaderValidationMode.LIGHT);
verifyZeroInteractions(voteTallyUpdater);
}
@Test
public void voteTallyUpdatedWhenBlockImportSucceeds() {
final Block block =
new Block(
new BlockHeaderTestFixture().buildHeader(), new BlockBody(emptyList(), emptyList()));
when(delegate.importBlock(context, block, HeaderValidationMode.FULL, HeaderValidationMode.FULL))
.thenReturn(true);
importer.importBlock(context, block, HeaderValidationMode.FULL);
verify(voteTallyUpdater).updateForBlock(block.getHeader(), voteTally);
}
@Test
public void voteTallyUpdatedWhenFastBlockImportSucceeds() {
final Block block =
new Block(
new BlockHeaderTestFixture().buildHeader(), new BlockBody(emptyList(), emptyList()));
when(delegate.fastImportBlock(context, block, emptyList(), HeaderValidationMode.LIGHT))
.thenReturn(true);
importer.fastImportBlock(context, block, emptyList(), HeaderValidationMode.LIGHT);
verify(voteTallyUpdater).updateForBlock(block.getHeader(), voteTally);
}
}

@ -16,10 +16,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;
import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing; import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing;
import tech.pegasys.pantheon.consensus.ibft.IbftBlockHeaderValidationRulesetFactory; import tech.pegasys.pantheon.consensus.ibft.IbftBlockHeaderValidationRulesetFactory;
@ -78,7 +78,7 @@ public class IbftBlockCreatorTest {
new ProtocolContext<>( new ProtocolContext<>(
blockchain, blockchain,
createInMemoryWorldStateArchive(), createInMemoryWorldStateArchive(),
new IbftContext(voteTally, new VoteProposer())); setupContextWithValidators(initialValidatorList));
final IbftBlockCreator blockCreator = final IbftBlockCreator blockCreator =
new IbftBlockCreator( new IbftBlockCreator(

@ -19,7 +19,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.common.BlockInterface; import tech.pegasys.pantheon.consensus.common.BlockInterface;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
@ -28,6 +27,7 @@ import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Optional; import java.util.Optional;
@ -39,9 +39,10 @@ public class ProposerSelectorTest {
private final BlockInterface blockInterface = mock(BlockInterface.class); private final BlockInterface blockInterface = mock(BlockInterface.class);
private Blockchain createMockedBlockChainWithHeadOf( private Blockchain createMockedBlockChainWithHeadOf(
final long blockNumber, final Address proposer) { final long blockNumber, final Address proposer, final Collection<Address> validators) {
when(blockInterface.getProposerOfBlock(any())).thenReturn(proposer); when(blockInterface.getProposerOfBlock(any())).thenReturn(proposer);
when(blockInterface.validatorsInBlock(any())).thenReturn(validators);
final BlockHeaderTestFixture headerBuilderFixture = new BlockHeaderTestFixture(); final BlockHeaderTestFixture headerBuilderFixture = new BlockHeaderTestFixture();
headerBuilderFixture.number(blockNumber); headerBuilderFixture.number(blockNumber);
@ -87,12 +88,11 @@ public class ProposerSelectorTest {
final long PREV_BLOCK_NUMBER = 2; final long PREV_BLOCK_NUMBER = 2;
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
final LinkedList<Address> validatorList = createValidatorList(localAddr, 0, 4); final LinkedList<Address> validatorList = createValidatorList(localAddr, 0, 4);
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, true); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, true);
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
@ -105,12 +105,12 @@ public class ProposerSelectorTest {
public void lastValidatorInListValidatedPreviousBlockSoFirstIsNextProposer() { public void lastValidatorInListValidatedPreviousBlockSoFirstIsNextProposer() {
final long PREV_BLOCK_NUMBER = 2; final long PREV_BLOCK_NUMBER = 2;
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0); final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0);
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, true); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, true);
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
@ -125,11 +125,11 @@ public class ProposerSelectorTest {
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0); final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0);
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, false); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, false);
final Address nextProposer = uut.selectProposerForRound(roundId); final Address nextProposer = uut.selectProposerForRound(roundId);
assertThat(nextProposer).isEqualTo(localAddr); assertThat(nextProposer).isEqualTo(localAddr);
@ -141,12 +141,12 @@ public class ProposerSelectorTest {
ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0); final LinkedList<Address> validatorList = createValidatorList(localAddr, 4, 0);
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, false); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, false);
assertThat(uut.selectProposerForRound(roundId)).isEqualTo(localAddr); assertThat(uut.selectProposerForRound(roundId)).isEqualTo(localAddr);
roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 1); roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 1);
@ -162,7 +162,6 @@ public class ProposerSelectorTest {
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
// LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is // LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is
// removed) // removed)
@ -170,9 +169,10 @@ public class ProposerSelectorTest {
validatorList.remove(localAddr); validatorList.remove(localAddr);
// Note the signer of the Previous block was not included. // Note the signer of the Previous block was not included.
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, false); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, false);
assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(2)); assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(2));
} }
@ -183,17 +183,16 @@ public class ProposerSelectorTest {
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
// LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is // LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is
// removed) // removed)
final LinkedList<Address> validatorList = createValidatorList(localAddr, 2, 2); final LinkedList<Address> validatorList = createValidatorList(localAddr, 2, 2);
validatorList.remove(localAddr); validatorList.remove(localAddr);
// Note the signer of the Previous block was not included. final Blockchain blockchain =
final VoteTally voteTally = new VoteTally(validatorList); createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, true); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, true);
assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(2)); assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(2));
} }
@ -204,7 +203,6 @@ public class ProposerSelectorTest {
final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0); final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(PREV_BLOCK_NUMBER + 1, 0);
final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected final Address localAddr = AddressHelpers.ofValue(10); // arbitrarily selected
final Blockchain blockchain = createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr);
// LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is // LocalAddr will be in index 2 - the next proposer will also be in 2 (as prev proposer is
// removed) // removed)
@ -212,9 +210,10 @@ public class ProposerSelectorTest {
validatorList.remove(localAddr); validatorList.remove(localAddr);
// Note the signer of the Previous block was not included. // Note the signer of the Previous block was not included.
final VoteTally voteTally = new VoteTally(validatorList); final Blockchain blockchain =
createMockedBlockChainWithHeadOf(PREV_BLOCK_NUMBER, localAddr, validatorList);
final ProposerSelector uut = new ProposerSelector(blockchain, voteTally, blockInterface, false); final ProposerSelector uut = new ProposerSelector(blockchain, blockInterface, false);
assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(0)); assertThat(uut.selectProposerForRound(roundId)).isEqualTo(validatorList.get(0));
} }

@ -13,8 +13,8 @@
package tech.pegasys.pantheon.consensus.ibft.headervalidationrules; package tech.pegasys.pantheon.consensus.ibft.headervalidationrules;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData; import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraDataFixture; import tech.pegasys.pantheon.consensus.ibft.IbftExtraDataFixture;
@ -68,9 +68,8 @@ public class IbftCoinbaseValidationRuleTest {
final List<KeyPair> committers = Lists.newArrayList(proposerKeyPair); final List<KeyPair> committers = Lists.newArrayList(proposerKeyPair);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftCoinbaseValidationRule coinbaseValidationRule = new IbftCoinbaseValidationRule(); final IbftCoinbaseValidationRule coinbaseValidationRule = new IbftCoinbaseValidationRule();
@ -91,9 +90,8 @@ public class IbftCoinbaseValidationRuleTest {
final List<KeyPair> committers = Lists.newArrayList(otherValidatorKeyPair); final List<KeyPair> committers = Lists.newArrayList(otherValidatorKeyPair);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftCoinbaseValidationRule coinbaseValidationRule = new IbftCoinbaseValidationRule(); final IbftCoinbaseValidationRule coinbaseValidationRule = new IbftCoinbaseValidationRule();

@ -15,9 +15,9 @@ package tech.pegasys.pantheon.consensus.ibft.headervalidationrules;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import static tech.pegasys.pantheon.consensus.ibft.headervalidationrules.HeaderValidationTestHelpers.createProposedBlockHeader; import static tech.pegasys.pantheon.consensus.ibft.headervalidationrules.HeaderValidationTestHelpers.createProposedBlockHeader;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData; import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
@ -51,9 +51,8 @@ public class IbftCommitSealsValidationRuleTest {
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
final VoteTally voteTally = new VoteTally(committerAddresses);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(committerAddresses));
BlockHeader header = createProposedBlockHeader(committerAddresses, committerKeyPairs, false); BlockHeader header = createProposedBlockHeader(committerAddresses, committerKeyPairs, false);
@ -67,9 +66,8 @@ public class IbftCommitSealsValidationRuleTest {
Address.extract(Hash.hash(committerKeyPair.getPublicKey().getEncodedBytes())); Address.extract(Hash.hash(committerKeyPair.getPublicKey().getEncodedBytes()));
final List<Address> validators = singletonList(committerAddress); final List<Address> validators = singletonList(committerAddress);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final BlockHeader header = createProposedBlockHeader(validators, emptyList(), false); final BlockHeader header = createProposedBlockHeader(validators, emptyList(), false);
@ -86,16 +84,15 @@ public class IbftCommitSealsValidationRuleTest {
final Address committerAddress = Util.publicKeyToAddress(committerKeyPair.getPublicKey()); final Address committerAddress = Util.publicKeyToAddress(committerKeyPair.getPublicKey());
final List<Address> validators = singletonList(committerAddress); final List<Address> validators = singletonList(committerAddress);
final VoteTally voteTally = new VoteTally(validators);
// Insert an extraData block with committer seals. // Insert an extraData block with committer seals.
final KeyPair nonValidatorKeyPair = KeyPair.generate(); final KeyPair nonValidatorKeyPair = KeyPair.generate();
BlockHeader header = final BlockHeader header =
createProposedBlockHeader(validators, singletonList(nonValidatorKeyPair), false); createProposedBlockHeader(validators, singletonList(nonValidatorKeyPair), false);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
assertThat(commitSealsValidationRule.validate(header, null, context)).isFalse(); assertThat(commitSealsValidationRule.validate(header, null, context)).isFalse();
} }
@ -148,9 +145,8 @@ public class IbftCommitSealsValidationRuleTest {
createProposedBlockHeader( createProposedBlockHeader(
validators, Lists.newArrayList(committerKeyPair, committerKeyPair), false); validators, Lists.newArrayList(committerKeyPair, committerKeyPair), false);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
assertThat(commitSealsValidationRule.validate(header, null, context)).isFalse(); assertThat(commitSealsValidationRule.validate(header, null, context)).isFalse();
} }
@ -170,7 +166,6 @@ public class IbftCommitSealsValidationRuleTest {
} }
Collections.sort(validators); Collections.sort(validators);
final VoteTally voteTally = new VoteTally(validators);
final BlockHeader header = final BlockHeader header =
createProposedBlockHeader( createProposedBlockHeader(
validators, validators,
@ -178,7 +173,7 @@ public class IbftCommitSealsValidationRuleTest {
useDifferentRoundNumbersForCommittedSeals); useDifferentRoundNumbersForCommittedSeals);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
return commitSealsValidationRule.validate(header, null, context); return commitSealsValidationRule.validate(header, null, context);
} }

@ -14,9 +14,9 @@ package tech.pegasys.pantheon.consensus.ibft.headervalidationrules;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import static tech.pegasys.pantheon.consensus.ibft.headervalidationrules.HeaderValidationTestHelpers.createProposedBlockHeader; import static tech.pegasys.pantheon.consensus.ibft.headervalidationrules.HeaderValidationTestHelpers.createProposedBlockHeader;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
@ -39,9 +39,8 @@ public class IbftValidatorsValidationRuleTest {
Lists.newArrayList( Lists.newArrayList(
AddressHelpers.ofValue(1), AddressHelpers.ofValue(2), AddressHelpers.ofValue(3)); AddressHelpers.ofValue(1), AddressHelpers.ofValue(2), AddressHelpers.ofValue(3));
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final BlockHeader header = createProposedBlockHeader(validators, emptyList(), false); final BlockHeader header = createProposedBlockHeader(validators, emptyList(), false);
@ -53,13 +52,13 @@ public class IbftValidatorsValidationRuleTest {
final List<Address> validators = final List<Address> validators =
Lists.newArrayList( Lists.newArrayList(
AddressHelpers.ofValue(3), AddressHelpers.ofValue(2), AddressHelpers.ofValue(1)); AddressHelpers.ofValue(1), AddressHelpers.ofValue(2), AddressHelpers.ofValue(3));
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final BlockHeader header = createProposedBlockHeader(validators, emptyList(), false); final BlockHeader header =
createProposedBlockHeader(Lists.reverse(validators), emptyList(), false);
assertThat(validatorsValidationRule.validate(header, null, context)).isFalse(); assertThat(validatorsValidationRule.validate(header, null, context)).isFalse();
} }
@ -74,9 +73,8 @@ public class IbftValidatorsValidationRuleTest {
Lists.newArrayList( Lists.newArrayList(
AddressHelpers.ofValue(2), AddressHelpers.ofValue(3), AddressHelpers.ofValue(4)); AddressHelpers.ofValue(2), AddressHelpers.ofValue(3), AddressHelpers.ofValue(4));
final VoteTally voteTally = new VoteTally(storedValidators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(storedValidators));
final BlockHeader header = createProposedBlockHeader(reportedValidators, emptyList(), false); final BlockHeader header = createProposedBlockHeader(reportedValidators, emptyList(), false);

@ -20,7 +20,8 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.common.ValidatorProvider; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.crypto.SECP256K1.PublicKey; import tech.pegasys.pantheon.crypto.SECP256K1.PublicKey;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
@ -67,10 +68,12 @@ public class ValidatorPeersTest {
public void onlyValidatorsAreSentAMessage() throws PeerNotConnected { public void onlyValidatorsAreSentAMessage() throws PeerNotConnected {
// Only add the first Peer's address to the validators. // Only add the first Peer's address to the validators.
validators.add(Util.publicKeyToAddress(publicKeys.get(0))); validators.add(Util.publicKeyToAddress(publicKeys.get(0)));
final ValidatorProvider validatorProvider = mock(ValidatorProvider.class); final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
final VoteTally validatorProvider = mock(VoteTally.class);
when(voteTallyCache.getVoteTallyAtHead()).thenReturn(validatorProvider);
when(validatorProvider.getValidators()).thenReturn(validators); when(validatorProvider.getValidators()).thenReturn(validators);
final ValidatorPeers peers = new ValidatorPeers(validatorProvider); final ValidatorPeers peers = new ValidatorPeers(voteTallyCache);
for (final PeerConnection peer : peerConnections) { for (final PeerConnection peer : peerConnections) {
peers.add(peer); peers.add(peer);
} }
@ -88,10 +91,12 @@ public class ValidatorPeersTest {
public void doesntSendToValidatorsWhichAreNotDirectlyConnected() throws PeerNotConnected { public void doesntSendToValidatorsWhichAreNotDirectlyConnected() throws PeerNotConnected {
validators.add(Util.publicKeyToAddress(publicKeys.get(0))); validators.add(Util.publicKeyToAddress(publicKeys.get(0)));
final ValidatorProvider validatorProvider = mock(ValidatorProvider.class); final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
final VoteTally validatorProvider = mock(VoteTally.class);
when(voteTallyCache.getVoteTallyAtHead()).thenReturn(validatorProvider);
when(validatorProvider.getValidators()).thenReturn(validators); when(validatorProvider.getValidators()).thenReturn(validators);
final ValidatorPeers peers = new ValidatorPeers(validatorProvider); final ValidatorPeers peers = new ValidatorPeers(voteTallyCache);
// only add peer connections 1, 2 & 3, none of which should be invoked. // only add peer connections 1, 2 & 3, none of which should be invoked.
newArrayList(1, 2, 3).forEach(i -> peers.add(peerConnections.get(i))); newArrayList(1, 2, 3).forEach(i -> peers.add(peerConnections.get(i)));
@ -111,10 +116,12 @@ public class ValidatorPeersTest {
final Address validatorAddress = Util.publicKeyToAddress(publicKeys.get(0)); final Address validatorAddress = Util.publicKeyToAddress(publicKeys.get(0));
validators.add(validatorAddress); validators.add(validatorAddress);
validators.add(Util.publicKeyToAddress(publicKeys.get(1))); validators.add(Util.publicKeyToAddress(publicKeys.get(1)));
final ValidatorProvider validatorProvider = mock(ValidatorProvider.class); final VoteTallyCache voteTallyCache = mock(VoteTallyCache.class);
final VoteTally validatorProvider = mock(VoteTally.class);
when(voteTallyCache.getVoteTallyAtHead()).thenReturn(validatorProvider);
when(validatorProvider.getValidators()).thenReturn(validators); when(validatorProvider.getValidators()).thenReturn(validators);
final ValidatorPeers peers = new ValidatorPeers(validatorProvider); final ValidatorPeers peers = new ValidatorPeers(voteTallyCache);
for (final PeerConnection peer : peerConnections) { for (final PeerConnection peer : peerConnections) {
peers.add(peer); peers.add(peer);
} }

@ -24,9 +24,9 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import static tech.pegasys.pantheon.consensus.ibft.TestHelpers.createFrom; import static tech.pegasys.pantheon.consensus.ibft.TestHelpers.createFrom;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.BlockTimer; import tech.pegasys.pantheon.consensus.ibft.BlockTimer;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
@ -135,12 +135,11 @@ public class IbftBlockHeightManagerTest {
when(finalState.getMessageFactory()).thenReturn(messageFactory); when(finalState.getMessageFactory()).thenReturn(messageFactory);
when(blockCreator.createBlock(anyLong())).thenReturn(createdBlock); when(blockCreator.createBlock(anyLong())).thenReturn(createdBlock);
when(newRoundPayloadValidator.validateNewRoundMessage(any())).thenReturn(true); when(newRoundPayloadValidator.validateNewRoundMessage(any())).thenReturn(true);
when(messageValidatorFactory.createNewRoundValidator(anyLong())) when(messageValidatorFactory.createNewRoundValidator(anyLong(), any()))
.thenReturn(newRoundPayloadValidator); .thenReturn(newRoundPayloadValidator);
when(messageValidatorFactory.createMessageValidator(any())).thenReturn(messageValidator); when(messageValidatorFactory.createMessageValidator(any(), any())).thenReturn(messageValidator);
protocolContext = protocolContext = new ProtocolContext<>(null, null, setupContextWithValidators(validators));
new ProtocolContext<>(null, null, new IbftContext(new VoteTally(validators), null));
// Ensure the created IbftRound has the valid ConsensusRoundIdentifier; // Ensure the created IbftRound has the valid ConsensusRoundIdentifier;
when(roundFactory.createNewRound(any(), anyInt())) when(roundFactory.createNewRound(any(), anyInt()))

@ -22,9 +22,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing; import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
@ -94,9 +93,7 @@ public class IbftRoundTest {
public void setup() { public void setup() {
protocolContext = protocolContext =
new ProtocolContext<>( new ProtocolContext<>(
blockChain, blockChain, worldStateArchive, setupContextWithValidators(emptyList()));
worldStateArchive,
new IbftContext(new VoteTally(emptyList()), new VoteProposer()));
when(messageValidator.validateProposal(any())).thenReturn(true); when(messageValidator.validateProposal(any())).thenReturn(true);
when(messageValidator.validatePrepare(any())).thenReturn(true); when(messageValidator.validatePrepare(any())).thenReturn(true);

@ -17,8 +17,6 @@ import static tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHeaderValidati
import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.config.IbftConfigOptions; import tech.pegasys.pantheon.config.IbftConfigOptions;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.consensus.ibft.IbftBlockImporter;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.ethereum.MainnetBlockValidator; import tech.pegasys.pantheon.ethereum.MainnetBlockValidator;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
@ -60,10 +58,7 @@ public class IbftProtocolSchedule {
difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks),
MainnetBlockBodyValidator::new, MainnetBlockBodyValidator::new,
MainnetBlockValidator::new, MainnetBlockValidator::new,
(blockValidator) -> MainnetBlockImporter::new,
new IbftBlockImporter(
new MainnetBlockImporter<>(blockValidator),
new VoteTallyUpdater(epochManager, new IbftLegacyBlockInterface())),
(time, parent, protocolContext) -> BigInteger.ONE) (time, parent, protocolContext) -> BigInteger.ONE)
.blockReward(Wei.ZERO) .blockReward(Wei.ZERO)
.blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain); .blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain);

@ -25,6 +25,8 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -50,26 +52,9 @@ public class IbftExtraDataValidationRule implements AttachedBlockHeaderValidatio
final BlockHeader header, final BlockHeader header,
final BlockHeader parent, final BlockHeader parent,
final ProtocolContext<IbftContext> context) { final ProtocolContext<IbftContext> context) {
return validateExtraData(header, context);
}
/**
* Responsible for determining the validity of the extra data field. Ensures:
*
* <ul>
* <li>Bytes in the extra data field can be decoded as per IBFT specification
* <li>Proposer (derived from the proposerSeal) is a member of the validators
* <li>Committers (derived from committerSeals) are all members of the validators
* </ul>
*
* @param header the block header containing the extraData to be validated.
* @return True if the extraData successfully produces an IstanbulExtraData object, false
* otherwise
*/
private boolean validateExtraData(
final BlockHeader header, final ProtocolContext<IbftContext> context) {
try { try {
final ValidatorProvider validatorProvider = context.getConsensusState().getVoteTally(); final ValidatorProvider validatorProvider =
context.getConsensusState().getVoteTallyCache().getVoteTallyAfterBlock(parent);
final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData()); final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData());
final Address proposer = IbftBlockHashing.recoverProposerAddress(header, ibftExtraData); final Address proposer = IbftBlockHashing.recoverProposerAddress(header, ibftExtraData);
@ -89,6 +74,17 @@ public class IbftExtraDataValidationRule implements AttachedBlockHeaderValidatio
} }
} }
final SortedSet<Address> sortedReportedValidators =
new TreeSet<>(ibftExtraData.getValidators());
if (!Iterables.elementsEqual(ibftExtraData.getValidators(), sortedReportedValidators)) {
LOG.trace(
"Validators are not sorted in ascending order. Expected {} but got {}.",
sortedReportedValidators,
ibftExtraData.getValidators());
return false;
}
if (!Iterables.elementsEqual(ibftExtraData.getValidators(), storedValidators)) { if (!Iterables.elementsEqual(ibftExtraData.getValidators(), storedValidators)) {
LOG.trace( LOG.trace(
"Incorrect validators. Expected {} but got {}.", "Incorrect validators. Expected {} but got {}.",
@ -103,6 +99,9 @@ public class IbftExtraDataValidationRule implements AttachedBlockHeaderValidatio
} catch (final IllegalArgumentException ex) { } catch (final IllegalArgumentException ex) {
LOG.trace("Failed to verify extra data", ex); LOG.trace("Failed to verify extra data", ex);
return false; return false;
} catch (final RuntimeException ex) {
LOG.trace("Failed to find validators at parent");
return false;
} }
return true; return true;

@ -15,12 +15,17 @@ package tech.pegasys.pantheon.consensus.ibftlegacy;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; 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 tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftProtocolContextFixture;
import tech.pegasys.pantheon.crypto.SECP256K1; import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature; 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.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
@ -31,12 +36,25 @@ import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
public class IbftBlockHeaderValidationRulesetFactoryTest { public class IbftBlockHeaderValidationRulesetFactoryTest {
private ProtocolContext<IbftContext> setupContextWithValidators(
final Collection<Address> validators) {
final IbftContext ibftContext = mock(IbftContext.class);
final VoteTallyCache mockCache = mock(VoteTallyCache.class);
final VoteTally mockVoteTally = mock(VoteTally.class);
when(ibftContext.getVoteTallyCache()).thenReturn(mockCache);
when(mockCache.getVoteTallyAfterBlock(any())).thenReturn(mockVoteTally);
when(mockVoteTally.getValidators()).thenReturn(validators);
return new ProtocolContext<>(null, null, ibftContext);
}
@Test @Test
public void ibftValidateHeaderPasses() { public void ibftValidateHeaderPasses() {
final KeyPair proposerKeyPair = KeyPair.generate(); final KeyPair proposerKeyPair = KeyPair.generate();
@ -55,7 +73,7 @@ public class IbftBlockHeaderValidationRulesetFactoryTest {
validator.validateHeader( validator.validateHeader(
blockHeader, blockHeader,
parentHeader, parentHeader,
IbftProtocolContextFixture.protocolContext(validators), setupContextWithValidators(validators),
HeaderValidationMode.FULL)) HeaderValidationMode.FULL))
.isTrue(); .isTrue();
} }
@ -78,7 +96,7 @@ public class IbftBlockHeaderValidationRulesetFactoryTest {
validator.validateHeader( validator.validateHeader(
blockHeader, blockHeader,
parentHeader, parentHeader,
IbftProtocolContextFixture.protocolContext(validators), setupContextWithValidators(validators),
HeaderValidationMode.FULL)) HeaderValidationMode.FULL))
.isFalse(); .isFalse();
} }

@ -16,10 +16,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;
import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHeaderValidationRulesetFactory; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHeaderValidationRulesetFactory;
@ -84,7 +84,7 @@ public class IbftBlockCreatorTest {
new ProtocolContext<>( new ProtocolContext<>(
blockchain, blockchain,
createInMemoryWorldStateArchive(), createInMemoryWorldStateArchive(),
new IbftContext(voteTally, new VoteProposer())); setupContextWithValidators(initialValidatorList));
final IbftBlockCreator blockCreator = final IbftBlockCreator blockCreator =
new IbftBlockCreator( new IbftBlockCreator(

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.consensus.ibftlegacy.headervalidationrules;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.consensus.ibft.IbftContextBuilder.setupContextWithValidators;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
@ -103,9 +104,8 @@ public class IbftExtraDataValidationRuleTest {
Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes())); Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes()));
final List<Address> validators = singletonList(proposerAddress); final List<Address> validators = singletonList(proposerAddress);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
@ -130,9 +130,8 @@ public class IbftExtraDataValidationRuleTest {
Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes())); Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes()));
final List<Address> validators = singletonList(proposerAddress); final List<Address> validators = singletonList(proposerAddress);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
@ -158,9 +157,8 @@ public class IbftExtraDataValidationRuleTest {
Lists.newArrayList( Lists.newArrayList(
AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 1), proposerAddress); AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 1), proposerAddress);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
@ -190,7 +188,7 @@ public class IbftExtraDataValidationRuleTest {
final VoteTally voteTally = new VoteTally(validators); final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
@ -216,16 +214,17 @@ public class IbftExtraDataValidationRuleTest {
final List<Address> validators = Lists.newArrayList(proposerAddress); final List<Address> validators = Lists.newArrayList(proposerAddress);
final VoteTally voteTally = new VoteTally(validators);
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
// Add another validator to the list reported in the IbftExtraData (note, as the // Add another validator to the list reported in the IbftExtraData (note, as the
validators.add(AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 1)); final List<Address> extraDataValidators =
BlockHeader header = createProposedBlockHeader(proposerKeyPair, validators); Lists.newArrayList(
proposerAddress, AddressHelpers.calculateAddressWithRespectTo(proposerAddress, 1));
BlockHeader header = createProposedBlockHeader(proposerKeyPair, extraDataValidators);
// Insert an extraData block with committer seals. // Insert an extraData block with committer seals.
final IbftExtraData commitedExtraData = final IbftExtraData commitedExtraData =
@ -245,7 +244,6 @@ public class IbftExtraDataValidationRuleTest {
Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes())); Address.extract(Hash.hash(proposerKeyPair.getPublicKey().getEncodedBytes()));
final List<Address> validators = singletonList(proposerAddress); final List<Address> validators = singletonList(proposerAddress);
final VoteTally voteTally = new VoteTally(validators);
BlockHeader header = createProposedBlockHeader(proposerKeyPair, validators); BlockHeader header = createProposedBlockHeader(proposerKeyPair, validators);
@ -257,7 +255,7 @@ public class IbftExtraDataValidationRuleTest {
header = builder.buildHeader(); header = builder.buildHeader();
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);
@ -323,7 +321,7 @@ public class IbftExtraDataValidationRuleTest {
header = builder.buildHeader(); header = builder.buildHeader();
final ProtocolContext<IbftContext> context = final ProtocolContext<IbftContext> context =
new ProtocolContext<>(null, null, new IbftContext(voteTally, null)); new ProtocolContext<>(null, null, setupContextWithValidators(validators));
final IbftExtraDataValidationRule extraDataValidationRule = final IbftExtraDataValidationRule extraDataValidationRule =
new IbftExtraDataValidationRule(true); new IbftExtraDataValidationRule(true);

@ -20,13 +20,13 @@ import tech.pegasys.pantheon.consensus.clique.CliqueBlockInterface;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueMiningTracker; import tech.pegasys.pantheon.consensus.clique.CliqueMiningTracker;
import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache;
import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueBlockScheduler; import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueBlockScheduler;
import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueMinerExecutor; import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueMinerExecutor;
import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueMiningCoordinator; import tech.pegasys.pantheon.consensus.clique.blockcreation.CliqueMiningCoordinator;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueJsonRpcMethodsFactory; import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueJsonRpcMethodsFactory;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
@ -113,7 +113,7 @@ public class CliquePantheonController implements PantheonController<CliqueContex
final long blocksPerEpoch = cliqueConfig.getEpochLength(); final long blocksPerEpoch = cliqueConfig.getEpochLength();
final long secondsBetweenBlocks = cliqueConfig.getBlockPeriodSeconds(); final long secondsBetweenBlocks = cliqueConfig.getBlockPeriodSeconds();
final EpochManager epochManger = new EpochManager(blocksPerEpoch); final EpochManager epochManager = new EpochManager(blocksPerEpoch);
final ProtocolSchedule<CliqueContext> protocolSchedule = final ProtocolSchedule<CliqueContext> protocolSchedule =
CliqueProtocolSchedule.create(genesisConfig.getConfigOptions(), nodeKeys); CliqueProtocolSchedule.create(genesisConfig.getConfigOptions(), nodeKeys);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule);
@ -128,10 +128,11 @@ public class CliquePantheonController implements PantheonController<CliqueContex
new CliqueContext( new CliqueContext(
new VoteTallyCache( new VoteTallyCache(
blockchain, blockchain,
new VoteTallyUpdater(epochManger, new CliqueBlockInterface()), new VoteTallyUpdater(epochManager, new CliqueBlockInterface()),
epochManger), epochManager,
new CliqueBlockInterface()),
new VoteProposer(), new VoteProposer(),
epochManger)); epochManager));
final MutableBlockchain blockchain = protocolContext.getBlockchain(); final MutableBlockchain blockchain = protocolContext.getBlockchain();
final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST); final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST);
@ -176,7 +177,7 @@ public class CliquePantheonController implements PantheonController<CliqueContex
protocolContext.getConsensusState().getVoteTallyCache(), protocolContext.getConsensusState().getVoteTallyCache(),
localAddress, localAddress,
secondsBetweenBlocks), secondsBetweenBlocks),
epochManger); epochManager);
final CliqueMiningCoordinator miningCoordinator = final CliqueMiningCoordinator miningCoordinator =
new CliqueMiningCoordinator( new CliqueMiningCoordinator(
blockchain, blockchain,

@ -18,7 +18,7 @@ import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.config.IbftConfigOptions; import tech.pegasys.pantheon.config.IbftConfigOptions;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftJsonRpcMethodsFactory; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftJsonRpcMethodsFactory;
@ -112,12 +112,15 @@ public class IbftLegacyPantheonController implements PantheonController<IbftCont
metricsSystem, metricsSystem,
(blockchain, worldStateArchive) -> { (blockchain, worldStateArchive) -> {
final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength()); final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength());
final VoteTally voteTally = final VoteTallyCache voteTallyCache =
new VoteTallyUpdater(epochManager, new IbftLegacyBlockInterface()) new VoteTallyCache(
.buildVoteTallyFromBlockchain(blockchain); blockchain,
new VoteTallyUpdater(epochManager, new IbftLegacyBlockInterface()),
epochManager,
new IbftLegacyBlockInterface());
final VoteProposer voteProposer = new VoteProposer(); final VoteProposer voteProposer = new VoteProposer();
return new IbftContext(voteTally, voteProposer); return new IbftContext(voteTallyCache, voteProposer);
}); });
final MutableBlockchain blockchain = protocolContext.getBlockchain(); final MutableBlockchain blockchain = protocolContext.getBlockchain();

@ -19,7 +19,7 @@ import tech.pegasys.pantheon.config.IbftConfigOptions;
import tech.pegasys.pantheon.consensus.common.BlockInterface; import tech.pegasys.pantheon.consensus.common.BlockInterface;
import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.consensus.common.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTallyCache;
import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater;
import tech.pegasys.pantheon.consensus.ibft.BlockTimer; import tech.pegasys.pantheon.consensus.ibft.BlockTimer;
import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer; import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer;
@ -145,14 +145,15 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
metricsSystem, metricsSystem,
(blockchain, worldStateArchive) -> { (blockchain, worldStateArchive) -> {
final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength()); final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength());
final VoteTally voteTally = return new IbftContext(
new VoteTallyUpdater(epochManager, blockInterface) new VoteTallyCache(
.buildVoteTallyFromBlockchain(blockchain); blockchain,
final VoteProposer voteProposer = new VoteProposer(); new VoteTallyUpdater(epochManager, new IbftBlockInterface()),
return new IbftContext(voteTally, voteProposer); epochManager,
new IbftBlockInterface()),
new VoteProposer());
}); });
final MutableBlockchain blockchain = protocolContext.getBlockchain(); final MutableBlockchain blockchain = protocolContext.getBlockchain();
final VoteTally voteTally = protocolContext.getConsensusState().getVoteTally();
final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST); final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST);
final EthProtocolManager ethProtocolManager = final EthProtocolManager ethProtocolManager =
@ -197,11 +198,12 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
Util.publicKeyToAddress(nodeKeys.getPublicKey())); Util.publicKeyToAddress(nodeKeys.getPublicKey()));
final ProposerSelector proposerSelector = final ProposerSelector proposerSelector =
new ProposerSelector(blockchain, voteTally, blockInterface, true); new ProposerSelector(blockchain, blockInterface, true);
// NOTE: peers should not be used for accessing the network as it does not enforce the // NOTE: peers should not be used for accessing the network as it does not enforce the
// "only send once" filter applied by the UniqueMessageMulticaster. // "only send once" filter applied by the UniqueMessageMulticaster.
final ValidatorPeers peers = new ValidatorPeers(voteTally); final VoteTallyCache voteTallyCache = protocolContext.getConsensusState().getVoteTallyCache();
final ValidatorPeers peers = new ValidatorPeers(voteTallyCache);
final UniqueMessageMulticaster uniqueMessageMulticaster = final UniqueMessageMulticaster uniqueMessageMulticaster =
new UniqueMessageMulticaster(peers, ibftConfig.getGossipedHistoryLimit()); new UniqueMessageMulticaster(peers, ibftConfig.getGossipedHistoryLimit());
@ -210,7 +212,7 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
final IbftFinalState finalState = final IbftFinalState finalState =
new IbftFinalState( new IbftFinalState(
voteTally, voteTallyCache,
nodeKeys, nodeKeys,
Util.publicKeyToAddress(nodeKeys.getPublicKey()), Util.publicKeyToAddress(nodeKeys.getPublicKey()),
proposerSelector, proposerSelector,

@ -162,7 +162,7 @@ public class BlockImporter {
final BlockHeaderValidator<C> blockHeaderValidator = protocolSpec.getBlockHeaderValidator(); final BlockHeaderValidator<C> blockHeaderValidator = protocolSpec.getBlockHeaderValidator();
final boolean validHeader = final boolean validHeader =
blockHeaderValidator.validateHeader( blockHeaderValidator.validateHeader(
header, previousHeader, context, HeaderValidationMode.FULL); header, previousHeader, context, HeaderValidationMode.DETACHED_ONLY);
if (!validHeader) { if (!validHeader) {
throw new IllegalStateException("Invalid header at block number " + header.getNumber() + "."); throw new IllegalStateException("Invalid header at block number " + header.getNumber() + ".");
} }
@ -177,7 +177,7 @@ public class BlockImporter {
final tech.pegasys.pantheon.ethereum.core.BlockImporter<C> blockImporter = final tech.pegasys.pantheon.ethereum.core.BlockImporter<C> blockImporter =
protocolSpec.getBlockImporter(); protocolSpec.getBlockImporter();
final boolean blockImported = final boolean blockImported =
blockImporter.importBlock(context, block, HeaderValidationMode.NONE); blockImporter.importBlock(context, block, HeaderValidationMode.SKIP_DETACHED);
if (!blockImported) { if (!blockImported) {
throw new IllegalStateException( throw new IllegalStateException(
"Invalid block at block number " + header.getNumber() + "."); "Invalid block at block number " + header.getNumber() + ".");

Loading…
Cancel
Save