mirror of https://github.com/hyperledger/besu
Create Qbft Prepare and Commit messages (#1691)
This adds the Prepare and Commit messages used in the QBFT protocol, this is an incremental movement toward QBFT - and does not offer new functionality. Signed-off-by: Trent Mohay <trent.mohay@consensys.net>pull/1747/head
parent
2544dfd3e8
commit
6dd89a534a
@ -0,0 +1,71 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
|
||||
apply plugin: 'java-library' |
||||
|
||||
jar { |
||||
archiveBaseName = 'besu-qbft' |
||||
manifest { |
||||
attributes( |
||||
'Specification-Title': archiveBaseName, |
||||
'Specification-Version': project.version, |
||||
'Implementation-Title': archiveBaseName, |
||||
'Implementation-Version': calculateVersion() |
||||
) |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation project(':config') |
||||
implementation project(':consensus:common') |
||||
implementation project(':crypto') |
||||
implementation project(':ethereum:api') |
||||
implementation project(':ethereum:blockcreation') |
||||
implementation project(':ethereum:core') |
||||
implementation project(':ethereum:eth') |
||||
implementation project(':ethereum:p2p') |
||||
implementation project(':ethereum:rlp') |
||||
implementation project(':services:kvstore') |
||||
|
||||
implementation 'com.google.guava:guava' |
||||
implementation 'io.vertx:vertx-core' |
||||
implementation 'org.apache.tuweni:bytes' |
||||
implementation 'org.apache.tuweni:units' |
||||
|
||||
integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') |
||||
integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') |
||||
|
||||
testImplementation 'junit:junit' |
||||
testImplementation 'org.awaitility:awaitility' |
||||
testImplementation 'org.assertj:assertj-core' |
||||
testImplementation 'org.mockito:mockito-core' |
||||
testImplementation project(path: ':crypto', configuration: 'testSupportArtifacts') |
||||
testImplementation project(path: ':config', configuration: 'testSupportArtifacts') |
||||
testImplementation project(path: ':consensus:common', configuration: 'testArtifacts') |
||||
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') |
||||
testImplementation project(':metrics:core') |
||||
testImplementation project(':testutil') |
||||
testImplementation project(':crypto') |
||||
|
||||
integrationTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts') |
||||
integrationTestImplementation project(':metrics:core') |
||||
integrationTestImplementation project(':testutil') |
||||
|
||||
integrationTestImplementation 'junit:junit' |
||||
integrationTestImplementation 'org.assertj:assertj-core' |
||||
integrationTestImplementation 'org.mockito:mockito-core' |
||||
|
||||
testSupportImplementation 'org.mockito:mockito-core' |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagedata; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.messagedata.AbstractBftMessageData; |
||||
import org.hyperledger.besu.consensus.qbft.messagewrappers.Commit; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class CommitMessageData extends AbstractBftMessageData { |
||||
|
||||
private static final int MESSAGE_CODE = QbftV1.COMMIT; |
||||
|
||||
private CommitMessageData(final Bytes data) { |
||||
super(data); |
||||
} |
||||
|
||||
public static CommitMessageData fromMessageData(final MessageData messageData) { |
||||
return fromMessageData( |
||||
messageData, MESSAGE_CODE, CommitMessageData.class, CommitMessageData::new); |
||||
} |
||||
|
||||
public Commit decode() { |
||||
return Commit.decode(data); |
||||
} |
||||
|
||||
public static CommitMessageData create(final Commit commit) { |
||||
return new CommitMessageData(commit.encode()); |
||||
} |
||||
|
||||
@Override |
||||
public int getCode() { |
||||
return MESSAGE_CODE; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagedata; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.messagedata.AbstractBftMessageData; |
||||
import org.hyperledger.besu.consensus.qbft.messagewrappers.Prepare; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class PrepareMessageData extends AbstractBftMessageData { |
||||
|
||||
private static final int MESSAGE_CODE = QbftV1.PREPARE; |
||||
|
||||
private PrepareMessageData(final Bytes data) { |
||||
super(data); |
||||
} |
||||
|
||||
public static PrepareMessageData fromMessageData(final MessageData messageData) { |
||||
return fromMessageData( |
||||
messageData, MESSAGE_CODE, PrepareMessageData.class, PrepareMessageData::new); |
||||
} |
||||
|
||||
public Prepare decode() { |
||||
return Prepare.decode(data); |
||||
} |
||||
|
||||
public static PrepareMessageData create(final Prepare preapare) { |
||||
return new PrepareMessageData(preapare.encode()); |
||||
} |
||||
|
||||
@Override |
||||
public int getCode() { |
||||
return MESSAGE_CODE; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagedata; |
||||
|
||||
/** Message codes for QBFT v1 messages */ |
||||
public class QbftV1 { |
||||
public static final int PROPOSAL = 0; |
||||
public static final int PREPARE = 1; |
||||
public static final int COMMIT = 2; |
||||
public static final int ROUND_CHANGE = 3; |
||||
|
||||
public static final int MESSAGE_SPACE = 4; |
||||
} |
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagewrappers; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.consensus.qbft.payload.CommitPayload; |
||||
import org.hyperledger.besu.consensus.qbft.payload.PayloadDeserializers; |
||||
import org.hyperledger.besu.crypto.SECP256K1.Signature; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.rlp.RLP; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class Commit extends BftMessage<CommitPayload> { |
||||
|
||||
public Commit(final SignedData<CommitPayload> payload) { |
||||
super(payload); |
||||
} |
||||
|
||||
public Signature getCommitSeal() { |
||||
return getPayload().getCommitSeal(); |
||||
} |
||||
|
||||
public Hash getDigest() { |
||||
return getPayload().getDigest(); |
||||
} |
||||
|
||||
public static Commit decode(final Bytes data) { |
||||
return new Commit(PayloadDeserializers.readSignedCommitPayloadFrom(RLP.input(data))); |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagewrappers; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.consensus.qbft.payload.PayloadDeserializers; |
||||
import org.hyperledger.besu.consensus.qbft.payload.PreparePayload; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.rlp.RLP; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class Prepare extends BftMessage<PreparePayload> { |
||||
|
||||
public Prepare(final SignedData<PreparePayload> payload) { |
||||
super(payload); |
||||
} |
||||
|
||||
public Hash getDigest() { |
||||
return getPayload().getDigest(); |
||||
} |
||||
|
||||
public static Prepare decode(final Bytes data) { |
||||
return new Prepare(PayloadDeserializers.readSignedPreparePayloadFrom(RLP.input(data))); |
||||
} |
||||
} |
@ -0,0 +1,107 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.payload; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.Payload; |
||||
import org.hyperledger.besu.consensus.qbft.messagedata.QbftV1; |
||||
import org.hyperledger.besu.crypto.SECP256K1.Signature; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPInput; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||
|
||||
import java.util.Objects; |
||||
import java.util.StringJoiner; |
||||
|
||||
public class CommitPayload implements Payload { |
||||
private static final int TYPE = QbftV1.COMMIT; |
||||
private final ConsensusRoundIdentifier roundIdentifier; |
||||
private final Hash digest; |
||||
private final Signature commitSeal; |
||||
|
||||
public CommitPayload( |
||||
final ConsensusRoundIdentifier roundIdentifier, |
||||
final Hash digest, |
||||
final Signature commitSeal) { |
||||
this.roundIdentifier = roundIdentifier; |
||||
this.digest = digest; |
||||
this.commitSeal = commitSeal; |
||||
} |
||||
|
||||
public static CommitPayload readFrom(final RLPInput rlpInput) { |
||||
rlpInput.enterList(); |
||||
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput); |
||||
final Hash digest = Payload.readDigest(rlpInput); |
||||
final Signature commitSeal = rlpInput.readBytes(Signature::decode); |
||||
rlpInput.leaveList(); |
||||
|
||||
return new CommitPayload(roundIdentifier, digest, commitSeal); |
||||
} |
||||
|
||||
@Override |
||||
public void writeTo(final RLPOutput rlpOutput) { |
||||
rlpOutput.startList(); |
||||
roundIdentifier.writeTo(rlpOutput); |
||||
rlpOutput.writeBytes(digest); |
||||
rlpOutput.writeBytes(commitSeal.encodedBytes()); |
||||
rlpOutput.endList(); |
||||
} |
||||
|
||||
@Override |
||||
public int getMessageType() { |
||||
return TYPE; |
||||
} |
||||
|
||||
public Hash getDigest() { |
||||
return digest; |
||||
} |
||||
|
||||
public Signature getCommitSeal() { |
||||
return commitSeal; |
||||
} |
||||
|
||||
@Override |
||||
public ConsensusRoundIdentifier getRoundIdentifier() { |
||||
return roundIdentifier; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object o) { |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o == null || getClass() != o.getClass()) { |
||||
return false; |
||||
} |
||||
final CommitPayload that = (CommitPayload) o; |
||||
return Objects.equals(roundIdentifier, that.roundIdentifier) |
||||
&& Objects.equals(digest, that.digest) |
||||
&& Objects.equals(commitSeal, that.commitSeal); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(roundIdentifier, digest, commitSeal); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return new StringJoiner(", ", CommitPayload.class.getSimpleName() + "[", "]") |
||||
.add("roundIdentifier=" + roundIdentifier) |
||||
.add("digest=" + digest) |
||||
.add("commitSeal=" + commitSeal) |
||||
.toString(); |
||||
} |
||||
} |
@ -0,0 +1,60 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.payload; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.Payload; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.consensus.qbft.messagewrappers.Commit; |
||||
import org.hyperledger.besu.consensus.qbft.messagewrappers.Prepare; |
||||
import org.hyperledger.besu.crypto.NodeKey; |
||||
import org.hyperledger.besu.crypto.SECP256K1.Signature; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.core.Util; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class MessageFactory { |
||||
|
||||
private final NodeKey nodeKey; |
||||
|
||||
public MessageFactory(final NodeKey nodeKey) { |
||||
this.nodeKey = nodeKey; |
||||
} |
||||
|
||||
public Prepare createPrepare(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) { |
||||
final PreparePayload payload = new PreparePayload(roundIdentifier, digest); |
||||
return new Prepare(createSignedMessage(payload)); |
||||
} |
||||
|
||||
public Commit createCommit( |
||||
final ConsensusRoundIdentifier roundIdentifier, |
||||
final Hash digest, |
||||
final Signature commitSeal) { |
||||
final CommitPayload payload = new CommitPayload(roundIdentifier, digest, commitSeal); |
||||
return new Commit(createSignedMessage(payload)); |
||||
} |
||||
|
||||
private <M extends Payload> SignedData<M> createSignedMessage(final M payload) { |
||||
final Signature signature = nodeKey.sign(hashForSignature(payload)); |
||||
return new SignedData<>(payload, Util.publicKeyToAddress(nodeKey.getPublicKey()), signature); |
||||
} |
||||
|
||||
public static Hash hashForSignature(final Payload unsignedMessageData) { |
||||
return Hash.hash( |
||||
Bytes.concatenate( |
||||
Bytes.of(unsignedMessageData.getMessageType()), unsignedMessageData.encoded())); |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
/* |
||||
* Copyright 2020 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.payload; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.payload.Payload; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.crypto.SECP256K1.Signature; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Util; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPInput; |
||||
|
||||
public class PayloadDeserializers { |
||||
|
||||
public static SignedData<PreparePayload> readSignedPreparePayloadFrom(final RLPInput rlpInput) { |
||||
rlpInput.enterList(); |
||||
final PreparePayload unsignedMessageData = PreparePayload.readFrom(rlpInput); |
||||
final Signature signature = readSignature(rlpInput); |
||||
rlpInput.leaveList(); |
||||
return from(unsignedMessageData, signature); |
||||
} |
||||
|
||||
public static SignedData<CommitPayload> readSignedCommitPayloadFrom(final RLPInput rlpInput) { |
||||
rlpInput.enterList(); |
||||
final CommitPayload unsignedMessageData = CommitPayload.readFrom(rlpInput); |
||||
final Signature signature = readSignature(rlpInput); |
||||
rlpInput.leaveList(); |
||||
return from(unsignedMessageData, signature); |
||||
} |
||||
|
||||
protected static <M extends Payload> SignedData<M> from( |
||||
final M unsignedMessageData, final Signature signature) { |
||||
final Address sender = recoverSender(unsignedMessageData, signature); |
||||
return new SignedData<>(unsignedMessageData, sender, signature); |
||||
} |
||||
|
||||
protected static Signature readSignature(final RLPInput signedMessage) { |
||||
return signedMessage.readBytes(Signature::decode); |
||||
} |
||||
|
||||
protected static Address recoverSender( |
||||
final Payload unsignedMessageData, final Signature signature) { |
||||
return Util.signatureToAddress(signature, MessageFactory.hashForSignature(unsignedMessageData)); |
||||
} |
||||
} |
@ -0,0 +1,92 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.payload; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.Payload; |
||||
import org.hyperledger.besu.consensus.qbft.messagedata.QbftV1; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPInput; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||
|
||||
import java.util.Objects; |
||||
import java.util.StringJoiner; |
||||
|
||||
public class PreparePayload implements Payload { |
||||
private static final int TYPE = QbftV1.PREPARE; |
||||
private final ConsensusRoundIdentifier roundIdentifier; |
||||
private final Hash digest; |
||||
|
||||
public PreparePayload(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) { |
||||
this.roundIdentifier = roundIdentifier; |
||||
this.digest = digest; |
||||
} |
||||
|
||||
public static PreparePayload readFrom(final RLPInput rlpInput) { |
||||
rlpInput.enterList(); |
||||
final ConsensusRoundIdentifier roundIdentifier = ConsensusRoundIdentifier.readFrom(rlpInput); |
||||
final Hash digest = Payload.readDigest(rlpInput); |
||||
rlpInput.leaveList(); |
||||
return new PreparePayload(roundIdentifier, digest); |
||||
} |
||||
|
||||
@Override |
||||
public void writeTo(final RLPOutput rlpOutput) { |
||||
rlpOutput.startList(); |
||||
roundIdentifier.writeTo(rlpOutput); |
||||
rlpOutput.writeBytes(digest); |
||||
rlpOutput.endList(); |
||||
} |
||||
|
||||
@Override |
||||
public int getMessageType() { |
||||
return TYPE; |
||||
} |
||||
|
||||
public Hash getDigest() { |
||||
return digest; |
||||
} |
||||
|
||||
@Override |
||||
public ConsensusRoundIdentifier getRoundIdentifier() { |
||||
return roundIdentifier; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object o) { |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o == null || getClass() != o.getClass()) { |
||||
return false; |
||||
} |
||||
final PreparePayload that = (PreparePayload) o; |
||||
return Objects.equals(roundIdentifier, that.roundIdentifier) |
||||
&& Objects.equals(digest, that.digest); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(roundIdentifier, digest); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return new StringJoiner(", ", PreparePayload.class.getSimpleName() + "[", "]") |
||||
.add("roundIdentifier=" + roundIdentifier) |
||||
.add("digest=" + digest) |
||||
.toString(); |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
/* |
||||
* Copyright 2020 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagewrappers; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.consensus.qbft.messagedata.QbftV1; |
||||
import org.hyperledger.besu.consensus.qbft.payload.CommitPayload; |
||||
import org.hyperledger.besu.consensus.qbft.payload.MessageFactory; |
||||
import org.hyperledger.besu.crypto.NodeKey; |
||||
import org.hyperledger.besu.crypto.NodeKeyUtils; |
||||
import org.hyperledger.besu.crypto.SECP256K1.Signature; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.core.Util; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class CommitTest { |
||||
|
||||
@Test |
||||
public void canRoundTripAPrepareMessage() { |
||||
final NodeKey nodeKey = NodeKeyUtils.generate(); |
||||
final Address addr = Util.publicKeyToAddress(nodeKey.getPublicKey()); |
||||
|
||||
final CommitPayload commitPayload = |
||||
new CommitPayload( |
||||
new ConsensusRoundIdentifier(1, 1), |
||||
Hash.ZERO, |
||||
Signature.create(BigInteger.ONE, BigInteger.ONE, (byte) 0)); |
||||
|
||||
final SignedData<CommitPayload> signedCommitPayload = |
||||
new SignedData<>( |
||||
commitPayload, addr, nodeKey.sign(MessageFactory.hashForSignature(commitPayload))); |
||||
|
||||
final Commit commitMsg = new Commit(signedCommitPayload); |
||||
|
||||
final Commit decodedPrepare = Commit.decode(commitMsg.encode()); |
||||
|
||||
assertThat(decodedPrepare.getMessageType()).isEqualTo(QbftV1.COMMIT); |
||||
assertThat(decodedPrepare.getAuthor()).isEqualTo(addr); |
||||
assertThat(decodedPrepare.getSignedPayload()) |
||||
.isEqualToComparingFieldByField(signedCommitPayload); |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
/* |
||||
* Copyright 2020 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.consensus.qbft.messagewrappers; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; |
||||
import org.hyperledger.besu.consensus.common.bft.payload.SignedData; |
||||
import org.hyperledger.besu.consensus.qbft.messagedata.QbftV1; |
||||
import org.hyperledger.besu.consensus.qbft.payload.MessageFactory; |
||||
import org.hyperledger.besu.consensus.qbft.payload.PreparePayload; |
||||
import org.hyperledger.besu.crypto.NodeKey; |
||||
import org.hyperledger.besu.crypto.NodeKeyUtils; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.core.Util; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class PrepareTest { |
||||
|
||||
@Test |
||||
public void canRoundTripAPrepareMessage() { |
||||
final NodeKey nodeKey = NodeKeyUtils.generate(); |
||||
final Address addr = Util.publicKeyToAddress(nodeKey.getPublicKey()); |
||||
|
||||
final PreparePayload preparePayload = |
||||
new PreparePayload(new ConsensusRoundIdentifier(1, 1), Hash.ZERO); |
||||
|
||||
final SignedData<PreparePayload> signedPreparePayload = |
||||
new SignedData<>( |
||||
preparePayload, addr, nodeKey.sign(MessageFactory.hashForSignature(preparePayload))); |
||||
|
||||
final Prepare prepareMsg = new Prepare(signedPreparePayload); |
||||
|
||||
final Prepare decodedPrepare = Prepare.decode(prepareMsg.encode()); |
||||
|
||||
assertThat(decodedPrepare.getMessageType()).isEqualTo(QbftV1.PREPARE); |
||||
assertThat(decodedPrepare.getAuthor()).isEqualTo(addr); |
||||
assertThat(decodedPrepare.getSignedPayload()) |
||||
.isEqualToComparingFieldByField(signedPreparePayload); |
||||
} |
||||
} |
Loading…
Reference in new issue