Added TerminatedRoundArtefacts (#756)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
tmohay 6 years ago committed by GitHub
parent 4a7b9823ad
commit 46c888c792
  1. 7
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/RoundSpecificPeers.java
  2. 18
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestHelpers.java
  3. 7
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/ValidatorPeer.java
  4. 16
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/ReceivedNewRoundTest.java
  5. 33
      consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/RoundChangeTest.java
  6. 5
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/messagewrappers/Proposal.java
  7. 6
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/network/IbftMessageTransmitter.java
  8. 8
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/payload/MessageFactory.java
  9. 16
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftBlockHeightManager.java
  10. 4
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftRound.java
  11. 29
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/RoundState.java
  12. 42
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/TerminatedRoundArtefacts.java
  13. 41
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftHelpersTest.java
  14. 10
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java
  15. 8
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftRoundTest.java
  16. 17
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/RoundChangeManagerTest.java
  17. 23
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/RoundStateTest.java
  18. 50
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/validation/NewRoundSignedDataValidatorTest.java
  19. 61
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/validation/RoundChangeSignedDataValidatorTest.java

@ -27,9 +27,9 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.IbftMessage;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.Payload; import tech.pegasys.pantheon.consensus.ibft.payload.Payload;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparePayload; import tech.pegasys.pantheon.consensus.ibft.payload.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
@ -113,13 +113,14 @@ public class RoundSpecificPeers {
} }
public List<SignedData<RoundChangePayload>> createSignedRoundChangePayload( public List<SignedData<RoundChangePayload>> createSignedRoundChangePayload(
final ConsensusRoundIdentifier roundId, final PreparedCertificate preparedCertificate) { final ConsensusRoundIdentifier roundId,
final TerminatedRoundArtefacts terminatedRoundArtefacts) {
return peers return peers
.stream() .stream()
.map( .map(
p -> p ->
p.getMessageFactory() p.getMessageFactory()
.createSignedRoundChangePayload(roundId, Optional.of(preparedCertificate)) .createSignedRoundChangePayload(roundId, Optional.of(terminatedRoundArtefacts))
.getSignedPayload()) .getSignedPayload())
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

@ -16,19 +16,21 @@ 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.IbftExtraData; import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.NewRound; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.NewRound;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.CommitPayload; import tech.pegasys.pantheon.consensus.ibft.payload.CommitPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
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.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class TestHelpers { public class TestHelpers {
@ -49,17 +51,17 @@ public class TestHelpers {
.getSignedPayload(); .getSignedPayload();
} }
public static PreparedCertificate createValidPreparedCertificate( public static TerminatedRoundArtefacts createValidTerminatedRoundArtefacts(
final TestContext context, final ConsensusRoundIdentifier preparedRound, final Block block) { final TestContext context, final ConsensusRoundIdentifier preparedRound, final Block block) {
final RoundSpecificPeers peers = context.roundSpecificPeers(preparedRound); final RoundSpecificPeers peers = context.roundSpecificPeers(preparedRound);
return new PreparedCertificate( return new TerminatedRoundArtefacts(
peers.getProposer().getMessageFactory().createSignedProposalPayload(preparedRound, block),
peers peers
.getProposer() .createSignedPreparePayloadOfNonProposing(preparedRound, block.getHash())
.getMessageFactory() .stream()
.createSignedProposalPayload(preparedRound, block) .map(Prepare::new)
.getSignedPayload(), .collect(Collectors.toList()));
peers.createSignedPreparePayloadOfNonProposing(preparedRound, block.getHash()));
} }
public static NewRound injectEmptyNewRound( public static NewRound injectEmptyNewRound(

@ -26,10 +26,10 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload; import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
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;
@ -120,9 +120,10 @@ public class ValidatorPeer {
} }
public RoundChange injectRoundChange( public RoundChange injectRoundChange(
final ConsensusRoundIdentifier rId, final Optional<PreparedCertificate> preparedCertificate) { final ConsensusRoundIdentifier rId,
final Optional<TerminatedRoundArtefacts> terminatedRoundArtefacts) {
final RoundChange payload = final RoundChange payload =
messageFactory.createSignedRoundChangePayload(rId, preparedCertificate); messageFactory.createSignedRoundChangePayload(rId, terminatedRoundArtefacts);
injectMessage(RoundChangeMessageData.create(payload)); injectMessage(RoundChangeMessageData.create(payload));
return payload; return payload;
} }

@ -12,17 +12,17 @@
*/ */
package tech.pegasys.pantheon.consensus.ibft.tests; package tech.pegasys.pantheon.consensus.ibft.tests;
import static tech.pegasys.pantheon.consensus.ibft.support.TestHelpers.createValidPreparedCertificate; import static tech.pegasys.pantheon.consensus.ibft.support.TestHelpers.createValidTerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Commit; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Commit;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.support.RoundSpecificPeers; import tech.pegasys.pantheon.consensus.ibft.support.RoundSpecificPeers;
import tech.pegasys.pantheon.consensus.ibft.support.TestContext; import tech.pegasys.pantheon.consensus.ibft.support.TestContext;
import tech.pegasys.pantheon.consensus.ibft.support.TestContextBuilder; import tech.pegasys.pantheon.consensus.ibft.support.TestContextBuilder;
@ -111,11 +111,11 @@ public class ReceivedNewRoundTest {
final Block reproposedBlock = context.createBlockForProposalFromChainHead(1, 15); final Block reproposedBlock = context.createBlockForProposalFromChainHead(1, 15);
final ConsensusRoundIdentifier nextRoundId = new ConsensusRoundIdentifier(1, 1); final ConsensusRoundIdentifier nextRoundId = new ConsensusRoundIdentifier(1, 1);
final PreparedCertificate preparedCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
createValidPreparedCertificate(context, roundId, initialBlock); createValidTerminatedRoundArtefacts(context, roundId, initialBlock);
final List<SignedData<RoundChangePayload>> roundChanges = final List<SignedData<RoundChangePayload>> roundChanges =
peers.createSignedRoundChangePayload(nextRoundId, preparedCertificate); peers.createSignedRoundChangePayload(nextRoundId, terminatedRoundArtefacts);
final ValidatorPeer nextProposer = context.roundSpecificPeers(nextRoundId).getProposer(); final ValidatorPeer nextProposer = context.roundSpecificPeers(nextRoundId).getProposer();
@ -164,11 +164,11 @@ public class ReceivedNewRoundTest {
final Block reproposedBlock = context.createBlockForProposalFromChainHead(1, 15); final Block reproposedBlock = context.createBlockForProposalFromChainHead(1, 15);
final ConsensusRoundIdentifier nextRoundId = new ConsensusRoundIdentifier(1, 1); final ConsensusRoundIdentifier nextRoundId = new ConsensusRoundIdentifier(1, 1);
final PreparedCertificate preparedCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
createValidPreparedCertificate(context, roundId, initialBlock); createValidTerminatedRoundArtefacts(context, roundId, initialBlock);
final List<SignedData<RoundChangePayload>> roundChanges = final List<SignedData<RoundChangePayload>> roundChanges =
peers.createSignedRoundChangePayload(nextRoundId, preparedCertificate); peers.createSignedRoundChangePayload(nextRoundId, terminatedRoundArtefacts);
final RoundSpecificPeers nextRoles = context.roundSpecificPeers(nextRoundId); final RoundSpecificPeers nextRoles = context.roundSpecificPeers(nextRoundId);
final ValidatorPeer nextProposer = nextRoles.getProposer(); final ValidatorPeer nextProposer = nextRoles.getProposer();

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.consensus.ibft.tests;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Optional.empty; import static java.util.Optional.empty;
import static tech.pegasys.pantheon.consensus.ibft.support.TestHelpers.createValidPreparedCertificate; import static tech.pegasys.pantheon.consensus.ibft.support.TestHelpers.createValidTerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftHelpers; import tech.pegasys.pantheon.consensus.ibft.IbftHelpers;
@ -24,10 +24,10 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.support.RoundSpecificPeers; import tech.pegasys.pantheon.consensus.ibft.support.RoundSpecificPeers;
import tech.pegasys.pantheon.consensus.ibft.support.TestContext; import tech.pegasys.pantheon.consensus.ibft.support.TestContext;
import tech.pegasys.pantheon.consensus.ibft.support.TestContextBuilder; import tech.pegasys.pantheon.consensus.ibft.support.TestContextBuilder;
@ -130,12 +130,8 @@ public class RoundChangeTest {
localNodeMessageFactory.createSignedRoundChangePayload( localNodeMessageFactory.createSignedRoundChangePayload(
targetRound, targetRound,
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
proposal.getSignedPayload(), proposal, Lists.newArrayList(localPrepareMessage, p1, p2))));
Lists.newArrayList(
localPrepareMessage.getSignedPayload(),
p1.getSignedPayload(),
p2.getSignedPayload()))));
context.getController().handleRoundExpiry(new RoundExpiry(roundId)); context.getController().handleRoundExpiry(new RoundExpiry(roundId));
peers.verifyMessagesReceived(expectedTxRoundChange); peers.verifyMessagesReceived(expectedTxRoundChange);
@ -173,14 +169,14 @@ public class RoundChangeTest {
public void newRoundMessageContainsBlockOnWhichPeerPrepared() { public void newRoundMessageContainsBlockOnWhichPeerPrepared() {
final long ARBITRARY_BLOCKTIME = 1500; final long ARBITRARY_BLOCKTIME = 1500;
final PreparedCertificate earlierPrepCert = final TerminatedRoundArtefacts earlierPrepCert =
createValidPreparedCertificate( createValidTerminatedRoundArtefacts(
context, context,
new ConsensusRoundIdentifier(1, 1), new ConsensusRoundIdentifier(1, 1),
context.createBlockForProposalFromChainHead(1, ARBITRARY_BLOCKTIME / 2)); context.createBlockForProposalFromChainHead(1, ARBITRARY_BLOCKTIME / 2));
final PreparedCertificate bestPrepCert = final TerminatedRoundArtefacts bestPrepCert =
createValidPreparedCertificate( createValidTerminatedRoundArtefacts(
context, context,
new ConsensusRoundIdentifier(1, 2), new ConsensusRoundIdentifier(1, 2),
context.createBlockForProposalFromChainHead(2, ARBITRARY_BLOCKTIME)); context.createBlockForProposalFromChainHead(2, ARBITRARY_BLOCKTIME));
@ -267,8 +263,8 @@ public class RoundChangeTest {
final ConsensusRoundIdentifier targetRound = new ConsensusRoundIdentifier(1, 4); final ConsensusRoundIdentifier targetRound = new ConsensusRoundIdentifier(1, 4);
final PreparedCertificate prepCert = final TerminatedRoundArtefacts prepCert =
createValidPreparedCertificate( createValidTerminatedRoundArtefacts(
context, context,
new ConsensusRoundIdentifier(1, 2), new ConsensusRoundIdentifier(1, 2),
context.createBlockForProposalFromChainHead(2, ARBITRARY_BLOCKTIME)); context.createBlockForProposalFromChainHead(2, ARBITRARY_BLOCKTIME));
@ -333,18 +329,17 @@ public class RoundChangeTest {
final RoundChange rc3 = peers.getNonProposing(2).injectRoundChange(targetRound, empty()); final RoundChange rc3 = peers.getNonProposing(2).injectRoundChange(targetRound, empty());
// create illegal RoundChangeMessage // create illegal RoundChangeMessage
final PreparedCertificate illegalPreparedCertificate = final TerminatedRoundArtefacts illegalTerminatedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
peers peers
.getNonProposing(0) .getNonProposing(0)
.getMessageFactory() .getMessageFactory()
.createSignedProposalPayload(roundId, blockToPropose) .createSignedProposalPayload(roundId, blockToPropose),
.getSignedPayload(),
emptyList()); emptyList());
peers peers
.getNonProposing(2) .getNonProposing(2)
.injectRoundChange(targetRound, Optional.of(illegalPreparedCertificate)); .injectRoundChange(targetRound, Optional.of(illegalTerminatedRoundArtefacts));
// Ensure no NewRound message is sent. // Ensure no NewRound message is sent.
peers.verifyNoMessagesReceived(); peers.verifyNoMessagesReceived();

@ -14,10 +14,15 @@ package tech.pegasys.pantheon.consensus.ibft.messagewrappers;
import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload; import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.ethereum.core.Block;
public class Proposal extends IbftMessage<ProposalPayload> { public class Proposal extends IbftMessage<ProposalPayload> {
public Proposal(final SignedData<ProposalPayload> payload) { public Proposal(final SignedData<ProposalPayload> payload) {
super(payload); super(payload);
} }
public Block getBlock() {
return getSignedPayload().getPayload().getBlock();
}
} }

@ -24,10 +24,10 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload; import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
@ -75,10 +75,10 @@ public class IbftMessageTransmitter {
public void multicastRoundChange( public void multicastRoundChange(
final ConsensusRoundIdentifier roundIdentifier, final ConsensusRoundIdentifier roundIdentifier,
final Optional<PreparedCertificate> preparedCertificate) { final Optional<TerminatedRoundArtefacts> terminatedRoundArtefacts) {
final RoundChange data = final RoundChange data =
messageFactory.createSignedRoundChangePayload(roundIdentifier, preparedCertificate); messageFactory.createSignedRoundChangePayload(roundIdentifier, terminatedRoundArtefacts);
final RoundChangeMessageData message = RoundChangeMessageData.create(data); final RoundChangeMessageData message = RoundChangeMessageData.create(data);

@ -18,6 +18,7 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.NewRound;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
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;
@ -64,9 +65,12 @@ public class MessageFactory {
public RoundChange createSignedRoundChangePayload( public RoundChange createSignedRoundChangePayload(
final ConsensusRoundIdentifier roundIdentifier, final ConsensusRoundIdentifier roundIdentifier,
final Optional<PreparedCertificate> preparedCertificate) { final Optional<TerminatedRoundArtefacts> terminatedRoundArtefacts) {
final RoundChangePayload payload = new RoundChangePayload(roundIdentifier, preparedCertificate); final RoundChangePayload payload =
new RoundChangePayload(
roundIdentifier,
terminatedRoundArtefacts.map(TerminatedRoundArtefacts::getPreparedCertificate));
return new RoundChange(createSignedMessage(payload)); return new RoundChange(createSignedMessage(payload));
} }

@ -29,7 +29,6 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter; import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.Payload; import tech.pegasys.pantheon.consensus.ibft.payload.Payload;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidatorFactory; import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidatorFactory;
import tech.pegasys.pantheon.consensus.ibft.validation.NewRoundMessageValidator; import tech.pegasys.pantheon.consensus.ibft.validation.NewRoundMessageValidator;
@ -70,7 +69,7 @@ public class IbftBlockHeightManager implements BlockHeightManager {
private final Function<ConsensusRoundIdentifier, RoundState> roundStateCreator; private final Function<ConsensusRoundIdentifier, RoundState> roundStateCreator;
private final IbftFinalState finalState; private final IbftFinalState finalState;
private Optional<PreparedCertificate> latestPreparedCertificate = Optional.empty(); private Optional<TerminatedRoundArtefacts> latesteTerminatedRoundArtefacts = Optional.empty();
private IbftRound currentRound; private IbftRound currentRound;
@ -134,19 +133,20 @@ public class IbftBlockHeightManager implements BlockHeightManager {
LOG.info( LOG.info(
"Round has expired, creating PreparedCertificate and notifying peers. round={}", "Round has expired, creating PreparedCertificate and notifying peers. round={}",
currentRound.getRoundIdentifier()); currentRound.getRoundIdentifier());
final Optional<PreparedCertificate> preparedCertificate = final Optional<TerminatedRoundArtefacts> terminatedRoundArtefats =
currentRound.createPrepareCertificate(); currentRound.constructTerminatedRoundArtefacts();
if (preparedCertificate.isPresent()) { if (terminatedRoundArtefats.isPresent()) {
latestPreparedCertificate = preparedCertificate; latesteTerminatedRoundArtefacts = terminatedRoundArtefats;
} }
startNewRound(currentRound.getRoundIdentifier().getRoundNumber() + 1); startNewRound(currentRound.getRoundIdentifier().getRoundNumber() + 1);
final RoundChange localRoundChange = final RoundChange localRoundChange =
messageFactory.createSignedRoundChangePayload( messageFactory.createSignedRoundChangePayload(
currentRound.getRoundIdentifier(), latestPreparedCertificate); currentRound.getRoundIdentifier(), latesteTerminatedRoundArtefacts);
transmitter.multicastRoundChange(currentRound.getRoundIdentifier(), latestPreparedCertificate); transmitter.multicastRoundChange(
currentRound.getRoundIdentifier(), latesteTerminatedRoundArtefacts);
// Its possible the locally created RoundChange triggers the transmission of a NewRound // Its possible the locally created RoundChange triggers the transmission of a NewRound
// message - so it must be handled accordingly. // message - so it must be handled accordingly.

@ -189,8 +189,8 @@ public class IbftRound {
peerIsCommitted(msg); peerIsCommitted(msg);
} }
public Optional<PreparedCertificate> createPrepareCertificate() { public Optional<TerminatedRoundArtefacts> constructTerminatedRoundArtefacts() {
return roundState.constructPreparedCertificate(); return roundState.constructTerminatedRoundArtefacts();
} }
private boolean updateStateWithProposedBlock(final Proposal msg) { private boolean updateStateWithProposedBlock(final Proposal msg) {

@ -18,7 +18,6 @@ import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Commit; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Commit;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidator; import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidator;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
@ -44,8 +43,8 @@ public class RoundState {
// Must track the actual Prepare message, not just the sender, as these may need to be reused // Must track the actual Prepare message, not just the sender, as these may need to be reused
// to send out in a PrepareCertificate. // to send out in a PrepareCertificate.
private final Set<Prepare> preparePayloads = Sets.newLinkedHashSet(); private final Set<Prepare> prepareMessages = Sets.newLinkedHashSet();
private final Set<Commit> commitPayloads = Sets.newLinkedHashSet(); private final Set<Commit> commitMessages = Sets.newLinkedHashSet();
private boolean prepared = false; private boolean prepared = false;
private boolean committed = false; private boolean committed = false;
@ -68,8 +67,8 @@ public class RoundState {
if (!proposalMessage.isPresent()) { if (!proposalMessage.isPresent()) {
if (validator.addSignedProposalPayload(msg)) { if (validator.addSignedProposalPayload(msg)) {
proposalMessage = Optional.of(msg); proposalMessage = Optional.of(msg);
preparePayloads.removeIf(p -> !validator.validatePrepareMessage(p)); prepareMessages.removeIf(p -> !validator.validatePrepareMessage(p));
commitPayloads.removeIf(p -> !validator.validateCommitMessage(p)); commitMessages.removeIf(p -> !validator.validateCommitMessage(p));
updateState(); updateState();
return true; return true;
} }
@ -80,7 +79,7 @@ public class RoundState {
public void addPrepareMessage(final Prepare msg) { public void addPrepareMessage(final Prepare msg) {
if (!proposalMessage.isPresent() || validator.validatePrepareMessage(msg)) { if (!proposalMessage.isPresent() || validator.validatePrepareMessage(msg)) {
preparePayloads.add(msg); prepareMessages.add(msg);
LOG.debug("Round state added prepare message prepare={}", msg); LOG.debug("Round state added prepare message prepare={}", msg);
} }
updateState(); updateState();
@ -88,7 +87,7 @@ public class RoundState {
public void addCommitMessage(final Commit msg) { public void addCommitMessage(final Commit msg) {
if (!proposalMessage.isPresent() || validator.validateCommitMessage(msg)) { if (!proposalMessage.isPresent() || validator.validateCommitMessage(msg)) {
commitPayloads.add(msg); commitMessages.add(msg);
LOG.debug("Round state added commit message commit={}", msg); LOG.debug("Round state added commit message commit={}", msg);
} }
@ -99,8 +98,8 @@ public class RoundState {
// NOTE: The quorum for Prepare messages is 1 less than the quorum size as the proposer // NOTE: The quorum for Prepare messages is 1 less than the quorum size as the proposer
// does not supply a prepare message // does not supply a prepare message
final long prepareQuorum = prepareMessageCountForQuorum(quorum); final long prepareQuorum = prepareMessageCountForQuorum(quorum);
prepared = (preparePayloads.size() >= prepareQuorum) && proposalMessage.isPresent(); prepared = (prepareMessages.size() >= prepareQuorum) && proposalMessage.isPresent();
committed = (commitPayloads.size() >= quorum) && proposalMessage.isPresent(); committed = (commitMessages.size() >= quorum) && proposalMessage.isPresent();
LOG.debug( LOG.debug(
"Round state updated prepared={} committed={} prepareQuorum={} quorum={}", "Round state updated prepared={} committed={} prepareQuorum={} quorum={}",
prepared, prepared,
@ -122,21 +121,15 @@ public class RoundState {
} }
public Collection<Signature> getCommitSeals() { public Collection<Signature> getCommitSeals() {
return commitPayloads return commitMessages
.stream() .stream()
.map(cp -> cp.getSignedPayload().getPayload().getCommitSeal()) .map(cp -> cp.getSignedPayload().getPayload().getCommitSeal())
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public Optional<PreparedCertificate> constructPreparedCertificate() { public Optional<TerminatedRoundArtefacts> constructTerminatedRoundArtefacts() {
if (isPrepared()) { if (isPrepared()) {
return Optional.of( return Optional.of(new TerminatedRoundArtefacts(proposalMessage.get(), prepareMessages));
new PreparedCertificate(
proposalMessage.get().getSignedPayload(),
preparePayloads
.stream()
.map(Prepare::getSignedPayload)
.collect(Collectors.toList())));
} }
return Optional.empty(); return Optional.empty();
} }

@ -0,0 +1,42 @@
/*
* 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.statemachine;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.ethereum.core.Block;
import java.util.Collection;
import java.util.stream.Collectors;
public class TerminatedRoundArtefacts {
private Proposal proposal;
private Collection<Prepare> prepares;
public TerminatedRoundArtefacts(final Proposal proposal, final Collection<Prepare> prepares) {
this.proposal = proposal;
this.prepares = prepares;
}
public Block getBlock() {
return proposal.getBlock();
}
public PreparedCertificate getPreparedCertificate() {
return new PreparedCertificate(
proposal.getSignedPayload(),
prepares.stream().map(Prepare::getSignedPayload).collect(Collectors.toList()));
}
}

@ -20,6 +20,7 @@ import static tech.pegasys.pantheon.consensus.ibft.IbftHelpers.calculateRequired
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
@ -92,17 +93,15 @@ public class IbftHelpersTest {
final Proposal differentProposal = final Proposal differentProposal =
proposerMessageFactory.createSignedProposalPayload(preparedRound, proposedBlock); proposerMessageFactory.createSignedProposalPayload(preparedRound, proposedBlock);
final Optional<PreparedCertificate> latterPreparedCert = final Optional<TerminatedRoundArtefacts> latterTerminatedRoundArtefacts =
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
differentProposal.getSignedPayload(), differentProposal,
Lists.newArrayList( Lists.newArrayList(
proposerMessageFactory proposerMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(roundIdentifier, proposedBlock.getHash()) roundIdentifier, proposedBlock.getHash()),
.getSignedPayload(), proposerMessageFactory.createSignedPreparePayload(
proposerMessageFactory roundIdentifier, proposedBlock.getHash()))));
.createSignedPreparePayload(roundIdentifier, proposedBlock.getHash())
.getSignedPayload())));
// An earlier PrepareCert is added to ensure the path to find the latest PrepareCert // An earlier PrepareCert is added to ensure the path to find the latest PrepareCert
// is correctly followed. // is correctly followed.
@ -110,29 +109,29 @@ public class IbftHelpersTest {
TestHelpers.createFrom(roundIdentifier, 0, -2); TestHelpers.createFrom(roundIdentifier, 0, -2);
final Proposal earlierProposal = final Proposal earlierProposal =
proposerMessageFactory.createSignedProposalPayload(earlierPreparedRound, proposedBlock); proposerMessageFactory.createSignedProposalPayload(earlierPreparedRound, proposedBlock);
final Optional<PreparedCertificate> earlierPreparedCert = final Optional<TerminatedRoundArtefacts> earlierTerminatedRoundArtefacts =
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
earlierProposal.getSignedPayload(), earlierProposal,
Lists.newArrayList( Lists.newArrayList(
proposerMessageFactory proposerMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(earlierPreparedRound, proposedBlock.getHash()) earlierPreparedRound, proposedBlock.getHash()),
.getSignedPayload(), proposerMessageFactory.createSignedPreparePayload(
proposerMessageFactory earlierPreparedRound, proposedBlock.getHash()))));
.createSignedPreparePayload(earlierPreparedRound, proposedBlock.getHash())
.getSignedPayload())));
final Optional<PreparedCertificate> newestCert = final Optional<PreparedCertificate> newestCert =
IbftHelpers.findLatestPreparedCertificate( IbftHelpers.findLatestPreparedCertificate(
Lists.newArrayList( Lists.newArrayList(
proposerMessageFactory proposerMessageFactory
.createSignedRoundChangePayload(roundIdentifier, earlierPreparedCert) .createSignedRoundChangePayload(
roundIdentifier, earlierTerminatedRoundArtefacts)
.getSignedPayload(), .getSignedPayload(),
proposerMessageFactory proposerMessageFactory
.createSignedRoundChangePayload(roundIdentifier, latterPreparedCert) .createSignedRoundChangePayload(roundIdentifier, latterTerminatedRoundArtefacts)
.getSignedPayload())); .getSignedPayload()));
assertThat(newestCert).isEqualTo(latterPreparedCert); assertThat(newestCert.get())
.isEqualTo(latterTerminatedRoundArtefacts.get().getPreparedCertificate());
} }
@Test @Test

@ -40,7 +40,6 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter; import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidator; import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidator;
import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidatorFactory; import tech.pegasys.pantheon.consensus.ibft.validation.MessageValidatorFactory;
@ -93,7 +92,7 @@ public class IbftBlockHeightManagerTest {
@Mock private RoundTimer roundTimer; @Mock private RoundTimer roundTimer;
@Mock private NewRoundMessageValidator newRoundMessageValidator; @Mock private NewRoundMessageValidator newRoundMessageValidator;
@Captor private ArgumentCaptor<Optional<PreparedCertificate>> preparedCaptor; @Captor private ArgumentCaptor<Optional<TerminatedRoundArtefacts>> terminatedRoundArtefactsCaptor;
private final List<KeyPair> validatorKeys = Lists.newArrayList(); private final List<KeyPair> validatorKeys = Lists.newArrayList();
private final List<Address> validators = Lists.newArrayList(); private final List<Address> validators = Lists.newArrayList();
@ -360,12 +359,13 @@ public class IbftBlockHeightManagerTest {
final ConsensusRoundIdentifier nextRound = createFrom(roundIdentifier, 0, +1); final ConsensusRoundIdentifier nextRound = createFrom(roundIdentifier, 0, +1);
verify(messageTransmitter, times(1)) verify(messageTransmitter, times(1))
.multicastRoundChange(eq(nextRound), preparedCaptor.capture()); .multicastRoundChange(eq(nextRound), terminatedRoundArtefactsCaptor.capture());
final Optional<PreparedCertificate> preparedCert = preparedCaptor.getValue(); final Optional<TerminatedRoundArtefacts> preparedCert =
terminatedRoundArtefactsCaptor.getValue();
assertThat(preparedCert).isNotEmpty(); assertThat(preparedCert).isNotEmpty();
assertThat(preparedCert.get().getPreparePayloads()) assertThat(preparedCert.get().getPreparedCertificate().getPreparePayloads())
.containsOnly(firstPrepare.getSignedPayload(), secondPrepare.getSignedPayload()); .containsOnly(firstPrepare.getSignedPayload(), secondPrepare.getSignedPayload());
} }
} }

@ -30,7 +30,6 @@ import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.consensus.ibft.blockcreation.IbftBlockCreator; import tech.pegasys.pantheon.consensus.ibft.blockcreation.IbftBlockCreator;
import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter; import tech.pegasys.pantheon.consensus.ibft.network.IbftMessageTransmitter;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload; import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
@ -305,10 +304,9 @@ public class IbftRoundTest {
.createSignedRoundChangePayload( .createSignedRoundChangePayload(
roundIdentifier, roundIdentifier,
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
messageFactory messageFactory.createSignedProposalPayload(
.createSignedProposalPayload(priorRoundChange, proposedBlock) priorRoundChange, proposedBlock),
.getSignedPayload(),
Collections.emptyList()))) Collections.emptyList())))
.getSignedPayload())); .getSignedPayload()));
// NOTE: IbftRound assumes the prepare's are valid // NOTE: IbftRound assumes the prepare's are valid

@ -21,12 +21,10 @@ import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftHelpers; import tech.pegasys.pantheon.consensus.ibft.IbftHelpers;
import tech.pegasys.pantheon.consensus.ibft.TestHelpers; import tech.pegasys.pantheon.consensus.ibft.TestHelpers;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.SignedData;
import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator; import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator;
import tech.pegasys.pantheon.consensus.ibft.validation.SignedDataValidator; import tech.pegasys.pantheon.consensus.ibft.validation.SignedDataValidator;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
@ -142,22 +140,21 @@ public class RoundChangeManagerTest {
// Proposal must come from an earlier round. // Proposal must come from an earlier round.
final Proposal proposal = messageFactory.createSignedProposalPayload(proposalRound, block); final Proposal proposal = messageFactory.createSignedProposalPayload(proposalRound, block);
final List<SignedData<PreparePayload>> preparePayloads = final List<Prepare> preparePayloads =
prepareProviders prepareProviders
.stream() .stream()
.map( .map(
k -> { k -> {
final MessageFactory prepareFactory = new MessageFactory(k); final MessageFactory prepareFactory = new MessageFactory(k);
return prepareFactory return prepareFactory.createSignedPreparePayload(proposalRound, block.getHash());
.createSignedPreparePayload(proposalRound, block.getHash())
.getSignedPayload();
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
final PreparedCertificate cert = final TerminatedRoundArtefacts terminatedRoundArtects =
new PreparedCertificate(proposal.getSignedPayload(), preparePayloads); new TerminatedRoundArtefacts(proposal, preparePayloads);
return messageFactory.createSignedRoundChangePayload(round, Optional.of(cert)); return messageFactory.createSignedRoundChangePayload(
round, Optional.of(terminatedRoundArtects));
} }
@Test @Test

@ -71,7 +71,7 @@ public class RoundStateTest {
assertThat(roundState.isPrepared()).isFalse(); assertThat(roundState.isPrepared()).isFalse();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isEmpty();
} }
@Test @Test
@ -85,7 +85,7 @@ public class RoundStateTest {
assertThat(roundState.setProposedBlock(proposal)).isFalse(); assertThat(roundState.setProposedBlock(proposal)).isFalse();
assertThat(roundState.isPrepared()).isFalse(); assertThat(roundState.isPrepared()).isFalse();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isEmpty();
} }
@Test @Test
@ -99,8 +99,13 @@ public class RoundStateTest {
assertThat(roundState.setProposedBlock(proposal)).isTrue(); assertThat(roundState.setProposedBlock(proposal)).isTrue();
assertThat(roundState.isPrepared()).isTrue(); assertThat(roundState.isPrepared()).isTrue();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isNotEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isNotEmpty();
assertThat(roundState.constructPreparedCertificate().get().getProposalPayload()) assertThat(
roundState
.constructTerminatedRoundArtefacts()
.get()
.getPreparedCertificate()
.getProposalPayload())
.isEqualTo(proposal.getSignedPayload()); .isEqualTo(proposal.getSignedPayload());
} }
@ -129,7 +134,7 @@ public class RoundStateTest {
roundState.addCommitMessage(commit); roundState.addCommitMessage(commit);
assertThat(roundState.isPrepared()).isTrue(); assertThat(roundState.isPrepared()).isTrue();
assertThat(roundState.isCommitted()).isTrue(); assertThat(roundState.isCommitted()).isTrue();
assertThat(roundState.constructPreparedCertificate()).isNotEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isNotEmpty();
} }
@Test @Test
@ -152,19 +157,19 @@ public class RoundStateTest {
roundState.addPrepareMessage(firstPrepare); roundState.addPrepareMessage(firstPrepare);
assertThat(roundState.isPrepared()).isFalse(); assertThat(roundState.isPrepared()).isFalse();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isEmpty();
roundState.addPrepareMessage(secondPrepare); roundState.addPrepareMessage(secondPrepare);
assertThat(roundState.isPrepared()).isFalse(); assertThat(roundState.isPrepared()).isFalse();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isEmpty();
final Proposal proposal = final Proposal proposal =
validatorMessageFactories.get(0).createSignedProposalPayload(roundIdentifier, block); validatorMessageFactories.get(0).createSignedProposalPayload(roundIdentifier, block);
assertThat(roundState.setProposedBlock(proposal)).isTrue(); assertThat(roundState.setProposedBlock(proposal)).isTrue();
assertThat(roundState.isPrepared()).isTrue(); assertThat(roundState.isPrepared()).isTrue();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isNotEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isNotEmpty();
} }
@Test @Test
@ -197,7 +202,7 @@ public class RoundStateTest {
assertThat(roundState.setProposedBlock(proposal)).isTrue(); assertThat(roundState.setProposedBlock(proposal)).isTrue();
assertThat(roundState.isPrepared()).isFalse(); assertThat(roundState.isPrepared()).isFalse();
assertThat(roundState.isCommitted()).isFalse(); assertThat(roundState.isCommitted()).isFalse();
assertThat(roundState.constructPreparedCertificate()).isEmpty(); assertThat(roundState.constructTerminatedRoundArtefacts()).isEmpty();
} }
@Test @Test

@ -25,8 +25,8 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.NewRound;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Proposal;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.NewRoundPayload; import tech.pegasys.pantheon.consensus.ibft.payload.NewRoundPayload;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.RoundChangeCertificate;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator.MessageValidatorForHeightFactory; import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator.MessageValidatorForHeightFactory;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
@ -165,22 +165,19 @@ public class NewRoundSignedDataValidatorTest {
final Block prevProposedBlock = final Block prevProposedBlock =
TestHelpers.createProposalBlock(validators.subList(0, 1), roundIdentifier.getRoundNumber()); TestHelpers.createProposalBlock(validators.subList(0, 1), roundIdentifier.getRoundNumber());
final PreparedCertificate misMatchedPreparedCertificate = final TerminatedRoundArtefacts mismatchedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(preparedRound, prevProposedBlock),
.createSignedProposalPayload(preparedRound, prevProposedBlock)
.getSignedPayload(),
singletonList( singletonList(
validatorMessageFactory validatorMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(preparedRound, prevProposedBlock.getHash()) preparedRound, prevProposedBlock.getHash())));
.getSignedPayload()));
msgBuilder.setRoundChangeCertificate( msgBuilder.setRoundChangeCertificate(
new RoundChangeCertificate( new RoundChangeCertificate(
singletonList( singletonList(
validatorMessageFactory validatorMessageFactory
.createSignedRoundChangePayload( .createSignedRoundChangePayload(
roundIdentifier, Optional.of(misMatchedPreparedCertificate)) roundIdentifier, Optional.of(mismatchedRoundArtefacts))
.getSignedPayload()))); .getSignedPayload())));
final NewRound invalidMsg = signPayload(msgBuilder.build(), proposerKey); final NewRound invalidMsg = signPayload(msgBuilder.build(), proposerKey);
@ -214,14 +211,11 @@ public class NewRoundSignedDataValidatorTest {
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
roundIdentifier, roundIdentifier,
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(prevRound, proposedBlock),
.createSignedProposalPayload(prevRound, proposedBlock)
.getSignedPayload(),
Lists.newArrayList( Lists.newArrayList(
validatorMessageFactory validatorMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(prevRound, proposedBlock.getHash()) prevRound, proposedBlock.getHash()))))));
.getSignedPayload())))));
msgBuilder.setRoundChangeCertificate(roundChangeBuilder.buildCertificate()); msgBuilder.setRoundChangeCertificate(roundChangeBuilder.buildCertificate());
@ -240,14 +234,13 @@ public class NewRoundSignedDataValidatorTest {
roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() - 1); roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() - 1);
final Proposal latterProposal = final Proposal latterProposal =
proposerMessageFactory.createSignedProposalPayload(latterPrepareRound, proposedBlock); proposerMessageFactory.createSignedProposalPayload(latterPrepareRound, proposedBlock);
final Optional<PreparedCertificate> preparedCert = final Optional<TerminatedRoundArtefacts> preparedCert =
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
latterProposal.getSignedPayload(), latterProposal,
Lists.newArrayList( Lists.newArrayList(
validatorMessageFactory validatorMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(roundIdentifier, proposedBlock.getHash()) roundIdentifier, proposedBlock.getHash()))));
.getSignedPayload())));
// An earlier PrepareCert is added to ensure the path to find the latest PrepareCert // An earlier PrepareCert is added to ensure the path to find the latest PrepareCert
// is correctly followed. // is correctly followed.
@ -258,14 +251,13 @@ public class NewRoundSignedDataValidatorTest {
roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() - 2); roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() - 2);
final Proposal earlierProposal = final Proposal earlierProposal =
proposerMessageFactory.createSignedProposalPayload(earlierPreparedRound, earlierBlock); proposerMessageFactory.createSignedProposalPayload(earlierPreparedRound, earlierBlock);
final Optional<PreparedCertificate> earlierPreparedCert = final Optional<TerminatedRoundArtefacts> earlierPreparedCert =
Optional.of( Optional.of(
new PreparedCertificate( new TerminatedRoundArtefacts(
earlierProposal.getSignedPayload(), earlierProposal,
Lists.newArrayList( Lists.newArrayList(
validatorMessageFactory validatorMessageFactory.createSignedPreparePayload(
.createSignedPreparePayload(earlierPreparedRound, earlierBlock.getHash()) earlierPreparedRound, earlierBlock.getHash()))));
.getSignedPayload())));
final RoundChangeCertificate roundChangeCert = final RoundChangeCertificate roundChangeCert =
new RoundChangeCertificate( new RoundChangeCertificate(

@ -25,6 +25,7 @@ import tech.pegasys.pantheon.consensus.ibft.messagewrappers.Prepare;
import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange; import tech.pegasys.pantheon.consensus.ibft.messagewrappers.RoundChange;
import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate; import tech.pegasys.pantheon.consensus.ibft.payload.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.statemachine.TerminatedRoundArtefacts;
import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator.MessageValidatorForHeightFactory; import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator.MessageValidatorForHeightFactory;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
@ -95,16 +96,17 @@ public class RoundChangeSignedDataValidatorTest {
@Test @Test
public void roundChangeContainingInvalidProposalFails() { public void roundChangeContainingInvalidProposalFails() {
final PreparedCertificate prepareCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(currentRound, block),
.createSignedProposalPayload(currentRound, block)
.getSignedPayload(),
Collections.emptyList()); Collections.emptyList());
final PreparedCertificate prepareCertificate =
terminatedRoundArtefacts.getPreparedCertificate();
final RoundChange msg = final RoundChange msg =
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate)); targetRound, Optional.of(terminatedRoundArtefacts));
when(basicValidator.addSignedProposalPayload(any())).thenReturn(false); when(basicValidator.addSignedProposalPayload(any())).thenReturn(false);
@ -119,16 +121,14 @@ public class RoundChangeSignedDataValidatorTest {
@Test @Test
public void roundChangeContainingValidProposalButNoPrepareMessagesFails() { public void roundChangeContainingValidProposalButNoPrepareMessagesFails() {
final PreparedCertificate prepareCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(currentRound, block),
.createSignedProposalPayload(currentRound, block)
.getSignedPayload(),
Collections.emptyList()); Collections.emptyList());
final RoundChange msg = final RoundChange msg =
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate)); targetRound, Optional.of(terminatedRoundArtefacts));
when(basicValidator.addSignedProposalPayload(any())).thenReturn(true); when(basicValidator.addSignedProposalPayload(any())).thenReturn(true);
assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse(); assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse();
@ -138,19 +138,17 @@ public class RoundChangeSignedDataValidatorTest {
public void roundChangeInvalidPrepareMessageFromProposerFails() { public void roundChangeInvalidPrepareMessageFromProposerFails() {
final Prepare prepareMsg = final Prepare prepareMsg =
validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash()); validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash());
final PreparedCertificate prepareCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(currentRound, block),
.createSignedProposalPayload(currentRound, block) Lists.newArrayList(prepareMsg));
.getSignedPayload(),
Lists.newArrayList(prepareMsg.getSignedPayload()));
when(basicValidator.addSignedProposalPayload(any())).thenReturn(true); when(basicValidator.addSignedProposalPayload(any())).thenReturn(true);
when(basicValidator.validatePrepareMessage(any())).thenReturn(false); when(basicValidator.validatePrepareMessage(any())).thenReturn(false);
final RoundChange msg = final RoundChange msg =
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate)); targetRound, Optional.of(terminatedRoundArtefacts));
assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse(); assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse();
@ -179,16 +177,14 @@ public class RoundChangeSignedDataValidatorTest {
final Prepare prepareMsg = final Prepare prepareMsg =
validatorMessageFactory.createSignedPreparePayload(futureRound, block.getHash()); validatorMessageFactory.createSignedPreparePayload(futureRound, block.getHash());
final PreparedCertificate prepareCertificate = final TerminatedRoundArtefacts terminatedRoundArtefacts =
new PreparedCertificate( new TerminatedRoundArtefacts(
proposerMessageFactory proposerMessageFactory.createSignedProposalPayload(futureRound, block),
.createSignedProposalPayload(futureRound, block) Lists.newArrayList(prepareMsg));
.getSignedPayload(),
Lists.newArrayList(prepareMsg.getSignedPayload()));
final RoundChange msg = final RoundChange msg =
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate)); targetRound, Optional.of(terminatedRoundArtefacts));
assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse(); assertThat(validator.validateMessage(msg.getSignedPayload())).isFalse();
verify(validatorFactory, never()).createAt(any()); verify(validatorFactory, never()).createAt(any());
@ -200,16 +196,17 @@ public class RoundChangeSignedDataValidatorTest {
public void roundChangeWithPastProposalForCurrentHeightIsSuccessful() { public void roundChangeWithPastProposalForCurrentHeightIsSuccessful() {
final Prepare prepareMsg = final Prepare prepareMsg =
validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash()); validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash());
final TerminatedRoundArtefacts terminatedRoundArtefacts =
new TerminatedRoundArtefacts(
proposerMessageFactory.createSignedProposalPayload(currentRound, block),
Lists.newArrayList(prepareMsg));
final PreparedCertificate prepareCertificate = final PreparedCertificate prepareCertificate =
new PreparedCertificate( terminatedRoundArtefacts.getPreparedCertificate();
proposerMessageFactory
.createSignedProposalPayload(currentRound, block)
.getSignedPayload(),
Lists.newArrayList(prepareMsg.getSignedPayload()));
final RoundChange msg = final RoundChange msg =
proposerMessageFactory.createSignedRoundChangePayload( proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate)); targetRound, Optional.of(terminatedRoundArtefacts));
when(basicValidator.addSignedProposalPayload(prepareCertificate.getProposalPayload())) when(basicValidator.addSignedProposalPayload(prepareCertificate.getProposalPayload()))
.thenReturn(true); .thenReturn(true);

Loading…
Cancel
Save