[EC-183] Add iBFT Prepare and Round Change RLP encoding and decoding (#84)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Roberto Saltini 6 years ago committed by GitHub
parent 2cba87a899
commit 0dff893203
  1. 43
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftMessages.java
  2. 40
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/AbstractIbftMessage.java
  3. 64
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrePrepareMessage.java
  4. 64
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftPrepareMessage.java
  5. 64
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftRoundChangeMessage.java
  6. 23
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessage/IbftV2.java
  7. 28
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/AbstractIbftUnsignedInRoundMessageData.java
  8. 37
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/AbstractIbftUnsignedMessageData.java
  9. 72
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftMessageFactory.java
  10. 53
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftPreparedCertificate.java
  11. 108
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftSignedMessageData.java
  12. 44
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrePrepareMessageData.java
  13. 59
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedPrepareMessageData.java
  14. 84
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/ibftmessagedata/IbftUnsignedRoundChangeMessageData.java
  15. 49
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/protocol/IbftSubProtocol.java

@ -0,0 +1,43 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.consensus.ibft;
import tech.pegasys.pantheon.consensus.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.IbftV2;
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData;
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) {
final MessageData messageData = message.getData();
switch (messageData.getCode()) {
case IbftV2.PRE_PREPARE:
return IbftPrePrepareMessage.fromMessage(messageData).decode();
case IbftV2.PREPARE:
return IbftPrepareMessage.fromMessage(messageData).decode();
case IbftV2.ROUND_CHANGE:
return IbftRoundChangeMessage.fromMessage(messageData).decode();
default:
throw new IllegalArgumentException(
"Received message does not conform to any recognised IBFT message structure.");
}
}
}

@ -0,0 +1,40 @@
/*
* 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.ethereum.p2p.NetworkMemoryPool;
import tech.pegasys.pantheon.ethereum.p2p.wire.AbstractMessageData;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
import io.netty.buffer.ByteBuf;
public abstract class AbstractIbftMessage extends AbstractMessageData {
protected AbstractIbftMessage(final ByteBuf data) {
super(data);
}
public abstract IbftSignedMessageData<?> decode();
protected static ByteBuf writeMessageToByteBuf(
final IbftSignedMessageData<?> ibftSignedMessageData) {
BytesValueRLPOutput rlpEncode = new BytesValueRLPOutput();
ibftSignedMessageData.writeTo(rlpEncode);
final ByteBuf data = NetworkMemoryPool.allocate(rlpEncode.encodedSize());
data.writeBytes(rlpEncode.encoded().extractArray());
return data;
}
}

@ -0,0 +1,64 @@
/*
* 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.NetworkMemoryPool;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import io.netty.buffer.ByteBuf;
public class IbftPrePrepareMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.PRE_PREPARE;
private IbftPrePrepareMessage(final ByteBuf data) {
super(data);
}
public static IbftPrePrepareMessage fromMessage(final MessageData message) {
if (message instanceof IbftPrePrepareMessage) {
message.retain();
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));
}
final ByteBuf data = NetworkMemoryPool.allocate(message.getSize());
message.writeTo(data);
return new IbftPrePrepareMessage(data);
}
@Override
public IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> decode() {
return IbftSignedMessageData.readIbftSignedPrePrepareMessageDataFrom(
RLP.input(BytesValue.wrapBuffer(data)));
}
public static IbftPrePrepareMessage create(
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> ibftPrepareMessageDecoded) {
return new IbftPrePrepareMessage(writeMessageToByteBuf(ibftPrepareMessageDecoded));
}
@Override
public int getCode() {
return MESSAGE_CODE;
}
}

@ -0,0 +1,64 @@
/*
* 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.IbftUnsignedPrepareMessageData;
import tech.pegasys.pantheon.ethereum.p2p.NetworkMemoryPool;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import io.netty.buffer.ByteBuf;
public class IbftPrepareMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.PREPARE;
private IbftPrepareMessage(final ByteBuf data) {
super(data);
}
public static IbftPrepareMessage fromMessage(final MessageData message) {
if (message instanceof IbftPrepareMessage) {
message.retain();
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));
}
final ByteBuf data = NetworkMemoryPool.allocate(message.getSize());
message.writeTo(data);
return new IbftPrepareMessage(data);
}
@Override
public IbftSignedMessageData<IbftUnsignedPrepareMessageData> decode() {
return IbftSignedMessageData.readIbftSignedPrepareMessageDataFrom(
RLP.input(BytesValue.wrapBuffer(data)));
}
public static IbftPrepareMessage create(
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> ibftPrepareMessageDecoded) {
return new IbftPrepareMessage(writeMessageToByteBuf(ibftPrepareMessageDecoded));
}
@Override
public int getCode() {
return MESSAGE_CODE;
}
}

@ -0,0 +1,64 @@
/*
* 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.IbftUnsignedRoundChangeMessageData;
import tech.pegasys.pantheon.ethereum.p2p.NetworkMemoryPool;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import io.netty.buffer.ByteBuf;
public class IbftRoundChangeMessage extends AbstractIbftMessage {
private static final int MESSAGE_CODE = IbftV2.ROUND_CHANGE;
private IbftRoundChangeMessage(final ByteBuf data) {
super(data);
}
public static IbftRoundChangeMessage fromMessage(final MessageData message) {
if (message instanceof IbftRoundChangeMessage) {
message.retain();
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));
}
final ByteBuf data = NetworkMemoryPool.allocate(message.getSize());
message.writeTo(data);
return new IbftRoundChangeMessage(data);
}
@Override
public IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> decode() {
return IbftSignedMessageData.readIbftSignedRoundChangeMessageDataFrom(
RLP.input(BytesValue.wrapBuffer(data)));
}
public static IbftRoundChangeMessage create(
final IbftSignedMessageData<IbftUnsignedRoundChangeMessageData> ibftPrepareMessageDecoded) {
return new IbftRoundChangeMessage(writeMessageToByteBuf(ibftPrepareMessageDecoded));
}
@Override
public int getCode() {
return MESSAGE_CODE;
}
}

@ -0,0 +1,23 @@
/*
* 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;
/** Message codes for iBFT v2 messages */
public class IbftV2 {
public static final int PRE_PREPARE = 0;
public static final int PREPARE = 1;
public static final int COMMIT = 2;
public static final int ROUND_CHANGE = 3;
public static final int MESSAGE_SPACE = 4;
}

@ -0,0 +1,28 @@
/*
* 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;
public abstract class AbstractIbftUnsignedInRoundMessageData
extends AbstractIbftUnsignedMessageData {
protected final ConsensusRoundIdentifier roundIdentifier;
protected AbstractIbftUnsignedInRoundMessageData(final ConsensusRoundIdentifier roundIdentifier) {
this.roundIdentifier = roundIdentifier;
}
public ConsensusRoundIdentifier getRoundIdentifier() {
return roundIdentifier;
}
}

@ -0,0 +1,37 @@
/*
* 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.core.Hash;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
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 void writeTo(final RLPOutput rlpOutput);
public BytesValue encoded() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
writeTo(rlpOutput);
return rlpOutput.encoded();
}
public abstract int getMessageType();
protected static Hash readDigest(final RLPInput ibftMessageData) {
return Hash.wrap(ibftMessageData.readBytes32());
}
}

@ -0,0 +1,72 @@
/*
* 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.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<IbftUnsignedPrepareMessageData> createIbftSignedPrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
IbftUnsignedPrepareMessageData prepareUnsignedMessageData =
new IbftUnsignedPrepareMessageData(roundIdentifier, digest);
return createSignedMessage(prepareUnsignedMessageData);
}
public IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>
createIbftSignedRoundChangeMessageData(
final ConsensusRoundIdentifier roundIdentifier,
final Optional<IbftPreparedCertificate> preparedCertificate) {
IbftUnsignedRoundChangeMessageData prepareUnsignedMessageData =
new IbftUnsignedRoundChangeMessageData(roundIdentifier, preparedCertificate);
return createSignedMessage(prepareUnsignedMessageData);
}
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);
}
}

@ -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 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();
}
}

@ -0,0 +1,108 @@
/*
* 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.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public class IbftSignedMessageData<M extends AbstractIbftUnsignedMessageData> {
protected final Address sender;
protected final Signature signature;
protected final M ibftUnsignedMessageData;
public IbftSignedMessageData(
final M ibftUnsignedMessageData, final Address sender, final Signature signature) {
this.ibftUnsignedMessageData = ibftUnsignedMessageData;
this.sender = sender;
this.signature = signature;
}
public Address getSender() {
return sender;
}
public Signature getSignature() {
return signature;
}
public M getUnsignedMessageData() {
return ibftUnsignedMessageData;
}
public void writeTo(final RLPOutput output) {
output.startList();
ibftUnsignedMessageData.writeTo(output);
output.writeBytesValue(getSignature().encodedBytes());
output.endList();
}
public static IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>
readIbftSignedPrePrepareMessageDataFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedPrePrepareMessageData unsignedMessageData =
IbftUnsignedPrePrepareMessageData.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedPrepareMessageData>
readIbftSignedPrepareMessageDataFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedPrepareMessageData unsignedMessageData =
IbftUnsignedPrepareMessageData.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
public static IbftSignedMessageData<IbftUnsignedRoundChangeMessageData>
readIbftSignedRoundChangeMessageDataFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final IbftUnsignedRoundChangeMessageData unsignedMessageData =
IbftUnsignedRoundChangeMessageData.readFrom(rlpInput);
final Signature signature = readSignature(rlpInput);
rlpInput.leaveList();
return from(unsignedMessageData, signature);
}
protected static <M extends AbstractIbftUnsignedMessageData> IbftSignedMessageData<M> from(
final M unsignedMessageData, final Signature signature) {
final Address sender = recoverSender(unsignedMessageData, signature);
return new IbftSignedMessageData<>(unsignedMessageData, sender, signature);
}
protected static Signature readSignature(final RLPInput signedMessage) {
return signedMessage.readBytesValue(Signature::decode);
}
protected static Address recoverSender(
final AbstractIbftUnsignedMessageData unsignedMessageData, final Signature signature) {
return Util.signatureToAddress(
signature, IbftMessageFactory.hashForSignature(unsignedMessageData));
}
}

@ -0,0 +1,44 @@
/*
* 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.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 IbftUnsignedPrePrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Block block) {
super(roundIdentifier);
}
public Block getBlock() {
return null;
}
@Override
public void writeTo(final RLPOutput rlpOutput) {}
@Override
public int getMessageType() {
return 0;
}
public static IbftUnsignedPrePrepareMessageData readFrom(final RLPInput rlpInput) {
return null;
}
}

@ -0,0 +1,59 @@
/*
* 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.core.Hash;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public class IbftUnsignedPrepareMessageData extends AbstractIbftUnsignedInRoundMessageData {
private static final int TYPE = IbftV2.PREPARE;
private final Hash digest;
/** Constructor used when a validator wants to send a message */
public IbftUnsignedPrepareMessageData(
final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
super(roundIdentifier);
this.digest = digest;
}
public static IbftUnsignedPrepareMessageData readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
final Hash digest = readDigest(rlpInput);
rlpInput.leaveList();
return new IbftUnsignedPrepareMessageData(roundIdentifier, digest);
}
@Override
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
roundIdentifier.writeTo(rlpOutput);
rlpOutput.writeBytesValue(digest);
rlpOutput.endList();
}
@Override
public int getMessageType() {
return TYPE;
}
public Hash getDigest() {
return digest;
}
}

@ -0,0 +1,84 @@
/*
* 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.BytesValueRLPOutput;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import java.util.Optional;
public class IbftUnsignedRoundChangeMessageData extends AbstractIbftUnsignedMessageData {
private static final int TYPE = IbftV2.PREPARE;
private final ConsensusRoundIdentifier roundChangeIdentifier;
// The validator may not hae any prepared certificate
private final Optional<IbftPreparedCertificate> preparedCertificate;
/** Constructor used only by the {@link #readFrom(RLPInput)} method */
public IbftUnsignedRoundChangeMessageData(
final ConsensusRoundIdentifier roundIdentifier,
final Optional<IbftPreparedCertificate> preparedCertificate) {
this.roundChangeIdentifier = roundIdentifier;
this.preparedCertificate = preparedCertificate;
}
public ConsensusRoundIdentifier getRoundChangeIdentifier() {
return roundChangeIdentifier;
}
public Optional<IbftPreparedCertificate> getPreparedCertificate() {
return preparedCertificate;
}
@Override
public void writeTo(final RLPOutput rlpOutput) {
// RLP encode of the message data content (round identifier and prepared certificate)
BytesValueRLPOutput ibftMessage = new BytesValueRLPOutput();
ibftMessage.startList();
roundChangeIdentifier.writeTo(ibftMessage);
if (preparedCertificate.isPresent()) {
preparedCertificate.get().writeTo(ibftMessage);
} else {
ibftMessage.writeNull();
}
ibftMessage.endList();
}
public static IbftUnsignedRoundChangeMessageData readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput);
final Optional<IbftPreparedCertificate> preparedCertificate;
if (rlpInput.nextIsNull()) {
rlpInput.skipNext();
preparedCertificate = Optional.empty();
} else {
preparedCertificate = Optional.of(IbftPreparedCertificate.readFrom(rlpInput));
}
rlpInput.leaveList();
return new IbftUnsignedRoundChangeMessageData(roundIdentifier, preparedCertificate);
}
@Override
public int getMessageType() {
return TYPE;
}
}

@ -12,16 +12,10 @@
*/
package tech.pegasys.pantheon.consensus.ibft.protocol;
import tech.pegasys.pantheon.consensus.ibft.ibftmessage.IbftV2;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class IbftSubProtocol implements SubProtocol {
public static String NAME = "IBF";
@ -40,41 +34,20 @@ public class IbftSubProtocol implements SubProtocol {
@Override
public int messageSpace(final int protocolVersion) {
return NotificationType.getMax() + 1;
return IbftV2.MESSAGE_SPACE;
}
@Override
public boolean isValidMessageCode(final int protocolVersion, final int code) {
return NotificationType.fromValue(code).isPresent();
}
public enum NotificationType {
PREPREPARE(0),
PREPARE(1),
COMMIT(2),
ROUND_CHANGE(3);
private final int value;
NotificationType(final int value) {
this.value = value;
}
public final int getValue() {
return value;
}
public static final int getMax() {
return Collections.max(
Arrays.asList(NotificationType.values()),
Comparator.comparing(NotificationType::getValue))
.getValue();
}
public static final Optional<NotificationType> fromValue(final int i) {
final List<NotificationType> notifications = Arrays.asList(NotificationType.values());
return Stream.of(NotificationType.values()).filter(n -> n.getValue() == i).findFirst();
switch (code) {
case IbftV2.PRE_PREPARE:
case IbftV2.PREPARE:
case IbftV2.COMMIT:
case IbftV2.ROUND_CHANGE:
return true;
default:
return false;
}
}
}

Loading…
Cancel
Save