mirror of https://github.com/hyperledger/besu
[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
parent
2cba87a899
commit
0dff893203
@ -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; |
||||
} |
||||
} |
Loading…
Reference in new issue