mirror of https://github.com/hyperledger/besu
Basic Ibft message validators (#314)
parent
14957899d6
commit
a8b52e19f5
@ -0,0 +1,204 @@ |
|||||||
|
/* |
||||||
|
* 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.validation; |
||||||
|
|
||||||
|
import static tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode.FULL; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.IbftContext; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.AbstractIbftUnsignedInRoundMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData; |
||||||
|
import tech.pegasys.pantheon.ethereum.ProtocolContext; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Address; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Block; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Util; |
||||||
|
import tech.pegasys.pantheon.ethereum.mainnet.BlockHeaderValidator; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager; |
||||||
|
import org.apache.logging.log4j.Logger; |
||||||
|
|
||||||
|
public class MessageValidator { |
||||||
|
|
||||||
|
private static final Logger LOG = LogManager.getLogger(); |
||||||
|
|
||||||
|
private final Collection<Address> validators; |
||||||
|
private final Address expectedProposer; |
||||||
|
private final ConsensusRoundIdentifier roundIdentifier; |
||||||
|
private final BlockHeaderValidator<IbftContext> headerValidator; |
||||||
|
private final ProtocolContext<IbftContext> protocolContext; |
||||||
|
private final BlockHeader parentHeader; |
||||||
|
|
||||||
|
private Optional<IbftSignedMessageData<IbftUnsignedPrePrepareMessageData>> preprepareMessage = |
||||||
|
Optional.empty(); |
||||||
|
|
||||||
|
public MessageValidator( |
||||||
|
final Collection<Address> validators, |
||||||
|
final Address expectedProposer, |
||||||
|
final ConsensusRoundIdentifier roundIdentifier, |
||||||
|
final BlockHeaderValidator<IbftContext> headerValidator, |
||||||
|
final ProtocolContext<IbftContext> protocolContext, |
||||||
|
final BlockHeader parentHeader) { |
||||||
|
this.validators = validators; |
||||||
|
this.expectedProposer = expectedProposer; |
||||||
|
this.roundIdentifier = roundIdentifier; |
||||||
|
this.headerValidator = headerValidator; |
||||||
|
this.protocolContext = protocolContext; |
||||||
|
this.parentHeader = parentHeader; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean addPreprepareMessage( |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> msg) { |
||||||
|
|
||||||
|
if (preprepareMessage.isPresent()) { |
||||||
|
return handleSubsequentPreprepareMessage(preprepareMessage.get(), msg); |
||||||
|
} |
||||||
|
|
||||||
|
if (!validatePreprepareMessage(msg)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
preprepareMessage = Optional.of(msg); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean validatePreprepareMessage( |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> msg) { |
||||||
|
|
||||||
|
if (!msg.getUnsignedMessageData().getRoundIdentifier().equals(roundIdentifier)) { |
||||||
|
LOG.info("Invalid Preprepare message, does not match current round."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (!msg.getSender().equals(expectedProposer)) { |
||||||
|
LOG.info( |
||||||
|
"Invalid Preprepare message, was not created by the proposer expected for the " |
||||||
|
+ "associated round."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
final Block proposedBlock = msg.getUnsignedMessageData().getBlock(); |
||||||
|
if (!headerValidator.validateHeader( |
||||||
|
proposedBlock.getHeader(), parentHeader, protocolContext, FULL)) { |
||||||
|
LOG.info("Invalid Prepare message, block did not pass header validation."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean handleSubsequentPreprepareMessage( |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> existingMsg, |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> newMsg) { |
||||||
|
if (!existingMsg.getSender().equals(newMsg.getSender())) { |
||||||
|
LOG.debug("Received subsequent invalid Preprepare message; sender differs from original."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
final IbftUnsignedPrePrepareMessageData existingData = existingMsg.getUnsignedMessageData(); |
||||||
|
final IbftUnsignedPrePrepareMessageData newData = newMsg.getUnsignedMessageData(); |
||||||
|
|
||||||
|
if (!preprepareMessagesAreIdentical(existingData, newData)) { |
||||||
|
LOG.debug("Received subsequent invalid Preprepare message; content differs from original."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean validatePrepareMessage( |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> msg) { |
||||||
|
final String msgType = "Prepare"; |
||||||
|
|
||||||
|
if (!isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable(msg, msgType)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (msg.getSender().equals(expectedProposer)) { |
||||||
|
LOG.info("Illegal Prepare message; was sent by the round's proposer."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return validateDigestMatchesPreprepareBlock(msg.getUnsignedMessageData().getDigest(), msgType); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean validateCommmitMessage( |
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> msg) { |
||||||
|
final String msgType = "Commit"; |
||||||
|
|
||||||
|
if (!isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable(msg, msgType)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
final Block proposedBlock = preprepareMessage.get().getUnsignedMessageData().getBlock(); |
||||||
|
final Address commitSealCreator = |
||||||
|
Util.signatureToAddress( |
||||||
|
msg.getUnsignedMessageData().getCommitSeal(), proposedBlock.getHash()); |
||||||
|
|
||||||
|
if (!commitSealCreator.equals(msg.getSender())) { |
||||||
|
LOG.info("Invalid Commit message. Seal was not created by the message transmitter."); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return validateDigestMatchesPreprepareBlock(msg.getUnsignedMessageData().getDigest(), msgType); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isMessageForCurrentRoundFromValidatorAndPreprareMessageAvailable( |
||||||
|
final IbftSignedMessageData<? extends AbstractIbftUnsignedInRoundMessageData> msg, |
||||||
|
final String msgType) { |
||||||
|
|
||||||
|
if (!msg.getUnsignedMessageData().getRoundIdentifier().equals(roundIdentifier)) { |
||||||
|
LOG.info("Invalid {} message, does not match current round.", msgType); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (!validators.contains(msg.getSender())) { |
||||||
|
LOG.info( |
||||||
|
"Invalid {} message, was not transmitted by a validator for the " + "associated round.", |
||||||
|
msgType); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (!preprepareMessage.isPresent()) { |
||||||
|
LOG.info( |
||||||
|
"Unable to validate {} message. No Preprepare message exists against " |
||||||
|
+ "which to validate block digest.", |
||||||
|
msgType); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean validateDigestMatchesPreprepareBlock(final Hash digest, final String msgType) { |
||||||
|
final Block proposedBlock = preprepareMessage.get().getUnsignedMessageData().getBlock(); |
||||||
|
if (!digest.equals(proposedBlock.getHash())) { |
||||||
|
LOG.info( |
||||||
|
"Illegal {} message, digest does not match the block in the Prepare Message.", msgType); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean preprepareMessagesAreIdentical( |
||||||
|
final IbftUnsignedPrePrepareMessageData right, final IbftUnsignedPrePrepareMessageData left) { |
||||||
|
return right.getBlock().getHash().equals(left.getBlock().getHash()) |
||||||
|
&& (right.getRoundIdentifier().compareTo(left.getRoundIdentifier()) == 0); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,274 @@ |
|||||||
|
/* |
||||||
|
* 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.validation; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.mockito.ArgumentMatchers.any; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.mockito.Mockito.when; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.IbftContext; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftMessageFactory; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftSignedMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedCommitMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrePrepareMessageData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.ibftmessagedata.IbftUnsignedPrepareMessageData; |
||||||
|
import tech.pegasys.pantheon.crypto.SECP256K1; |
||||||
|
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||||
|
import tech.pegasys.pantheon.ethereum.ProtocolContext; |
||||||
|
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Address; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Block; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Util; |
||||||
|
import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; |
||||||
|
import tech.pegasys.pantheon.ethereum.mainnet.BlockHeaderValidator; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import com.google.common.collect.Lists; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.junit.MockitoJUnitRunner; |
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class) |
||||||
|
public class MessageValidatorTest { |
||||||
|
|
||||||
|
private final KeyPair proposerKey = KeyPair.generate(); |
||||||
|
private final KeyPair validatorKey = KeyPair.generate(); |
||||||
|
private final KeyPair nonValidatorKey = KeyPair.generate(); |
||||||
|
private final IbftMessageFactory proposerMessageFactory = new IbftMessageFactory(proposerKey); |
||||||
|
private final IbftMessageFactory validatorMessageFactory = new IbftMessageFactory(validatorKey); |
||||||
|
private final IbftMessageFactory nonValidatorMessageFactory = |
||||||
|
new IbftMessageFactory(nonValidatorKey); |
||||||
|
|
||||||
|
private List<Address> validators = Lists.newArrayList(); |
||||||
|
|
||||||
|
@Mock private BlockHeaderValidator<IbftContext> headerValidator; |
||||||
|
private BlockHeader parentHeader = mock(BlockHeader.class); |
||||||
|
private final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(2, 0); |
||||||
|
private MessageValidator validator; |
||||||
|
|
||||||
|
private final Block block = mock(Block.class); |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setup() { |
||||||
|
validators.add(Util.publicKeyToAddress(proposerKey.getPublicKey())); |
||||||
|
validators.add(Util.publicKeyToAddress(validatorKey.getPublicKey())); |
||||||
|
|
||||||
|
final ProtocolContext<IbftContext> protocolContext = |
||||||
|
new ProtocolContext<>( |
||||||
|
mock(MutableBlockchain.class), mock(WorldStateArchive.class), mock(IbftContext.class)); |
||||||
|
|
||||||
|
validator = |
||||||
|
new MessageValidator( |
||||||
|
validators, |
||||||
|
Util.publicKeyToAddress(proposerKey.getPublicKey()), |
||||||
|
roundIdentifier, |
||||||
|
headerValidator, |
||||||
|
protocolContext, |
||||||
|
parentHeader); |
||||||
|
|
||||||
|
when(block.getHash()).thenReturn(Hash.fromHexStringLenient("1")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingAPrepareMessageBeforePrePrepareFails() { |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrepareMessageData(roundIdentifier, Hash.ZERO); |
||||||
|
|
||||||
|
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingACommitMessageBeforePreprepareFails() { |
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg = |
||||||
|
proposerMessageFactory.createIbftSignedCommitMessageData( |
||||||
|
roundIdentifier, Hash.ZERO, SECP256K1.sign(Hash.ZERO, proposerKey)); |
||||||
|
|
||||||
|
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingPreprepareMessageFromNonProposerFails() { |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
validatorMessageFactory.createIbftSignedPrePrepareMessageData( |
||||||
|
roundIdentifier, mock(Block.class)); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingPreprepareMessageWithIllegalBlockFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(false); |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData( |
||||||
|
roundIdentifier, mock(Block.class)); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingPrepareFromProposerFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrepareMessageData(roundIdentifier, block.getHash()); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingPrepareFromNonValidatorFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
final Block block = mock(Block.class); |
||||||
|
final BlockHeader header = mock(BlockHeader.class); |
||||||
|
when(header.getHash()).thenReturn(Hash.fromHexStringLenient("1")); // arbitrary hash value.
|
||||||
|
when(block.getHeader()).thenReturn(header); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg = |
||||||
|
nonValidatorMessageFactory.createIbftSignedPrepareMessageData( |
||||||
|
roundIdentifier, header.getHash()); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingMessagesWithDifferentRoundIdFromPreprepareFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
|
||||||
|
final ConsensusRoundIdentifier invalidRoundIdentifier = |
||||||
|
new ConsensusRoundIdentifier( |
||||||
|
roundIdentifier.getSequenceNumber(), roundIdentifier.getRoundNumber() + 1); |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg = |
||||||
|
validatorMessageFactory.createIbftSignedPrepareMessageData( |
||||||
|
invalidRoundIdentifier, block.getHash()); |
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg = |
||||||
|
validatorMessageFactory.createIbftSignedCommitMessageData( |
||||||
|
invalidRoundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), proposerKey)); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validatePrepareMessage(prepareMsg)).isFalse(); |
||||||
|
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingPrepareNonProposerValidatorWithCorrectRoundIsSuccessful() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
final Block block = mock(Block.class); |
||||||
|
final BlockHeader header = mock(BlockHeader.class); |
||||||
|
final Hash blockHash = Hash.fromHexStringLenient("1"); |
||||||
|
when(header.getHash()).thenReturn(blockHash); // arbitrary hash value.
|
||||||
|
when(block.getHeader()).thenReturn(header); |
||||||
|
when(block.getHash()).thenReturn(blockHash); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrepareMessageData> prepareMsg = |
||||||
|
validatorMessageFactory.createIbftSignedPrepareMessageData( |
||||||
|
roundIdentifier, header.getHash()); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validatePrepareMessage(prepareMsg)).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void receivingACommitMessageWithAnInvalidCommitSealFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> commitMsg = |
||||||
|
proposerMessageFactory.createIbftSignedCommitMessageData( |
||||||
|
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), nonValidatorKey)); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validateCommmitMessage(commitMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void commitMessageContainingValidSealFromValidatorIsSuccessful() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> proposerCommitMsg = |
||||||
|
proposerMessageFactory.createIbftSignedCommitMessageData( |
||||||
|
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), proposerKey)); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedCommitMessageData> validatorCommitMsg = |
||||||
|
validatorMessageFactory.createIbftSignedCommitMessageData( |
||||||
|
roundIdentifier, block.getHash(), SECP256K1.sign(block.getHash(), validatorKey)); |
||||||
|
|
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
assertThat(validator.validateCommmitMessage(proposerCommitMsg)).isTrue(); |
||||||
|
assertThat(validator.validateCommmitMessage(validatorCommitMsg)).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void subsequentPreprepareHasDifferentSenderFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg = |
||||||
|
validatorMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void subsequentPreprepareHasDifferentContentFails() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
|
||||||
|
final ConsensusRoundIdentifier newRoundIdentifier = new ConsensusRoundIdentifier(3, 0); |
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(newRoundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void subsequentPreprepareHasIdenticalSenderAndContentIsSuccessful() { |
||||||
|
when(headerValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> preprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(preprepareMsg)).isTrue(); |
||||||
|
|
||||||
|
final IbftSignedMessageData<IbftUnsignedPrePrepareMessageData> secondPreprepareMsg = |
||||||
|
proposerMessageFactory.createIbftSignedPrePrepareMessageData(roundIdentifier, block); |
||||||
|
assertThat(validator.addPreprepareMessage(secondPreprepareMsg)).isTrue(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue