use of com.radixdlt.consensus.bft.BFTValidatorSet in project radixdlt by radixdlt.
the class PendingVotesTest method when_voting_again__previous_timeoutvote_is_removed.
@Test
public void when_voting_again__previous_timeoutvote_is_removed() {
BFTNode author = mock(BFTNode.class);
Vote vote = makeSignedVoteFor(author, View.genesis(), HashUtils.random256());
when(vote.getTimeoutSignature()).thenReturn(Optional.of(mock(ECDSASignature.class)));
when(vote.isTimeout()).thenReturn(true);
BFTValidatorSet validatorSet = mock(BFTValidatorSet.class);
ValidationState validationState = mock(ValidationState.class);
TimestampedECDSASignatures signatures = mock(TimestampedECDSASignatures.class);
when(validationState.signatures()).thenReturn(signatures);
when(validationState.isEmpty()).thenReturn(true);
when(validatorSet.newValidationState()).thenReturn(validationState);
when(validatorSet.containsNode(any())).thenReturn(true);
VoteData voteData = mock(VoteData.class);
BFTHeader proposed = vote.getVoteData().getProposed();
when(voteData.getProposed()).thenReturn(proposed);
// Preconditions
assertEquals(VoteProcessingResult.accepted(), this.pendingVotes.insertVote(vote, validatorSet));
assertEquals(1, this.pendingVotes.voteStateSize());
assertEquals(1, this.pendingVotes.timeoutVoteStateSize());
assertEquals(1, this.pendingVotes.previousVotesSize());
Vote vote2 = makeSignedVoteFor(author, View.of(1), HashUtils.random256());
// Need a different hash for this (different) vote
assertEquals(VoteProcessingResult.accepted(), this.pendingVotes.insertVote(vote2, validatorSet));
assertEquals(1, this.pendingVotes.voteStateSize());
assertEquals(0, this.pendingVotes.timeoutVoteStateSize());
assertEquals(1, this.pendingVotes.previousVotesSize());
}
use of com.radixdlt.consensus.bft.BFTValidatorSet in project radixdlt by radixdlt.
the class PendingVotesTest method when_inserting_valid_timeout_votes__then_tc_is_formed.
@Test
public void when_inserting_valid_timeout_votes__then_tc_is_formed() {
HashCode vertexId1 = HashUtils.random256();
HashCode vertexId2 = HashUtils.random256();
Vote vote1 = makeSignedVoteFor(mock(BFTNode.class), View.genesis(), vertexId1);
when(vote1.getTimeoutSignature()).thenReturn(Optional.of(mock(ECDSASignature.class)));
when(vote1.isTimeout()).thenReturn(true);
Vote vote2 = makeSignedVoteFor(mock(BFTNode.class), View.genesis(), vertexId2);
when(vote2.getTimeoutSignature()).thenReturn(Optional.of(mock(ECDSASignature.class)));
when(vote2.isTimeout()).thenReturn(true);
BFTValidatorSet validatorSet = BFTValidatorSet.from(Arrays.asList(BFTValidator.from(vote1.getAuthor(), UInt256.ONE), BFTValidator.from(vote2.getAuthor(), UInt256.ONE)));
assertTrue(this.pendingVotes.insertVote(vote1, validatorSet) instanceof VoteProcessingResult.VoteAccepted);
VoteProcessingResult result2 = this.pendingVotes.insertVote(vote2, validatorSet);
assertTrue(result2 instanceof VoteProcessingResult.QuorumReached);
assertTrue(((VoteProcessingResult.QuorumReached) result2).getViewVotingResult() instanceof ViewVotingResult.FormedTC);
}
use of com.radixdlt.consensus.bft.BFTValidatorSet in project radixdlt by radixdlt.
the class PendingVotesTest method when_inserting_valid_but_unaccepted_votes__then_no_qc_is_returned.
@Test
public void when_inserting_valid_but_unaccepted_votes__then_no_qc_is_returned() {
HashCode vertexId = HashUtils.random256();
Vote vote1 = makeSignedVoteFor(mock(BFTNode.class), View.genesis(), vertexId);
Vote vote2 = makeSignedVoteFor(mock(BFTNode.class), View.genesis(), vertexId);
BFTValidatorSet validatorSet = BFTValidatorSet.from(Collections.singleton(BFTValidator.from(vote1.getAuthor(), UInt256.ONE)));
VoteData voteData = mock(VoteData.class);
BFTHeader proposed = vote1.getVoteData().getProposed();
when(voteData.getProposed()).thenReturn(proposed);
assertEquals(VoteProcessingResult.rejected(VoteRejectedReason.INVALID_AUTHOR), this.pendingVotes.insertVote(vote2, validatorSet));
}
use of com.radixdlt.consensus.bft.BFTValidatorSet in project radixdlt by radixdlt.
the class EpochManagerTest method should_not_send_consensus_messages_if_not_part_of_new_epoch.
@Test
public void should_not_send_consensus_messages_if_not_part_of_new_epoch() {
// Arrange
epochManager.start();
BFTValidatorSet nextValidatorSet = BFTValidatorSet.from(Stream.of(BFTValidator.from(BFTNode.random(), UInt256.ONE)));
var accumulatorState = new AccumulatorState(0, HashUtils.zero256());
LedgerHeader header = LedgerHeader.genesis(accumulatorState, nextValidatorSet, 0);
UnverifiedVertex genesisVertex = UnverifiedVertex.createGenesis(header);
VerifiedVertex verifiedGenesisVertex = new VerifiedVertex(genesisVertex, hasher.hash(genesisVertex));
LedgerHeader nextLedgerHeader = LedgerHeader.create(header.getEpoch() + 1, View.genesis(), header.getAccumulatorState(), header.timestamp());
var genesisQC = QuorumCertificate.ofGenesis(verifiedGenesisVertex, nextLedgerHeader);
var proposerElection = new WeightedRotatingLeaders(nextValidatorSet);
var bftConfiguration = new BFTConfiguration(proposerElection, nextValidatorSet, VerifiedVertexStoreState.create(HighQC.from(genesisQC), verifiedGenesisVertex, Optional.empty(), hasher));
LedgerProof proof = mock(LedgerProof.class);
when(proof.getEpoch()).thenReturn(header.getEpoch() + 1);
var epochChange = new EpochChange(proof, bftConfiguration);
var ledgerUpdate = new LedgerUpdate(mock(VerifiedTxnsAndProof.class), ImmutableClassToInstanceMap.of(EpochChange.class, epochChange));
// Act
epochManager.epochsLedgerUpdateEventProcessor().process(ledgerUpdate);
// Assert
verify(proposalDispatcher, never()).dispatch(any(Iterable.class), argThat(p -> p.getEpoch() == epochChange.getEpoch()));
verify(voteDispatcher, never()).dispatch(any(BFTNode.class), any());
}
use of com.radixdlt.consensus.bft.BFTValidatorSet in project radixdlt by radixdlt.
the class PacemakerViewUpdateRaceConditionTest method test_pacemaker_view_update_race_condition.
@Test
public void test_pacemaker_view_update_race_condition() {
final DeterministicTest test = DeterministicTest.builder().numNodes(numNodes).messageSelector(MessageSelector.randomSelector(random)).messageMutator(messUpMessagesForNodeUnderTest()).pacemakerTimeout(pacemakerTimeout).overrideWithIncorrectModule(new AbstractModule() {
@ProvidesIntoSet
@ProcessOnDispatch
private EventProcessor<BFTInsertUpdate> bftInsertUpdateProcessor() {
final Map<HashCode, PreparedVertex> insertedVertices = new HashMap<>();
return bftInsertUpdate -> {
final PreparedVertex inserted = bftInsertUpdate.getInserted();
insertedVertices.putIfAbsent(inserted.getId(), inserted);
final Optional<PreparedVertex> maybeParent = Optional.ofNullable(insertedVertices.get(inserted.getParentId()));
maybeParent.ifPresent(parent -> {
if (parent.getView().equals(inserted.getView())) {
throw new IllegalStateException("Vertex can't have the same view as its parent.");
}
});
};
}
@Provides
public ProposerElection proposerElection(BFTValidatorSet validatorSet) {
final var sortedValidators = validatorSet.getValidators().stream().map(BFTValidator::getNode).sorted(Comparator.comparing(BFTNode::getKey, KeyComparator.instance().reversed())).toList();
return view -> sortedValidators.get(((int) view.number() - 1) % sortedValidators.size());
}
}).buildWithoutEpochs().runUntil(nodeUnderTestReachesView(View.of(3)));
final var counters = test.getSystemCounters(nodeUnderTestIndex);
assertThat(counters.get(SystemCounters.CounterType.BFT_VOTE_QUORUMS)).isEqualTo(// ensure that quorum was formed
2);
assertThat(counters.get(SystemCounters.CounterType.BFT_PACEMAKER_TIMEOUTS_SENT)).isEqualTo(// ensure that timeouts were processed
2);
}
Aggregations