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