Renamed IBFT message classes (#333)

The classes used around the IBFT Messaging classes have all been renamed to make their use less cumbersome throughout the codebase.

Other issues are yet to be found (not all variable names and function names have been captured in this sweep).
tmohay 6 years ago committed by GitHub
parent d9a7ad2eb8
commit 7891132dd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java
  2. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/ProposerSelector.java
  3. 4
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java
  4. 21
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/CommitMessage.java
  5. 49
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java
  6. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java
  7. 21
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/NewRoundMessage.java
  8. 21
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/PrepareMessage.java
  9. 47
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/ProposalMessage.java
  10. 22
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/RoundChangeMessage.java
  11. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/AbstractPayload.java
  12. 8
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/CommitPayload.java
  13. 108
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java
  14. 62
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java
  15. 53
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftRoundChangeCertificate.java
  16. 5
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/InRoundPayload.java
  17. 98
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/MessageFactory.java
  18. 34
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/NewRoundPayload.java
  19. 9
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/PreparePayload.java
  20. 58
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/PreparedCertificate.java
  21. 13
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/ProposalPayload.java
  22. 48
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/RoundChangeCertificate.java
  23. 18
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/RoundChangePayload.java
  24. 55
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/SignedData.java
  25. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java
  26. 101
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/validation/MessageValidator.java
  27. 53
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/validation/RoundChangeMessageValidator.java
  28. 153
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/validation/MessageValidatorTest.java
  29. 119
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/validation/RoundChangeMessageValidatorTest.java

@ -12,36 +12,36 @@
*/
package tech.pegasys.pantheon.consensus.ibft;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftCommitMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftNewRoundMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftPrePrepareMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftPrepareMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftRoundChangeMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.CommitMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftV2;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.NewRoundMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.PrepareMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.ProposalMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.RoundChangeMessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.Message;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
public class IbftMessages {
public static IbftSignedMessageData<?> fromMessage(final Message message) {
public static SignedData<?> fromMessage(final Message message) {
final MessageData messageData = message.getData();
switch (messageData.getCode()) {
case IbftV2.PRE_PREPARE:
return IbftPrePrepareMessage.fromMessage(messageData).decode();
case IbftV2.PROPOSAL:
return ProposalMessage.fromMessage(messageData).decode();
case IbftV2.PREPARE:
return IbftPrepareMessage.fromMessage(messageData).decode();
return PrepareMessage.fromMessage(messageData).decode();
case IbftV2.COMMIT:
return IbftCommitMessage.fromMessage(messageData).decode();
return CommitMessage.fromMessage(messageData).decode();
case IbftV2.ROUND_CHANGE:
return IbftRoundChangeMessage.fromMessage(messageData).decode();
return RoundChangeMessage.fromMessage(messageData).decode();
case IbftV2.NEW_ROUND:
return IbftNewRoundMessage.fromMessage(messageData).decode();
return NewRoundMessage.fromMessage(messageData).decode();
default:
throw new IllegalArgumentException(

@ -33,7 +33,7 @@ import org.apache.logging.log4j.Logger;
/**
* Responsible for determining which member of the validator pool should propose the next block
* (i.e. send the Preprepare message).
* (i.e. send the Proposal message).
*
* <p>It does this by extracting the previous block's proposer from the ProposerSeal (stored in the
* Blocks ExtraData) then iterating through the validator list (stored in {@link

@ -12,7 +12,7 @@
*/
package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.p2p.wire.AbstractMessageData;
import tech.pegasys.pantheon.util.bytes.BytesValue;
@ -24,7 +24,7 @@ public abstract class AbstractIbftMessage extends AbstractMessageData {
super(data);
}
public abstract IbftSignedMessageData<?> decode();
public abstract SignedData<?> decode();
protected static <T extends AbstractIbftMessage> T fromMessage(
final MessageData message,

@ -12,33 +12,32 @@
*/
package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.CommitPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftCommitMessage extends AbstractIbftMessage {
public class CommitMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.COMMIT;
private IbftCommitMessage(final BytesValue data) {
private CommitMessage(final BytesValue data) {
super(data);
}
public static IbftCommitMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, IbftCommitMessage.class, IbftCommitMessage::new);
public static CommitMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, CommitMessage.class, CommitMessage::new);
}
@Override
public IbftSignedMessageData<IbftUnsignedCommitMessageData> decode() {
return IbftSignedMessageData.readIbftSignedCommitMessageDataFrom(RLP.input(data));
public SignedData<CommitPayload> decode() {
return SignedData.readSignedCommitPayloadFrom(RLP.input(data));
}
public static IbftCommitMessage create(
final IbftSignedMessageData<IbftUnsignedCommitMessageData> ibftPrepareMessageDecoded) {
public static CommitMessage create(final SignedData<CommitPayload> signedPayload) {
return new IbftCommitMessage(ibftPrepareMessageDecoded.encode());
return new CommitMessage(signedPayload.encode());
}
@Override

@ -1,49 +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.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftPrePrepareMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.PRE_PREPARE;
private IbftPrePrepareMessage(final BytesValue data) {
super(data);
}
public static IbftPrePrepareMessage fromMessage(final MessageData message) {
return fromMessage(
message, MESSAGE_CODE, IbftPrePrepareMessage.class, IbftPrePrepareMessage::new);
}
@Override
public IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> decode() {
return IbftSignedMessageData.readIbftSignedPrePrepareMessageDataFrom(RLP.input(data));
}
public static IbftPrePrepareMessage create(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrepareMessageDecoded) {
return new IbftPrePrepareMessage(ibftPrepareMessageDecoded.encode());
}
@Override
public int getCode() {
return MESSAGE_CODE;
}
}

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
/** Message codes for iBFT v2 messages */
public class IbftV2 {
public static final int PRE_PREPARE = 0;
public static final int PROPOSAL = 0;
public static final int PREPARE = 1;
public static final int COMMIT = 2;
public static final int ROUND_CHANGE = 3;

@ -12,33 +12,32 @@
*/
package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedNewRoundMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.NewRoundPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftNewRoundMessage extends AbstractIbftMessage {
public class NewRoundMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.NEW_ROUND;
private IbftNewRoundMessage(final BytesValue data) {
private NewRoundMessage(final BytesValue data) {
super(data);
}
public static IbftNewRoundMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, IbftNewRoundMessage.class, IbftNewRoundMessage::new);
public static NewRoundMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, NewRoundMessage.class, NewRoundMessage::new);
}
@Override
public IbftSignedMessageData<IbftUnsignedNewRoundMessageData> decode() {
return IbftSignedMessageData.readIbftSignedNewRoundMessageDataFrom(RLP.input(data));
public SignedData<NewRoundPayload> decode() {
return SignedData.readSignedNewRoundPayloadFrom(RLP.input(data));
}
public static IbftNewRoundMessage create(
final IbftSignedMessageData<IbftUnsignedNewRoundMessageData> ibftPrepareMessageDecoded) {
public static NewRoundMessage create(final SignedData<NewRoundPayload> signedPayload) {
return new IbftNewRoundMessage(ibftPrepareMessageDecoded.encode());
return new NewRoundMessage(signedPayload.encode());
}
@Override

@ -12,33 +12,32 @@
*/
package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftPrepareMessage extends AbstractIbftMessage {
public class PrepareMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.PREPARE;
private IbftPrepareMessage(final BytesValue data) {
private PrepareMessage(final BytesValue data) {
super(data);
}
public static IbftPrepareMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, IbftPrepareMessage.class, IbftPrepareMessage::new);
public static PrepareMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, PrepareMessage.class, PrepareMessage::new);
}
@Override
public IbftSignedMessageData<IbftUnsignedPrepareMessageData> decode() {
return IbftSignedMessageData.readIbftSignedPrepareMessageDataFrom(RLP.input(data));
public SignedData<PreparePayload> decode() {
return SignedData.readSignedPreparePayloadFrom(RLP.input(data));
}
public static IbftPrepareMessage create(
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> ibftPrepareMessageDecoded) {
public static PrepareMessage create(final SignedData<PreparePayload> signedPayload) {
return new IbftPrepareMessage(ibftPrepareMessageDecoded.encode());
return new PrepareMessage(signedPayload.encode());
}
@Override

@ -0,0 +1,47 @@
/*
* 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.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class ProposalMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.PROPOSAL;
private ProposalMessage(final BytesValue data) {
super(data);
}
public static ProposalMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, ProposalMessage.class, ProposalMessage::new);
}
@Override
public SignedData<ProposalPayload> decode() {
return SignedData.readSignedProposalPayloadFrom(RLP.input(data));
}
public static ProposalMessage create(final SignedData<ProposalPayload> signedPayload) {
return new ProposalMessage(signedPayload.encode());
}
@Override
public int getCode() {
return MESSAGE_CODE;
}
}

@ -12,34 +12,32 @@
*/
package tech.pegasys.pantheon.consensus.ibft.ibftmessage;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedRoundChangeMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftRoundChangeMessage extends AbstractIbftMessage {
public class RoundChangeMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.ROUND_CHANGE;
private IbftRoundChangeMessage(final BytesValue data) {
private RoundChangeMessage(final BytesValue data) {
super(data);
}
public static IbftRoundChangeMessage fromMessage(final MessageData message) {
return fromMessage(
message, MESSAGE_CODE, IbftRoundChangeMessage.class, IbftRoundChangeMessage::new);
public static RoundChangeMessage fromMessage(final MessageData message) {
return fromMessage(message, MESSAGE_CODE, RoundChangeMessage.class, RoundChangeMessage::new);
}
@Override
public IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> decode() {
return IbftSignedMessageData.readIbftSignedRoundChangeMessageDataFrom(RLP.input(data));
public SignedData<RoundChangePayload> decode() {
return SignedData.readSignedRoundChangePayloadFrom(RLP.input(data));
}
public static IbftRoundChangeMessage create(
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> ibftPrepareMessageDecoded) {
public static RoundChangeMessage create(final SignedData<RoundChangePayload> signedPayload) {
return new IbftRoundChangeMessage(ibftPrepareMessageDecoded.encode());
return new RoundChangeMessage(signedPayload.encode());
}
@Override

@ -18,7 +18,7 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public abstract class AbstractIbftUnsignedMessageData {
public abstract class AbstractPayload {
public abstract void writeTo(final RLPOutput rlpOutput);

@ -19,12 +19,12 @@ import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public class IbftUnsignedCommitMessageData extends AbstractIbftUnsignedInRoundMessageData {
public class CommitPayload extends InRoundPayload {
private static final int TYPE = IbftV2.COMMIT;
private final Hash digest;
private final Signature commitSeal;
public IbftUnsignedCommitMessageData(
public CommitPayload(
final ConsensusRoundIdentifier roundIdentifier,
final Hash digest,
final Signature commitSeal) {
@ -33,7 +33,7 @@ public class IbftUnsignedCommitMessageData extends AbstractIbftUnsignedInRoundMe
this.commitSeal = commitSeal;
}
public static IbftUnsignedCommitMessageData readFrom(final RLPInput rlpInput) {
public static CommitPayload readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
@ -41,7 +41,7 @@ public class IbftUnsignedCommitMessageData extends AbstractIbftUnsignedInRoundMe
final Signature commitSeal = rlpInput.readBytesValue(Signature::decode);
rlpInput.leaveList();
return new IbftUnsignedCommitMessageData(roundIdentifier, digest, commitSeal);
return new CommitPayload(roundIdentifier, digest, commitSeal);
}
@Override

@ -1,108 +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.ibftmessagedata;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.util.bytes.BytesValues;
import java.util.Optional;
public class IbftMessageFactory {
private final KeyPair validatorKeyPair;
public IbftMessageFactory(final KeyPair validatorKeyPair) {
this.validatorKeyPair = validatorKeyPair;
}
public IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>
createIbftSignedPrePrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Block block) {
IbftUnsignedPrePrepareMessageData prePrepareUnsignedMessageData =
new IbftUnsignedPrePrepareMessageData(roundIdentifier, block);
return createSignedMessage(prePrepareUnsignedMessageData);
}
public IbftSignedMessageData<IbftUnsignedPrepareMessageData> createIbftSignedPrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
IbftUnsignedPrepareMessageData prepareUnsignedMessageData =
new IbftUnsignedPrepareMessageData(roundIdentifier, digest);
return createSignedMessage(prepareUnsignedMessageData);
}
public IbftSignedMessageData<IbftUnsignedCommitMessageData> createIbftSignedCommitMessageData(
final ConsensusRoundIdentifier roundIdentifier,
final Hash digest,
final Signature commitSeal) {
IbftUnsignedCommitMessageData commitUnsignedMessageData =
new IbftUnsignedCommitMessageData(roundIdentifier, digest, commitSeal);
return createSignedMessage(commitUnsignedMessageData);
}
public IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>
createIbftSignedRoundChangeMessageData(
final ConsensusRoundIdentifier roundIdentifier,
final Optional<IbftPreparedCertificate> preparedCertificate) {
IbftUnsignedRoundChangeMessageData prepareUnsignedMessageData =
new IbftUnsignedRoundChangeMessageData(roundIdentifier, preparedCertificate);
return createSignedMessage(prepareUnsignedMessageData);
}
public IbftSignedMessageData<IbftUnsignedNewRoundMessageData>
createIbftSignedNewRoundChangeMessageData(
final ConsensusRoundIdentifier roundIdentifier,
final IbftRoundChangeCertificate roundChangeCertificate,
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>
ibftPrePrepareMessageData) {
IbftUnsignedNewRoundMessageData newRoundUnsignedMessageData =
new IbftUnsignedNewRoundMessageData(
roundIdentifier, roundChangeCertificate, ibftPrePrepareMessageData);
return createSignedMessage(newRoundUnsignedMessageData);
}
private <M extends AbstractIbftUnsignedMessageData> IbftSignedMessageData<M> createSignedMessage(
final M ibftUnsignedMessage) {
final Signature signature = sign(ibftUnsignedMessage, validatorKeyPair);
return new IbftSignedMessageData<>(
ibftUnsignedMessage, Util.publicKeyToAddress(validatorKeyPair.getPublicKey()), signature);
}
static Hash hashForSignature(final AbstractIbftUnsignedMessageData unsignedMessageData) {
return Hash.hash(
BytesValues.concatenate(
BytesValues.ofUnsignedByte(unsignedMessageData.getMessageType()),
unsignedMessageData.encoded()));
}
private static Signature sign(
final AbstractIbftUnsignedMessageData unsignedMessageData, final KeyPair nodeKeys) {
return SECP256K1.sign(hashForSignature(unsignedMessageData), nodeKeys);
}
}

@ -1,62 +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.ibftmessagedata;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Collection;
public class IbftPreparedCertificate {
private final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePrepareMessage;
private final Collection<IbftSignedMessageData<IbftUnsignedPrepareMessageData>>
ibftPrepareMessages;
public IbftPreparedCertificate(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePrepareMessage,
final Collection<IbftSignedMessageData<IbftUnsignedPrepareMessageData>> ibftPrepareMessages) {
this.ibftPrePrepareMessage = ibftPrePrepareMessage;
this.ibftPrepareMessages = ibftPrepareMessages;
}
public static IbftPreparedCertificate readFrom(final RLPInput rlpInput) {
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePreparedMessage;
final Collection<IbftSignedMessageData<IbftUnsignedPrepareMessageData>> ibftPrepareMessages;
rlpInput.enterList();
ibftPrePreparedMessage =
IbftSignedMessageData.readIbftSignedPrePrepareMessageDataFrom(rlpInput);
ibftPrepareMessages =
rlpInput.readList(IbftSignedMessageData::readIbftSignedPrepareMessageDataFrom);
rlpInput.leaveList();
return new IbftPreparedCertificate(ibftPrePreparedMessage, ibftPrepareMessages);
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
ibftPrePrepareMessage.writeTo(rlpOutput);
rlpOutput.writeList(ibftPrepareMessages, IbftSignedMessageData::writeTo);
rlpOutput.endList();
}
public IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> getIbftPrePrepareMessage() {
return ibftPrePrepareMessage;
}
public Collection<IbftSignedMessageData<IbftUnsignedPrepareMessageData>>
getIbftPrepareMessages() {
return ibftPrepareMessages;
}
}

@ -1,53 +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.ibftmessagedata;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Collection;
public class IbftRoundChangeCertificate {
private final Collection<IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>>
ibftRoundChangeMessages;
public IbftRoundChangeCertificate(
final Collection<IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>>
ibftRoundChangeMessages) {
this.ibftRoundChangeMessages = ibftRoundChangeMessages;
}
public static IbftRoundChangeCertificate readFrom(final RLPInput rlpInput) {
final Collection<IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>>
ibftRoundChangeMessages;
rlpInput.enterList();
ibftRoundChangeMessages =
rlpInput.readList(IbftSignedMessageData::readIbftSignedRoundChangeMessageDataFrom);
rlpInput.leaveList();
return new IbftRoundChangeCertificate(ibftRoundChangeMessages);
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
rlpOutput.writeList(ibftRoundChangeMessages, IbftSignedMessageData::writeTo);
rlpOutput.endList();
}
public Collection<IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>>
getIbftRoundChangeMessages() {
return ibftRoundChangeMessages;
}
}

@ -14,11 +14,10 @@ package tech.pegasys.pantheon.consensus.ibft.ibftmessagedata;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
public abstract class AbstractIbftUnsignedInRoundMessageData
extends AbstractIbftUnsignedMessageData {
public abstract class InRoundPayload extends AbstractPayload {
protected final ConsensusRoundIdentifier roundIdentifier;
protected AbstractIbftUnsignedInRoundMessageData(final ConsensusRoundIdentifier roundIdentifier) {
protected InRoundPayload(final ConsensusRoundIdentifier roundIdentifier) {
this.roundIdentifier = roundIdentifier;
}

@ -0,0 +1,98 @@
/*
* 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.ibftmessagedata;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.util.bytes.BytesValues;
import java.util.Optional;
public class MessageFactory {
private final KeyPair validatorKeyPair;
public MessageFactory(final KeyPair validatorKeyPair) {
this.validatorKeyPair = validatorKeyPair;
}
public SignedData<ProposalPayload> createSignedProposalPayload(
final ConsensusRoundIdentifier roundIdentifier, final Block block) {
final ProposalPayload payload = new ProposalPayload(roundIdentifier, block);
return createSignedMessage(payload);
}
public SignedData<PreparePayload> createSignedPreparePayload(
final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
final PreparePayload payload = new PreparePayload(roundIdentifier, digest);
return createSignedMessage(payload);
}
public SignedData<CommitPayload> createSignedCommitPayload(
final ConsensusRoundIdentifier roundIdentifier,
final Hash digest,
final Signature commitSeal) {
final CommitPayload payload = new CommitPayload(roundIdentifier, digest, commitSeal);
return createSignedMessage(payload);
}
public SignedData<RoundChangePayload> createSignedRoundChangePayload(
final ConsensusRoundIdentifier roundIdentifier,
final Optional<PreparedCertificate> preparedCertificate) {
final RoundChangePayload payload = new RoundChangePayload(roundIdentifier, preparedCertificate);
return createSignedMessage(payload);
}
public SignedData<NewRoundPayload> createSignedNewRoundPayload(
final ConsensusRoundIdentifier roundIdentifier,
final RoundChangeCertificate roundChangeCertificate,
final SignedData<ProposalPayload> proposalPayload) {
final NewRoundPayload payload =
new NewRoundPayload(roundIdentifier, roundChangeCertificate, proposalPayload);
return createSignedMessage(payload);
}
private <M extends AbstractPayload> SignedData<M> createSignedMessage(final M payload) {
final Signature signature = sign(payload, validatorKeyPair);
return new SignedData<>(
payload, Util.publicKeyToAddress(validatorKeyPair.getPublicKey()), signature);
}
static Hash hashForSignature(final AbstractPayload unsignedMessageData) {
return Hash.hash(
BytesValues.concatenate(
BytesValues.ofUnsignedByte(unsignedMessageData.getMessageType()),
unsignedMessageData.encoded()));
}
private static Signature sign(final AbstractPayload unsignedMessageData, final KeyPair nodeKeys) {
return SECP256K1.sign(hashForSignature(unsignedMessageData), nodeKeys);
}
}

@ -17,35 +17,35 @@ import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftV2;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public class IbftUnsignedNewRoundMessageData extends AbstractIbftUnsignedMessageData {
public class NewRoundPayload extends AbstractPayload {
private static final int TYPE = IbftV2.NEW_ROUND;
private final ConsensusRoundIdentifier roundChangeIdentifier;
private final IbftRoundChangeCertificate roundChangeCertificate;
private final RoundChangeCertificate roundChangeCertificate;
private final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePrepareMessage;
private final SignedData<ProposalPayload> proposalPayload;
public IbftUnsignedNewRoundMessageData(
public NewRoundPayload(
final ConsensusRoundIdentifier roundIdentifier,
final IbftRoundChangeCertificate roundChangeCertificate,
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePrepareMessage) {
final RoundChangeCertificate roundChangeCertificate,
final SignedData<ProposalPayload> proposalPayload) {
this.roundChangeIdentifier = roundIdentifier;
this.roundChangeCertificate = roundChangeCertificate;
this.ibftPrePrepareMessage = ibftPrePrepareMessage;
this.proposalPayload = proposalPayload;
}
public ConsensusRoundIdentifier getRoundChangeIdentifier() {
return roundChangeIdentifier;
}
public IbftRoundChangeCertificate getRoundChangeCertificate() {
public RoundChangeCertificate getRoundChangeCertificate() {
return roundChangeCertificate;
}
public IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> getIbftPrePrepareMessage() {
return ibftPrePrepareMessage;
public SignedData<ProposalPayload> getProposalPayload() {
return proposalPayload;
}
@Override
@ -54,22 +54,20 @@ public class IbftUnsignedNewRoundMessageData extends AbstractIbftUnsignedMessage
rlpOutput.startList();
roundChangeIdentifier.writeTo(rlpOutput);
roundChangeCertificate.writeTo(rlpOutput);
ibftPrePrepareMessage.writeTo(rlpOutput);
proposalPayload.writeTo(rlpOutput);
rlpOutput.endList();
}
public static IbftUnsignedNewRoundMessageData readFrom(final RLPInput rlpInput) {
public static NewRoundPayload readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
final IbftRoundChangeCertificate roundChangeCertificate =
IbftRoundChangeCertificate.readFrom(rlpInput);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrePrepareMessage =
IbftSignedMessageData.readIbftSignedPrePrepareMessageDataFrom(rlpInput);
final RoundChangeCertificate roundChangeCertificate = RoundChangeCertificate.readFrom(rlpInput);
final SignedData<ProposalPayload> proposalPayload =
SignedData.readSignedProposalPayloadFrom(rlpInput);
rlpInput.leaveList();
return new IbftUnsignedNewRoundMessageData(
roundIdentifier, roundChangeCertificate, ibftPrePrepareMessage);
return new NewRoundPayload(roundIdentifier, roundChangeCertificate, proposalPayload);
}
@Override

@ -18,24 +18,23 @@ import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public class IbftUnsignedPrepareMessageData extends AbstractIbftUnsignedInRoundMessageData {
public class PreparePayload extends InRoundPayload {
private static final int TYPE = IbftV2.PREPARE;
private final Hash digest;
public IbftUnsignedPrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
public PreparePayload(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
super(roundIdentifier);
this.digest = digest;
}
public static IbftUnsignedPrepareMessageData readFrom(final RLPInput rlpInput) {
public static PreparePayload readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
final Hash digest = readDigest(rlpInput);
rlpInput.leaveList();
return new IbftUnsignedPrepareMessageData(roundIdentifier, digest);
return new PreparePayload(roundIdentifier, digest);
}
@Override

@ -0,0 +1,58 @@
/*
* 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.ibftmessagedata;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Collection;
public class PreparedCertificate {
private final SignedData<ProposalPayload> proposalPayload;
private final Collection<SignedData<PreparePayload>> preparePayloads;
public PreparedCertificate(
final SignedData<ProposalPayload> proposalPayload,
final Collection<SignedData<PreparePayload>> preparePayloads) {
this.proposalPayload = proposalPayload;
this.preparePayloads = preparePayloads;
}
public static PreparedCertificate readFrom(final RLPInput rlpInput) {
final SignedData<ProposalPayload> proposalMessage;
final Collection<SignedData<PreparePayload>> prepareMessages;
rlpInput.enterList();
proposalMessage = SignedData.readSignedProposalPayloadFrom(rlpInput);
prepareMessages = rlpInput.readList(SignedData::readSignedPreparePayloadFrom);
rlpInput.leaveList();
return new PreparedCertificate(proposalMessage, prepareMessages);
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
proposalPayload.writeTo(rlpOutput);
rlpOutput.writeList(preparePayloads, SignedData::writeTo);
rlpOutput.endList();
}
public SignedData<ProposalPayload> getProposalPayload() {
return proposalPayload;
}
public Collection<SignedData<PreparePayload>> getPreparePayloads() {
return preparePayloads;
}
}

@ -19,20 +19,17 @@ import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
// NOTE: Implementation of all methods of this class is still pending. This class was added to show
// how a PreparedCertificate is encoded and decoded inside a RoundChange message
public class IbftUnsignedPrePrepareMessageData extends AbstractIbftUnsignedInRoundMessageData {
public class ProposalPayload extends InRoundPayload {
private static final int TYPE = IbftV2.PRE_PREPARE;
private static final int TYPE = IbftV2.PROPOSAL;
private final Block block;
public IbftUnsignedPrePrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Block block) {
public ProposalPayload(final ConsensusRoundIdentifier roundIdentifier, final Block block) {
super(roundIdentifier);
this.block = block;
}
public static IbftUnsignedPrePrepareMessageData readFrom(final RLPInput rlpInput) {
public static ProposalPayload readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
@ -40,7 +37,7 @@ public class IbftUnsignedPrePrepareMessageData extends AbstractIbftUnsignedInRou
Block.readFrom(rlpInput, IbftBlockHashing::calculateDataHashForCommittedSeal);
rlpInput.leaveList();
return new IbftUnsignedPrePrepareMessageData(roundIdentifier, block);
return new ProposalPayload(roundIdentifier, block);
}
@Override

@ -0,0 +1,48 @@
/*
* 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.ibftmessagedata;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Collection;
public class RoundChangeCertificate {
private final Collection<SignedData<RoundChangePayload>> roundChangePayloads;
public RoundChangeCertificate(
final Collection<SignedData<RoundChangePayload>> roundChangePayloads) {
this.roundChangePayloads = roundChangePayloads;
}
public static RoundChangeCertificate readFrom(final RLPInput rlpInput) {
final Collection<SignedData<RoundChangePayload>> roundChangePayloads;
rlpInput.enterList();
roundChangePayloads = rlpInput.readList(SignedData::readSignedRoundChangePayloadFrom);
rlpInput.leaveList();
return new RoundChangeCertificate(roundChangePayloads);
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
rlpOutput.writeList(roundChangePayloads, SignedData::writeTo);
rlpOutput.endList();
}
public Collection<SignedData<RoundChangePayload>> getRoundChangePayloads() {
return roundChangePayloads;
}
}

@ -20,18 +20,18 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Optional;
public class IbftUnsignedRoundChangeMessageData extends AbstractIbftUnsignedMessageData {
public class RoundChangePayload extends AbstractPayload {
private static final int TYPE = IbftV2.PREPARE;
private final ConsensusRoundIdentifier roundChangeIdentifier;
// The validator may not hae any prepared certificate
private final Optional<IbftPreparedCertificate> preparedCertificate;
private final Optional<PreparedCertificate> preparedCertificate;
public IbftUnsignedRoundChangeMessageData(
public RoundChangePayload(
final ConsensusRoundIdentifier roundIdentifier,
final Optional<IbftPreparedCertificate> preparedCertificate) {
final Optional<PreparedCertificate> preparedCertificate) {
this.roundChangeIdentifier = roundIdentifier;
this.preparedCertificate = preparedCertificate;
}
@ -40,7 +40,7 @@ public class IbftUnsignedRoundChangeMessageData extends AbstractIbftUnsignedMess
return roundChangeIdentifier;
}
public Optional<IbftPreparedCertificate> getPreparedCertificate() {
public Optional<PreparedCertificate> getPreparedCertificate() {
return preparedCertificate;
}
@ -59,21 +59,21 @@ public class IbftUnsignedRoundChangeMessageData extends AbstractIbftUnsignedMess
ibftMessage.endList();
}
public static IbftUnsignedRoundChangeMessageData readFrom(final RLPInput rlpInput) {
public static RoundChangePayload readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
final Optional<IbftPreparedCertificate> preparedCertificate;
final Optional<PreparedCertificate> preparedCertificate;
if (rlpInput.nextIsNull()) {
rlpInput.skipNext();
preparedCertificate = Optional.empty();
} else {
preparedCertificate = Optional.of(IbftPreparedCertificate.readFrom(rlpInput));
preparedCertificate = Optional.of(PreparedCertificate.readFrom(rlpInput));
}
rlpInput.leaveList();
return new IbftUnsignedRoundChangeMessageData(roundIdentifier, preparedCertificate);
return new RoundChangePayload(roundIdentifier, preparedCertificate);
}
@Override

@ -20,15 +20,14 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import tech.pegasys.pantheon.util.bytes.BytesValue;
public class IbftSignedMessageData<M extends AbstractIbftUnsignedMessageData> {
public class SignedData<M extends AbstractPayload> {
protected final Address sender;
protected final Signature signature;
protected final M ibftUnsignedMessageData;
protected final M unsignedPayload;
public IbftSignedMessageData(
final M ibftUnsignedMessageData, final Address sender, final Signature signature) {
this.ibftUnsignedMessageData = ibftUnsignedMessageData;
public SignedData(final M unsignedPayload, final Address sender, final Signature signature) {
this.unsignedPayload = unsignedPayload;
this.sender = sender;
this.signature = signature;
}
@ -41,14 +40,14 @@ public class IbftSignedMessageData<M extends AbstractIbftUnsignedMessageData> {
return signature;
}
public M getUnsignedMessageData() {
return ibftUnsignedMessageData;
public M getPayload() {
return unsignedPayload;
}
public void writeTo(final RLPOutput output) {
output.startList();
ibftUnsignedMessageData.writeTo(output);
unsignedPayload.writeTo(output);
output.writeBytesValue(getSignature().encodedBytes());
output.endList();
}
@ -59,72 +58,63 @@ public class IbftSignedMessageData<M extends AbstractIbftUnsignedMessageData> {
return rlpEncode.encoded();
}
public static IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>
readIbftSignedPrePrepareMessageDataFrom(final RLPInput rlpInput) {
public static SignedData<ProposalPayload> readSignedProposalPayloadFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedPrePrepareMessageData unsignedMessageData =
IbftUnsignedPrePrepareMessageData.readFrom(rlpInput);
final ProposalPayload unsignedMessageData = ProposalPayload.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedPrepareMessageData>
readIbftSignedPrepareMessageDataFrom(final RLPInput rlpInput) {
public static SignedData<PreparePayload> readSignedPreparePayloadFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedPrepareMessageData unsignedMessageData =
IbftUnsignedPrepareMessageData.readFrom(rlpInput);
final PreparePayload unsignedMessageData = PreparePayload.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedCommitMessageData>
readIbftSignedCommitMessageDataFrom(final RLPInput rlpInput) {
public static SignedData<CommitPayload> readSignedCommitPayloadFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedCommitMessageData unsignedMessageData =
IbftUnsignedCommitMessageData.readFrom(rlpInput);
final CommitPayload unsignedMessageData = CommitPayload.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>
readIbftSignedRoundChangeMessageDataFrom(final RLPInput rlpInput) {
public static SignedData<RoundChangePayload> readSignedRoundChangePayloadFrom(
final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedRoundChangeMessageData unsignedMessageData =
IbftUnsignedRoundChangeMessageData.readFrom(rlpInput);
final RoundChangePayload unsignedMessageData = RoundChangePayload.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedNewRoundMessageData>
readIbftSignedNewRoundMessageDataFrom(final RLPInput rlpInput) {
public static SignedData<NewRoundPayload> readSignedNewRoundPayloadFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedNewRoundMessageData unsignedMessageData =
IbftUnsignedNewRoundMessageData.readFrom(rlpInput);
final NewRoundPayload unsignedMessageData = NewRoundPayload.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
protected static <M extends AbstractIbftUnsignedMessageData> IbftSignedMessageData<M> from(
protected static <M extends AbstractPayload> SignedData<M> from(
final M unsignedMessageData, final Signature signature) {
final Address sender = recoverSender(unsignedMessageData, signature);
return new IbftSignedMessageData<>(unsignedMessageData, sender, signature);
return new SignedData<>(unsignedMessageData, sender, signature);
}
protected static Signature readSignature(final RLPInput signedMessage) {
@ -132,9 +122,8 @@ public class IbftSignedMessageData<M extends AbstractIbftUnsignedMessageData> {
}
protected static Address recoverSender(
final AbstractIbftUnsignedMessageData unsignedMessageData, final Signature signature) {
final AbstractPayload unsignedMessageData, final Signature signature) {
return Util.signatureToAddress(
signature, IbftMessageFactory.hashForSignature(unsignedMessageData));
return Util.signatureToAddress(signature, MessageFactory.hashForSignature(unsignedMessageData));
}
}

@ -40,7 +40,7 @@ public class IbftSubProtocol implements SubProtocol {
@Override
public boolean isValidMessageCode(final int protocolVersion, final int code) {
switch (code) {
case IbftV2.PRE_PREPARE:
case IbftV2.PROPOSAL:
case IbftV2.PREPARE:
case IbftV2.COMMIT:
case IbftV2.ROUND_CHANGE:

@ -17,11 +17,11 @@ import static tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode.FULL;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.AbstractIbftUnsignedInRoundMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.CommitPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.InRoundPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Block;
@ -47,8 +47,7 @@ public class MessageValidator {
private final ProtocolContext<IbftContext> protocolContext;
private final BlockHeader parentHeader;
private Optional<IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>> preprepareMessage =
Optional.empty();
private Optional<SignedData<ProposalPayload>> proposal = Optional.empty();
public MessageValidator(
final Collection<Address> validators,
@ -65,41 +64,39 @@ public class MessageValidator {
this.parentHeader = parentHeader;
}
public boolean addPreprepareMessage(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> msg) {
public boolean addSignedProposalPayload(final SignedData<ProposalPayload> msg) {
if (preprepareMessage.isPresent()) {
return handleSubsequentPreprepareMessage(preprepareMessage.get(), msg);
if (proposal.isPresent()) {
return handleSubsequentProposal(proposal.get(), msg);
}
if (!validatePreprepareMessage(msg)) {
if (!validateSignedProposalPayload(msg)) {
return false;
}
if (!validateBlocKMatchesPrepareMessageRound(msg.getUnsignedMessageData())) {
if (!validateBlockMatchesProposalRound(msg.getPayload())) {
return false;
}
preprepareMessage = Optional.of(msg);
proposal = Optional.of(msg);
return true;
}
private boolean validatePreprepareMessage(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> msg) {
private boolean validateSignedProposalPayload(final SignedData<ProposalPayload> msg) {
if (!msg.getUnsignedMessageData().getRoundIdentifier().equals(roundIdentifier)) {
LOG.info("Invalid Preprepare message, does not match current round.");
if (!msg.getPayload().getRoundIdentifier().equals(roundIdentifier)) {
LOG.info("Invalid Proposal message, does not match current round.");
return false;
}
if (!msg.getSender().equals(expectedProposer)) {
LOG.info(
"Invalid Preprepare message, was not created by the proposer expected for the "
"Invalid Proposal message, was not created by the proposer expected for the "
+ "associated round.");
return false;
}
final Block proposedBlock = msg.getUnsignedMessageData().getBlock();
final Block proposedBlock = msg.getPayload().getBlock();
if (!headerValidator.validateHeader(
proposedBlock.getHeader(), parentHeader, protocolContext, FULL)) {
LOG.info("Invalid Prepare message, block did not pass header validation.");
@ -109,30 +106,28 @@ public class MessageValidator {
return true;
}
private boolean handleSubsequentPreprepareMessage(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> existingMsg,
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> newMsg) {
private boolean handleSubsequentProposal(
final SignedData<ProposalPayload> existingMsg, final SignedData<ProposalPayload> newMsg) {
if (!existingMsg.getSender().equals(newMsg.getSender())) {
LOG.debug("Received subsequent invalid Preprepare message; sender differs from original.");
LOG.debug("Received subsequent invalid Proposal message; sender differs from original.");
return false;
}
final IbftUnsignedPrePrepareMessageData existingData = existingMsg.getUnsignedMessageData();
final IbftUnsignedPrePrepareMessageData newData = newMsg.getUnsignedMessageData();
final ProposalPayload existingData = existingMsg.getPayload();
final ProposalPayload newData = newMsg.getPayload();
if (!preprepareMessagesAreIdentical(existingData, newData)) {
LOG.debug("Received subsequent invalid Preprepare message; content differs from original.");
if (!proposalMessagesAreIdentical(existingData, newData)) {
LOG.debug("Received subsequent invalid Proposal message; content differs from original.");
return false;
}
return true;
}
public boolean validatePrepareMessage(
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> msg) {
public boolean validatePrepareMessage(final SignedData<PreparePayload> msg) {
final String msgType = "Prepare";
if (!isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable(msg, msgType)) {
if (!isMessageForCurrentRoundFromValidatorAndProposalAvailable(msg, msgType)) {
return false;
}
@ -141,35 +136,32 @@ public class MessageValidator {
return false;
}
return validateDigestMatchesPreprepareBlock(msg.getUnsignedMessageData().getDigest(), msgType);
return validateDigestMatchesProposal(msg.getPayload().getDigest(), msgType);
}
public boolean validateCommmitMessage(
final IbftSignedMessageData<IbftUnsignedCommitMessageData> msg) {
public boolean validateCommmitMessage(final SignedData<CommitPayload> msg) {
final String msgType = "Commit";
if (!isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable(msg, msgType)) {
if (!isMessageForCurrentRoundFromValidatorAndProposalAvailable(msg, msgType)) {
return false;
}
final Block proposedBlock = preprepareMessage.get().getUnsignedMessageData().getBlock();
final Block proposedBlock = proposal.get().getPayload().getBlock();
final Address commitSealCreator =
Util.signatureToAddress(
msg.getUnsignedMessageData().getCommitSeal(), proposedBlock.getHash());
Util.signatureToAddress(msg.getPayload().getCommitSeal(), proposedBlock.getHash());
if (!commitSealCreator.equals(msg.getSender())) {
LOG.info("Invalid Commit message. Seal was not created by the message transmitter.");
return false;
}
return validateDigestMatchesPreprepareBlock(msg.getUnsignedMessageData().getDigest(), msgType);
return validateDigestMatchesProposal(msg.getPayload().getDigest(), msgType);
}
private boolean isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable(
final IbftSignedMessageData<? extends AbstractIbftUnsignedInRoundMessageData> msg,
final String msgType) {
private boolean isMessageForCurrentRoundFromValidatorAndProposalAvailable(
final SignedData<? extends InRoundPayload> msg, final String msgType) {
if (!msg.getUnsignedMessageData().getRoundIdentifier().equals(roundIdentifier)) {
if (!msg.getPayload().getRoundIdentifier().equals(roundIdentifier)) {
LOG.info("Invalid {} message, does not match current round.", msgType);
return false;
}
@ -181,18 +173,18 @@ public class MessageValidator {
return false;
}
if (!preprepareMessage.isPresent()) {
if (!proposal.isPresent()) {
LOG.info(
"Unable to validate {} message. No Preprepare message exists against "
+ "which to validate block digest.",
"Unable to validate {} message. No Proposal exists against which to validate "
+ "block digest.",
msgType);
return false;
}
return true;
}
private boolean validateDigestMatchesPreprepareBlock(final Hash digest, final String msgType) {
final Block proposedBlock = preprepareMessage.get().getUnsignedMessageData().getBlock();
private boolean validateDigestMatchesProposal(final Hash digest, final String msgType) {
final Block proposedBlock = proposal.get().getPayload().getBlock();
if (!digest.equals(proposedBlock.getHash())) {
LOG.info(
"Illegal {} message, digest does not match the block in the Prepare Message.", msgType);
@ -201,19 +193,18 @@ public class MessageValidator {
return true;
}
private boolean preprepareMessagesAreIdentical(
final IbftUnsignedPrePrepareMessageData right, final IbftUnsignedPrePrepareMessageData left) {
private boolean proposalMessagesAreIdentical(
final ProposalPayload right, final ProposalPayload left) {
return right.getBlock().getHash().equals(left.getBlock().getHash())
&& right.getRoundIdentifier().equals(left.getRoundIdentifier());
}
private boolean validateBlocKMatchesPrepareMessageRound(
final IbftUnsignedPrePrepareMessageData msgData) {
final ConsensusRoundIdentifier msgRound = msgData.getRoundIdentifier();
private boolean validateBlockMatchesProposalRound(final ProposalPayload payload) {
final ConsensusRoundIdentifier msgRound = payload.getRoundIdentifier();
final IbftExtraData extraData =
IbftExtraData.decode(msgData.getBlock().getHeader().getExtraData());
IbftExtraData.decode(payload.getBlock().getHeader().getExtraData());
if (extraData.getRound() != msgRound.getRoundNumber()) {
LOG.info("Invalid Preprepare message, round number in block does not match that in message.");
LOG.info("Invalid Proposal message, round number in block does not match that in message.");
return false;
}
return true;

@ -13,11 +13,11 @@
package tech.pegasys.pantheon.consensus.ibft.validation;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftPreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedRoundChangeMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.ethereum.core.Address;
import java.util.Collection;
@ -45,8 +45,7 @@ public class RoundChangeMessageValidator {
this.currentRound = currentRound;
}
public boolean validateMessage(
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg) {
public boolean validateMessage(final SignedData<RoundChangePayload> msg) {
if (!validators.contains(msg.getSender())) {
LOG.info(
@ -55,33 +54,30 @@ public class RoundChangeMessageValidator {
return false;
}
final ConsensusRoundIdentifier roundChangeTarget =
msg.getUnsignedMessageData().getRoundChangeIdentifier();
final ConsensusRoundIdentifier targetRound = msg.getPayload().getRoundChangeIdentifier();
if (roundChangeTarget.getSequenceNumber() != currentRound.getSequenceNumber()) {
if (targetRound.getSequenceNumber() != currentRound.getSequenceNumber()) {
LOG.info("Invalid RoundChange message, not valid for local chain height.");
return false;
}
if (msg.getUnsignedMessageData().getPreparedCertificate().isPresent()) {
final IbftPreparedCertificate certificate =
msg.getUnsignedMessageData().getPreparedCertificate().get();
if (msg.getPayload().getPreparedCertificate().isPresent()) {
final PreparedCertificate certificate = msg.getPayload().getPreparedCertificate().get();
return validatePrepareCertificate(certificate, roundChangeTarget);
return validatePrepareCertificate(certificate, targetRound);
}
return true;
}
private boolean validatePrepareCertificate(
final IbftPreparedCertificate certificate, final ConsensusRoundIdentifier roundChangeTarget) {
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMessage =
certificate.getIbftPrePrepareMessage();
final PreparedCertificate certificate, final ConsensusRoundIdentifier roundChangeTarget) {
final SignedData<ProposalPayload> proposalMessage = certificate.getProposalPayload();
final ConsensusRoundIdentifier prepareCertRound =
preprepareMessage.getUnsignedMessageData().getRoundIdentifier();
proposalMessage.getPayload().getRoundIdentifier();
if (!validatePreprepareCertificateRound(prepareCertRound, roundChangeTarget)) {
if (!validatePreparedCertificateRound(prepareCertRound, roundChangeTarget)) {
return false;
}
@ -90,22 +86,21 @@ public class RoundChangeMessageValidator {
}
private boolean validateConsistencyOfPrepareCertificateMessages(
final IbftPreparedCertificate certificate, final MessageValidator messageValidator) {
final PreparedCertificate certificate, final MessageValidator messageValidator) {
if (!messageValidator.addPreprepareMessage(certificate.getIbftPrePrepareMessage())) {
LOG.info("Invalid RoundChange message, embedded Preprepare message failed validation.");
if (!messageValidator.addSignedProposalPayload(certificate.getProposalPayload())) {
LOG.info("Invalid RoundChange message, embedded Proposal message failed validation.");
return false;
}
if (certificate.getIbftPrepareMessages().size() < minimumPrepareMessages) {
if (certificate.getPreparePayloads().size() < minimumPrepareMessages) {
LOG.info(
"Invalid RoundChange message, insufficient prepare messages exist to justify "
"Invalid RoundChange message, insufficient Prepare messages exist to justify "
+ "prepare certificate.");
return false;
}
for (final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg :
certificate.getIbftPrepareMessages()) {
for (final SignedData<PreparePayload> prepareMsg : certificate.getPreparePayloads()) {
if (!messageValidator.validatePrepareMessage(prepareMsg)) {
LOG.info("Invalid RoundChange message, embedded Prepare message failed validation.");
return false;
@ -115,18 +110,18 @@ public class RoundChangeMessageValidator {
return true;
}
private boolean validatePreprepareCertificateRound(
private boolean validatePreparedCertificateRound(
final ConsensusRoundIdentifier prepareCertRound,
final ConsensusRoundIdentifier roundChangeTarget) {
if (prepareCertRound.getSequenceNumber() != roundChangeTarget.getSequenceNumber()) {
LOG.info("Invalid RoundChange message, PreprepareCertificate is not for local chain height.");
LOG.info("Invalid RoundChange message, PreparedCertificate is not for local chain height.");
return false;
}
if (prepareCertRound.getRoundNumber() >= roundChangeTarget.getRoundNumber()) {
LOG.info(
"Invalid RoundChange message, PreprepareCertificate is newer than RoundChange target.");
"Invalid RoundChange message, PreparedCertificate is newer than RoundChange target.");
return false;
}
return true;

@ -20,11 +20,11 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftMessageFactory;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.CommitPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.ProposalPayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
@ -55,10 +55,9 @@ public class MessageValidatorTest {
private final KeyPair proposerKey = KeyPair.generate();
private final KeyPair validatorKey = KeyPair.generate();
private final KeyPair nonValidatorKey = KeyPair.generate();
private final IbftMessageFactory proposerMessageFactory = new IbftMessageFactory(proposerKey);
private final IbftMessageFactory validatorMessageFactory = new IbftMessageFactory(validatorKey);
private final IbftMessageFactory nonValidatorMessageFactory =
new IbftMessageFactory(nonValidatorKey);
private final MessageFactory proposerMessageFactory = new MessageFactory(proposerKey);
private final MessageFactory validatorMessageFactory = new MessageFactory(validatorKey);
private final MessageFactory nonValidatorMessageFactory = new MessageFactory(nonValidatorKey);
private final List<Address> validators = Lists.newArrayList();
@ -107,16 +106,16 @@ public class MessageValidatorTest {
@Test
public void receivingAPrepareMessageBeforePrePrepareFails() {
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
proposerMessageFactory.createIbftSignedPrepareMessageData(roundIdentifier, Hash.ZERO);
final SignedData<PreparePayload> prepareMsg =
proposerMessageFactory.createSignedPreparePayload(roundIdentifier, Hash.ZERO);
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse();
}
@Test
public void receivingACommitMessageBeforePreprepareFails() {
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg =
proposerMessageFactory.createIbftSignedCommitMessageData(
final SignedData<CommitPayload> commitMsg =
proposerMessageFactory.createSignedCommitPayload(
roundIdentifier, Hash.ZERO, SECP256K1.sign(Hash.ZERO, proposerKey));
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse();
@ -124,48 +123,46 @@ public class MessageValidatorTest {
@Test
public void receivingPreprepareMessageFromNonProposerFails() {
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
validatorMessageFactory.createIbftSignedPrePrepareMessageData(
roundIdentifier, mock(Block.class));
final SignedData<ProposalPayload> preprepareMsg =
validatorMessageFactory.createSignedProposalPayload(roundIdentifier, mock(Block.class));
assertThat(validator.addPreprepareMessage(preprepareMsg)).isFalse();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isFalse();
}
@Test
public void receivingPreprepareMessageWithIllegalBlockFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(false);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(
roundIdentifier, mock(Block.class));
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, mock(Block.class));
assertThat(validator.addPreprepareMessage(preprepareMsg)).isFalse();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isFalse();
}
@Test
public void receivingPrepareFromProposerFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
proposerMessageFactory.createIbftSignedPrepareMessageData(roundIdentifier, block.getHash());
final SignedData<PreparePayload> prepareMsg =
proposerMessageFactory.createSignedPreparePayload(roundIdentifier, block.getHash());
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse();
}
@Test
public void receivingPrepareFromNonValidatorFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
nonValidatorMessageFactory.createIbftSignedPrepareMessageData(
roundIdentifier, block.getHash());
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
final SignedData<PreparePayload> prepareMsg =
nonValidatorMessageFactory.createSignedPreparePayload(roundIdentifier, block.getHash());
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse();
}
@ -173,20 +170,19 @@ public class MessageValidatorTest {
public void receivingMessagesWithDifferentRoundIdFromPreprepareFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
final ConsensusRoundIdentifier invalidRoundIdentifier =
new ConsensusRoundIdentifier(
roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() + 1);
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
validatorMessageFactory.createIbftSignedPrepareMessageData(
invalidRoundIdentifier, block.getHash());
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg =
validatorMessageFactory.createIbftSignedCommitMessageData(
final SignedData<PreparePayload> prepareMsg =
validatorMessageFactory.createSignedPreparePayload(invalidRoundIdentifier, block.getHash());
final SignedData<CommitPayload> commitMsg =
validatorMessageFactory.createSignedCommitPayload(
invalidRoundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), proposerKey));
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse();
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse();
}
@ -195,13 +191,12 @@ public class MessageValidatorTest {
public void receivingPrepareNonProposerValidatorWithCorrectRoundIsSuccessful() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
validatorMessageFactory.createIbftSignedPrepareMessageData(
roundIdentifier, block.getHash());
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
final SignedData<PreparePayload> prepareMsg =
validatorMessageFactory.createSignedPreparePayload(roundIdentifier, block.getHash());
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validatePrepareMessage(prepareMsg)).isTrue();
}
@ -209,14 +204,14 @@ public class MessageValidatorTest {
public void receivingACommitMessageWithAnInvalidCommitSealFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg =
proposerMessageFactory.createIbftSignedCommitMessageData(
final SignedData<CommitPayload> commitMsg =
proposerMessageFactory.createSignedCommitPayload(
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), nonValidatorKey));
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse();
}
@ -224,18 +219,18 @@ public class MessageValidatorTest {
public void commitMessageContainingValidSealFromValidatorIsSuccessful() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
final IbftSignedMessageData<IbftUnsignedCommitMessageData> proposerCommitMsg =
proposerMessageFactory.createIbftSignedCommitMessageData(
final SignedData<CommitPayload> proposerCommitMsg =
proposerMessageFactory.createSignedCommitPayload(
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), proposerKey));
final IbftSignedMessageData<IbftUnsignedCommitMessageData> validatorCommitMsg =
validatorMessageFactory.createIbftSignedCommitMessageData(
final SignedData<CommitPayload> validatorCommitMsg =
validatorMessageFactory.createSignedCommitPayload(
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), validatorKey));
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
assertThat(validator.validateCommmitMessage(proposerCommitMsg)).isTrue();
assertThat(validator.validateCommmitMessage(validatorCommitMsg)).isTrue();
}
@ -244,39 +239,39 @@ public class MessageValidatorTest {
public void subsequentPreprepareHasDifferentSenderFails() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg =
validatorMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isFalse();
final SignedData<ProposalPayload> secondPreprepareMsg =
validatorMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addSignedProposalPayload(secondPreprepareMsg)).isFalse();
}
@Test
public void subsequentPreprepareHasDifferentContentFails() {
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
final ConsensusRoundIdentifier newRoundIdentifier = new ConsensusRoundIdentifier(3, 0);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(newRoundIdentifier, block);
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isFalse();
final SignedData<ProposalPayload> secondPreprepareMsg =
proposerMessageFactory.createSignedProposalPayload(newRoundIdentifier, block);
assertThat(validator.addSignedProposalPayload(secondPreprepareMsg)).isFalse();
}
@Test
public void subsequentPreprepareHasIdenticalSenderAndContentIsSuccessful() {
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue();
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isTrue();
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isTrue();
final SignedData<ProposalPayload> secondPreprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addSignedProposalPayload(secondPreprepareMsg)).isTrue();
}
@Test
@ -284,9 +279,9 @@ public class MessageValidatorTest {
insertRoundToBlockHeader(roundIdentifier.getRoundNumber() + 1);
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true);
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg =
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block);
final SignedData<ProposalPayload> preprepareMsg =
proposerMessageFactory.createSignedProposalPayload(roundIdentifier, block);
assertThat(validator.addPreprepareMessage(preprepareMsg)).isFalse();
assertThat(validator.addSignedProposalPayload(preprepareMsg)).isFalse();
}
}

@ -21,11 +21,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftMessageFactory;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftPreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedRoundChangeMessageData;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.MessageFactory;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.PreparedCertificate;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.RoundChangePayload;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.SignedData;
import tech.pegasys.pantheon.consensus.ibft.validation.RoundChangeMessageValidator.MessageValidatorFactory;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
@ -46,10 +46,9 @@ public class RoundChangeMessageValidatorTest {
private final KeyPair proposerKey = KeyPair.generate();
private final KeyPair validatorKey = KeyPair.generate();
private final KeyPair nonValidatorKey = KeyPair.generate();
private final IbftMessageFactory proposerMessageFactory = new IbftMessageFactory(proposerKey);
private final IbftMessageFactory validatorMessageFactory = new IbftMessageFactory(validatorKey);
private final IbftMessageFactory nonValidatorMessageFactory =
new IbftMessageFactory(nonValidatorKey);
private final MessageFactory proposerMessageFactory = new MessageFactory(proposerKey);
private final MessageFactory validatorMessageFactory = new MessageFactory(validatorKey);
private final MessageFactory nonValidatorMessageFactory = new MessageFactory(nonValidatorKey);
private final ConsensusRoundIdentifier currentRound = new ConsensusRoundIdentifier(2, 3);
private final ConsensusRoundIdentifier targetRound = new ConsensusRoundIdentifier(2, 4);
@ -73,82 +72,76 @@ public class RoundChangeMessageValidatorTest {
// By default, have all basic messages being valid thus any failures are attributed to logic
// in the RoundChangeMessageValidator
when(basicValidator.addPreprepareMessage(any())).thenReturn(true);
when(basicValidator.addSignedProposalPayload(any())).thenReturn(true);
when(basicValidator.validatePrepareMessage(any())).thenReturn(true);
}
@Test
public void roundChangeSentByNonValidatorFails() {
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
nonValidatorMessageFactory.createIbftSignedRoundChangeMessageData(
targetRound, Optional.empty());
final SignedData<RoundChangePayload> msg =
nonValidatorMessageFactory.createSignedRoundChangePayload(targetRound, Optional.empty());
assertThat(validator.validateMessage(msg)).isFalse();
}
@Test
public void roundChangeContainingNoCertificateIsSuccessful() {
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
targetRound, Optional.empty());
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(targetRound, Optional.empty());
assertThat(validator.validateMessage(msg)).isTrue();
}
@Test
public void roundChangeContainingInvalidPreprepareFails() {
final IbftPreparedCertificate prepareCertificate =
new IbftPreparedCertificate(
proposerMessageFactory.createIbftSignedPrePrepareMessageData(currentRound, block),
final PreparedCertificate prepareCertificate =
new PreparedCertificate(
proposerMessageFactory.createSignedProposalPayload(currentRound, block),
Collections.emptyList());
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate));
when(basicValidator.addPreprepareMessage(any())).thenReturn(false);
when(basicValidator.addSignedProposalPayload(any())).thenReturn(false);
assertThat(validator.validateMessage(msg)).isFalse();
verify(validatorFactory, times(1))
.createAt(
prepareCertificate
.getIbftPrePrepareMessage()
.getUnsignedMessageData()
.getRoundIdentifier());
.createAt(prepareCertificate.getProposalPayload().getPayload().getRoundIdentifier());
verify(basicValidator, times(1))
.addPreprepareMessage(prepareCertificate.getIbftPrePrepareMessage());
.addSignedProposalPayload(prepareCertificate.getProposalPayload());
verify(basicValidator, never()).validatePrepareMessage(any());
verify(basicValidator, never()).validateCommmitMessage(any());
}
@Test
public void roundChangeContainingValidPreprepareButNoPrepareMessagesFails() {
final IbftPreparedCertificate prepareCertificate =
new IbftPreparedCertificate(
proposerMessageFactory.createIbftSignedPrePrepareMessageData(currentRound, block),
final PreparedCertificate prepareCertificate =
new PreparedCertificate(
proposerMessageFactory.createSignedProposalPayload(currentRound, block),
Collections.emptyList());
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate));
when(basicValidator.addPreprepareMessage(any())).thenReturn(true);
when(basicValidator.addSignedProposalPayload(any())).thenReturn(true);
assertThat(validator.validateMessage(msg)).isFalse();
}
@Test
public void roundChangeInvalidPrepareMessageFromProposerFails() {
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
validatorMessageFactory.createIbftSignedPrepareMessageData(currentRound, block.getHash());
final IbftPreparedCertificate prepareCertificate =
new IbftPreparedCertificate(
proposerMessageFactory.createIbftSignedPrePrepareMessageData(currentRound, block),
final SignedData<PreparePayload> prepareMsg =
validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash());
final PreparedCertificate prepareCertificate =
new PreparedCertificate(
proposerMessageFactory.createSignedProposalPayload(currentRound, block),
Lists.newArrayList(prepareMsg));
when(basicValidator.addPreprepareMessage(any())).thenReturn(true);
when(basicValidator.addSignedProposalPayload(any())).thenReturn(true);
when(basicValidator.validatePrepareMessage(any())).thenReturn(false);
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate));
assertThat(validator.validateMessage(msg)).isFalse();
@ -162,8 +155,8 @@ public class RoundChangeMessageValidatorTest {
final ConsensusRoundIdentifier latterRoundIdentifier =
new ConsensusRoundIdentifier(currentRound.getSequenceNumber() + 1, 1);
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
latterRoundIdentifier, Optional.empty());
assertThat(validator.validateMessage(msg)).isFalse();
@ -176,15 +169,15 @@ public class RoundChangeMessageValidatorTest {
new ConsensusRoundIdentifier(
currentRound.getSequenceNumber(), currentRound.getRoundNumber() + 2);
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
validatorMessageFactory.createIbftSignedPrepareMessageData(futureRound, block.getHash());
final IbftPreparedCertificate prepareCertificate =
new IbftPreparedCertificate(
proposerMessageFactory.createIbftSignedPrePrepareMessageData(futureRound, block),
final SignedData<PreparePayload> prepareMsg =
validatorMessageFactory.createSignedPreparePayload(futureRound, block.getHash());
final PreparedCertificate prepareCertificate =
new PreparedCertificate(
proposerMessageFactory.createSignedProposalPayload(futureRound, block),
Lists.newArrayList(prepareMsg));
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate));
assertThat(validator.validateMessage(msg)).isFalse();
@ -195,30 +188,26 @@ public class RoundChangeMessageValidatorTest {
@Test
public void roudnChangeWithPastPreprepareForCurrentHeightIsSuccessful() {
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg =
validatorMessageFactory.createIbftSignedPrepareMessageData(currentRound, block.getHash());
final IbftPreparedCertificate prepareCertificate =
new IbftPreparedCertificate(
proposerMessageFactory.createIbftSignedPrePrepareMessageData(currentRound, block),
final SignedData<PreparePayload> prepareMsg =
validatorMessageFactory.createSignedPreparePayload(currentRound, block.getHash());
final PreparedCertificate prepareCertificate =
new PreparedCertificate(
proposerMessageFactory.createSignedProposalPayload(currentRound, block),
Lists.newArrayList(prepareMsg));
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> msg =
proposerMessageFactory.createIbftSignedRoundChangeMessageData(
final SignedData<RoundChangePayload> msg =
proposerMessageFactory.createSignedRoundChangePayload(
targetRound, Optional.of(prepareCertificate));
when(basicValidator.addPreprepareMessage(prepareCertificate.getIbftPrePrepareMessage()))
when(basicValidator.addSignedProposalPayload(prepareCertificate.getProposalPayload()))
.thenReturn(true);
when(basicValidator.validatePrepareMessage(prepareMsg)).thenReturn(true);
assertThat(validator.validateMessage(msg)).isTrue();
verify(validatorFactory, times(1))
.createAt(
prepareCertificate
.getIbftPrePrepareMessage()
.getUnsignedMessageData()
.getRoundIdentifier());
.createAt(prepareCertificate.getProposalPayload().getPayload().getRoundIdentifier());
verify(basicValidator, times(1))
.addPreprepareMessage(prepareCertificate.getIbftPrePrepareMessage());
.addSignedProposalPayload(prepareCertificate.getProposalPayload());
verify(basicValidator, times(1)).validatePrepareMessage(prepareMsg);
}
}

Loading…
Cancel
Save