mirror of https://github.com/hyperledger/besu
[EC-183] Add iBFT Prepare and Round Change RLP encoding and decoding (#84)
parent
1849460e46
commit
e2468dba07
@ -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