diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java index 8ae7b285df..d729077a57 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java @@ -12,6 +12,8 @@ */ 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; @@ -32,9 +34,15 @@ public class IbftMessages { case IbftV2.PREPARE: return IbftPrepareMessage.fromMessage(messageData).decode(); + case IbftV2.COMMIT: + return IbftCommitMessage.fromMessage(messageData).decode(); + case IbftV2.ROUND_CHANGE: return IbftRoundChangeMessage.fromMessage(messageData).decode(); + case IbftV2.NEW_ROUND: + return IbftNewRoundMessage.fromMessage(messageData).decode(); + default: throw new IllegalArgumentException( "Received message does not conform to any recognised IBFT message structure."); diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java index 1a0cca471e..0943aefa57 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java @@ -13,13 +13,35 @@ package tech.pegasys.pantheon.consensus.ibft.ibftmessage; import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData; +import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; import tech.pegasys.pantheon.ethereum.p2p.wire.AbstractMessageData; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.util.function.Function; + public abstract class AbstractIbftMessage extends AbstractMessageData { protected AbstractIbftMessage(final BytesValue data) { super(data); } public abstract IbftSignedMessageData decode(); + + protected static T fromMessage( + final MessageData message, + final int messageCode, + final Class clazz, + final Function constructor) { + if (clazz.isInstance(message)) { + @SuppressWarnings("unchecked") + T castMessage = (T) message; + return castMessage; + } + final int code = message.getCode(); + if (code != messageCode) { + throw new IllegalArgumentException( + String.format("Message has code %d and thus is not a %s", code, clazz.getSimpleName())); + } + + return constructor.apply(message.getData()); + } } diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftCommitMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftCommitMessage.java new file mode 100644 index 0000000000..91449d6406 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftCommitMessage.java @@ -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.ibftmessage; + +import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData; +import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData; +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 { + + private static final int MESSAGE_CODE = IbftV2.COMMIT; + + private IbftCommitMessage(final BytesValue data) { + super(data); + } + + public static IbftCommitMessage fromMessage(final MessageData message) { + return fromMessage(message, MESSAGE_CODE, IbftCommitMessage.class, IbftCommitMessage::new); + } + + @Override + public IbftSignedMessageData decode() { + return IbftSignedMessageData.readIbftSignedCommitMessageDataFrom(RLP.input(data)); + } + + public static IbftCommitMessage create( + final IbftSignedMessageData ibftPrepareMessageDecoded) { + + return new IbftCommitMessage(ibftPrepareMessageDecoded.encode()); + } + + @Override + public int getCode() { + return MESSAGE_CODE; + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftNewRoundMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftNewRoundMessage.java new file mode 100644 index 0000000000..ddfe381f81 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftNewRoundMessage.java @@ -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.ibftmessage; + +import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData; +import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedNewRoundMessageData; +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 { + + private static final int MESSAGE_CODE = IbftV2.NEW_ROUND; + + private IbftNewRoundMessage(final BytesValue data) { + super(data); + } + + public static IbftNewRoundMessage fromMessage(final MessageData message) { + return fromMessage(message, MESSAGE_CODE, IbftNewRoundMessage.class, IbftNewRoundMessage::new); + } + + @Override + public IbftSignedMessageData decode() { + return IbftSignedMessageData.readIbftSignedNewRoundMessageDataFrom(RLP.input(data)); + } + + public static IbftNewRoundMessage create( + final IbftSignedMessageData ibftPrepareMessageDecoded) { + + return new IbftNewRoundMessage(ibftPrepareMessageDecoded.encode()); + } + + @Override + public int getCode() { + return MESSAGE_CODE; + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java index 18fe8d141f..6d9328dbe9 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java @@ -27,16 +27,8 @@ public class IbftPrePrepareMessage extends AbstractIbftMessage { } public static IbftPrePrepareMessage fromMessage(final MessageData message) { - if (message instanceof IbftPrePrepareMessage) { - return (IbftPrePrepareMessage) message; - } - final int code = message.getCode(); - if (code != MESSAGE_CODE) { - throw new IllegalArgumentException( - String.format("Message has code %d and thus is not a PrePrepareMessage", code)); - } - - return new IbftPrePrepareMessage(message.getData()); + return fromMessage( + message, MESSAGE_CODE, IbftPrePrepareMessage.class, IbftPrePrepareMessage::new); } @Override diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrepareMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrepareMessage.java index 4c44aff9b0..5707af605f 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrepareMessage.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrepareMessage.java @@ -27,16 +27,7 @@ public class IbftPrepareMessage extends AbstractIbftMessage { } public static IbftPrepareMessage fromMessage(final MessageData message) { - if (message instanceof IbftPrepareMessage) { - return (IbftPrepareMessage) message; - } - final int code = message.getCode(); - if (code != MESSAGE_CODE) { - throw new IllegalArgumentException( - String.format("Message has code %d and thus is not a PrepareMessage", code)); - } - - return new IbftPrepareMessage(message.getData()); + return fromMessage(message, MESSAGE_CODE, IbftPrepareMessage.class, IbftPrepareMessage::new); } @Override diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftRoundChangeMessage.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftRoundChangeMessage.java index cd6375babe..5a65b95dcb 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftRoundChangeMessage.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftRoundChangeMessage.java @@ -27,16 +27,8 @@ public class IbftRoundChangeMessage extends AbstractIbftMessage { } public static IbftRoundChangeMessage fromMessage(final MessageData message) { - if (message instanceof IbftRoundChangeMessage) { - return (IbftRoundChangeMessage) message; - } - final int code = message.getCode(); - if (code != MESSAGE_CODE) { - throw new IllegalArgumentException( - String.format("Message has code %d and thus is not a RoundChangeMessage", code)); - } - - return new IbftRoundChangeMessage(message.getData()); + return fromMessage( + message, MESSAGE_CODE, IbftRoundChangeMessage.class, IbftRoundChangeMessage::new); } @Override diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java index 3f7e81647e..5ed334e2d7 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java @@ -18,6 +18,7 @@ public class IbftV2 { public static final int PREPARE = 1; public static final int COMMIT = 2; public static final int ROUND_CHANGE = 3; + public static final int NEW_ROUND = 4; - public static final int MESSAGE_SPACE = 4; + public static final int MESSAGE_SPACE = 5; } diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java index 451368874a..09396a8193 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java @@ -16,6 +16,7 @@ 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; @@ -29,6 +30,16 @@ public class IbftMessageFactory { this.validatorKeyPair = validatorKeyPair; } + public IbftSignedMessageData + createIbftSignedPrePrepareMessageData( + final ConsensusRoundIdentifier roundIdentifier, final Block block) { + + IbftUnsignedPrePrepareMessageData prePrepareUnsignedMessageData = + new IbftUnsignedPrePrepareMessageData(roundIdentifier, block); + + return createSignedMessage(prePrepareUnsignedMessageData); + } + public IbftSignedMessageData createIbftSignedPrepareMessageData( final ConsensusRoundIdentifier roundIdentifier, final Hash digest) { @@ -38,6 +49,17 @@ public class IbftMessageFactory { return createSignedMessage(prepareUnsignedMessageData); } + public IbftSignedMessageData createIbftSignedCommitMessageData( + final ConsensusRoundIdentifier roundIdentifier, + final Hash digest, + final Signature commitSeal) { + + IbftUnsignedCommitMessageData commitUnsignedMessageData = + new IbftUnsignedCommitMessageData(roundIdentifier, digest, commitSeal); + + return createSignedMessage(commitUnsignedMessageData); + } + public IbftSignedMessageData createIbftSignedRoundChangeMessageData( final ConsensusRoundIdentifier roundIdentifier, @@ -49,6 +71,20 @@ public class IbftMessageFactory { return createSignedMessage(prepareUnsignedMessageData); } + public IbftSignedMessageData + createIbftSignedNewRoundChangeMessageData( + final ConsensusRoundIdentifier roundIdentifier, + final IbftRoundChangeCertificate roundChangeCertificate, + final IbftSignedMessageData + ibftPrePrepareMessageData) { + + IbftUnsignedNewRoundMessageData newRoundUnsignedMessageData = + new IbftUnsignedNewRoundMessageData( + roundIdentifier, roundChangeCertificate, ibftPrePrepareMessageData); + + return createSignedMessage(newRoundUnsignedMessageData); + } + private IbftSignedMessageData createSignedMessage( final M ibftUnsignedMessage) { final Signature signature = sign(ibftUnsignedMessage, validatorKeyPair); diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java index 56270b4554..f99d70ed7b 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java @@ -50,4 +50,13 @@ public class IbftPreparedCertificate { rlpOutput.writeList(ibftPrepareMessages, IbftSignedMessageData::writeTo); rlpOutput.endList(); } + + public IbftSignedMessageData getIbftPrePrepareMessage() { + return ibftPrePrepareMessage; + } + + public Collection> + getIbftPrepareMessages() { + return ibftPrepareMessages; + } } diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftRoundChangeCertificate.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftRoundChangeCertificate.java new file mode 100644 index 0000000000..cdda90b9c3 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftRoundChangeCertificate.java @@ -0,0 +1,53 @@ +/* + * 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> + ibftRoundChangeMessages; + + public IbftRoundChangeCertificate( + final Collection> + ibftRoundChangeMessages) { + this.ibftRoundChangeMessages = ibftRoundChangeMessages; + } + + public static IbftRoundChangeCertificate readFrom(final RLPInput rlpInput) { + final Collection> + 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> + getIbftRoundChangeMessages() { + return ibftRoundChangeMessages; + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftSignedMessageData.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftSignedMessageData.java index 0f26204f2c..209d02d889 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftSignedMessageData.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftSignedMessageData.java @@ -83,6 +83,18 @@ public class IbftSignedMessageData { return from(unsignedMessageData, signature); } + public static IbftSignedMessageData + readIbftSignedCommitMessageDataFrom(final RLPInput rlpInput) { + + rlpInput.enterList(); + final IbftUnsignedCommitMessageData unsignedMessageData = + IbftUnsignedCommitMessageData.readFrom(rlpInput); + final Signature signature = readSignature(rlpInput); + rlpInput.leaveList(); + + return from(unsignedMessageData, signature); + } + public static IbftSignedMessageData readIbftSignedRoundChangeMessageDataFrom(final RLPInput rlpInput) { @@ -95,6 +107,18 @@ public class IbftSignedMessageData { return from(unsignedMessageData, signature); } + public static IbftSignedMessageData + readIbftSignedNewRoundMessageDataFrom(final RLPInput rlpInput) { + + rlpInput.enterList(); + final IbftUnsignedNewRoundMessageData unsignedMessageData = + IbftUnsignedNewRoundMessageData.readFrom(rlpInput); + final Signature signature = readSignature(rlpInput); + rlpInput.leaveList(); + + return from(unsignedMessageData, signature); + } + protected static IbftSignedMessageData from( final M unsignedMessageData, final Signature signature) { diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedCommitMessageData.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedCommitMessageData.java new file mode 100644 index 0000000000..314ebf62ec --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedCommitMessageData.java @@ -0,0 +1,69 @@ +/* + * 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.consensus.ibft.ibftmessage.IbftV2; +import tech.pegasys.pantheon.crypto.SECP256K1.Signature; +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 { + private static final int TYPE = IbftV2.COMMIT; + private final Hash digest; + private final Signature commitSeal; + + public IbftUnsignedCommitMessageData( + final ConsensusRoundIdentifier roundIdentifier, + final Hash digest, + final Signature commitSeal) { + super(roundIdentifier); + this.digest = digest; + this.commitSeal = commitSeal; + } + + public static IbftUnsignedCommitMessageData readFrom(final RLPInput rlpInput) { + + rlpInput.enterList(); + final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput); + final Hash digest = readDigest(rlpInput); + final Signature commitSeal = rlpInput.readBytesValue(Signature::decode); + rlpInput.leaveList(); + + return new IbftUnsignedCommitMessageData(roundIdentifier, digest, commitSeal); + } + + @Override + public void writeTo(final RLPOutput rlpOutput) { + + rlpOutput.startList(); + roundIdentifier.writeTo(rlpOutput); + rlpOutput.writeBytesValue(digest); + rlpOutput.writeBytesValue(commitSeal.encodedBytes()); + rlpOutput.endList(); + } + + @Override + public int getMessageType() { + return TYPE; + } + + public Hash getDigest() { + return digest; + } + + public Signature getCommitSeal() { + return commitSeal; + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedNewRoundMessageData.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedNewRoundMessageData.java new file mode 100644 index 0000000000..cf451f4f92 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedNewRoundMessageData.java @@ -0,0 +1,79 @@ +/* + * 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.consensus.ibft.ibftmessage.IbftV2; +import tech.pegasys.pantheon.ethereum.rlp.RLPInput; +import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; + +public class IbftUnsignedNewRoundMessageData extends AbstractIbftUnsignedMessageData { + + private static final int TYPE = IbftV2.NEW_ROUND; + + private final ConsensusRoundIdentifier roundChangeIdentifier; + + private final IbftRoundChangeCertificate roundChangeCertificate; + + private final IbftSignedMessageData ibftPrePrepareMessage; + + public IbftUnsignedNewRoundMessageData( + final ConsensusRoundIdentifier roundIdentifier, + final IbftRoundChangeCertificate roundChangeCertificate, + final IbftSignedMessageData ibftPrePrepareMessage) { + this.roundChangeIdentifier = roundIdentifier; + this.roundChangeCertificate = roundChangeCertificate; + this.ibftPrePrepareMessage = ibftPrePrepareMessage; + } + + public ConsensusRoundIdentifier getRoundChangeIdentifier() { + return roundChangeIdentifier; + } + + public IbftRoundChangeCertificate getRoundChangeCertificate() { + return roundChangeCertificate; + } + + public IbftSignedMessageData getIbftPrePrepareMessage() { + return ibftPrePrepareMessage; + } + + @Override + public void writeTo(final RLPOutput rlpOutput) { + // RLP encode of the message data content (round identifier and prepared certificate) + rlpOutput.startList(); + roundChangeIdentifier.writeTo(rlpOutput); + roundChangeCertificate.writeTo(rlpOutput); + ibftPrePrepareMessage.writeTo(rlpOutput); + rlpOutput.endList(); + } + + public static IbftUnsignedNewRoundMessageData readFrom(final RLPInput rlpInput) { + + rlpInput.enterList(); + final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput); + final IbftRoundChangeCertificate roundChangeCertificate = + IbftRoundChangeCertificate.readFrom(rlpInput); + final IbftSignedMessageData ibftPrePrepareMessage = + IbftSignedMessageData.readIbftSignedPrePrepareMessageDataFrom(rlpInput); + rlpInput.leaveList(); + + return new IbftUnsignedNewRoundMessageData( + roundIdentifier, roundChangeCertificate, ibftPrePrepareMessage); + } + + @Override + public int getMessageType() { + return TYPE; + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrePrepareMessageData.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrePrepareMessageData.java index ad43c6ae69..4378b46880 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrePrepareMessageData.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrePrepareMessageData.java @@ -13,6 +13,8 @@ package tech.pegasys.pantheon.consensus.ibft.ibftmessagedata; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; +import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing; +import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftV2; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.rlp.RLPInput; import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; @@ -21,24 +23,40 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; // how a PreparedCertificate is encoded and decoded inside a RoundChange message public class IbftUnsignedPrePrepareMessageData extends AbstractIbftUnsignedInRoundMessageData { + private static final int TYPE = IbftV2.PRE_PREPARE; + private final Block block; + public IbftUnsignedPrePrepareMessageData( final ConsensusRoundIdentifier roundIdentifier, final Block block) { super(roundIdentifier); + this.block = block; } - public Block getBlock() { - return null; + public static IbftUnsignedPrePrepareMessageData readFrom(final RLPInput rlpInput) { + + rlpInput.enterList(); + final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput); + final Block block = Block.readFrom(rlpInput, IbftBlockHashing::calculateHashOfIbftBlockOnChain); + rlpInput.leaveList(); + + return new IbftUnsignedPrePrepareMessageData(roundIdentifier, block); } @Override - public void writeTo(final RLPOutput rlpOutput) {} + public void writeTo(final RLPOutput rlpOutput) { - @Override - public int getMessageType() { - return 0; + rlpOutput.startList(); + roundIdentifier.writeTo(rlpOutput); + block.writeTo(rlpOutput); + rlpOutput.endList(); } - public static IbftUnsignedPrePrepareMessageData readFrom(final RLPInput rlpInput) { - return null; + public Block getBlock() { + return block; + } + + @Override + public int getMessageType() { + return TYPE; } } diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java index a4a25ab448..37ad419c97 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java @@ -44,6 +44,7 @@ public class IbftSubProtocol implements SubProtocol { case IbftV2.PREPARE: case IbftV2.COMMIT: case IbftV2.ROUND_CHANGE: + case IbftV2.NEW_ROUND: return true; default: diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocolTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocolTest.java index b969560aef..3e1ee3baf8 100644 --- a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocolTest.java +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocolTest.java @@ -22,7 +22,7 @@ public class IbftSubProtocolTest { public void messageSpaceReportsCorrectly() { final IbftSubProtocol subProt = new IbftSubProtocol(); - assertThat(subProt.messageSpace(1)).isEqualTo(4); + assertThat(subProt.messageSpace(1)).isEqualTo(5); } @Test @@ -33,12 +33,13 @@ public class IbftSubProtocolTest { assertThat(subProt.isValidMessageCode(1, 1)).isTrue(); assertThat(subProt.isValidMessageCode(1, 2)).isTrue(); assertThat(subProt.isValidMessageCode(1, 3)).isTrue(); + assertThat(subProt.isValidMessageCode(1, 4)).isTrue(); } @Test public void invalidMessageTypesAreNotAcceptedByTheSubprotocol() { final IbftSubProtocol subProt = new IbftSubProtocol(); - assertThat(subProt.isValidMessageCode(1, 4)).isFalse(); + assertThat(subProt.isValidMessageCode(1, 5)).isFalse(); } }