def test_calc_batches_takes_prepared_if_preprepared_in_next_view(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest='empty') vc1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest2")], preprepared=[(0, 1, "digest1"), (2, 1, "digest2")], checkpoints=[cp]) vc2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1"), (2, 1, "digest2")], checkpoints=[cp]) vc3 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vc4 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vcs = [vc1, vc2, vc3, vc4] assert builder.calc_batches(cp, vcs) == [BatchID(1, 1, "digest2")]
def test_calc_batches_respects_checkpoint(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=cp_digest(0, 0)) vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (0, 2, "digest2")], preprepared=[(0, 1, "digest1"), (0, 2, "digest2")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches(cp, vcs) == [] cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=cp_digest(0, 0)) vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 10, "digest10"), (0, 11, "digest11"), (1, 12, "digest12")], preprepared=[(0, 10, "digest10"), (0, 11, "digest11"), (1, 12, "digest12")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches( cp, vcs) == [BatchID(0, 11, "digest11"), BatchID(1, 12, "digest12")]
def test_calc_batches_must_be_in_pre_prepare(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (0, 2, "digest2")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] # all nodes are malicious here since all added (0, 2) into prepared without adding to pre-prepared # so, None here means we can not calculate NewView reliably assert builder.calc_batches(cp, vcs) is None vc1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (0, 2, "digest2")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vc2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vcs = [vc1, vc2, vc2, vc2] assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]
def test_start_vc_by_quorum_of_vc_msgs(view_change_service_builder, internal_bus, external_bus, validators, is_master): svc_queue = [] def svc_handler(msg: StartViewChange): svc_queue.append(msg) internal_bus.subscribe(StartViewChange, svc_handler) # Quorum for ViewChange message is N-f service = view_change_service_builder(validators[0]) proposed_view_no = 10 f = getMaxFailures(len(validators)) # Append N-f-1 ViewChange msgs to view_change_votes for validator in validators[1:-f]: msg = ViewChange(proposed_view_no, 0, [], [], []) service.process_view_change_message(msg, validator) # N-f-1 msgs is not enough for triggering view_change assert not svc_queue # Process the other one message service.process_view_change_message( ViewChange(proposed_view_no, 0, [], [], []), validators[-1]) if is_master: assert svc_queue assert isinstance(svc_queue[0], StartViewChange) assert svc_queue[0].view_no == proposed_view_no else: # ViewChange message isn't processed on backups assert not svc_queue
def test_calc_batches_takes_prepared_only(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[(0, 1, "digest1"), (0, 2, "digest2"), (0, 3, "digest3"), (0, 4, "digest4")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches(cp, vcs) == [] cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (0, 2, "digest2")], preprepared=[(0, 1, "digest1"), (0, 2, "digest2"), (0, 3, "digest3"), (0, 4, "digest4")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches( cp, vcs) == [BatchID(0, 1, "digest1"), BatchID(0, 2, "digest2")]
def test_calc_batches_takes_prepared_with_same_batchid_only(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vc1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp]) vc2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp]) vc3 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest2")], preprepared=[(1, 1, "digest2")], checkpoints=[cp]) vc4 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[(1, 1, "digest1")], checkpoints=[cp]) vcs = [vc1, vc2, vc3, vc4] assert builder.calc_batches(cp, vcs) == [BatchID(1, 1, "digest1")]
def test_calc_batches_takes_quorum_of_prepared(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) vc1 = ViewChange(viewNo=1, stableCheckpoint=0, prepared=[BatchID(0, 0, 1, "digest2")], preprepared=[BatchID(0, 0, 1, "digest2")], checkpoints=[cp]) vc2 = ViewChange(viewNo=1, stableCheckpoint=0, prepared=[BatchID(0, 0, 1, "digest1")], preprepared=[BatchID(0, 0, 1, "digest1")], checkpoints=[cp]) vc3 = ViewChange(viewNo=1, stableCheckpoint=0, prepared=[], preprepared=[BatchID(0, 0, 1, "digest1")], checkpoints=[cp]) vcs = [vc1, vc2, vc2, vc2] assert builder.calc_batches(cp, vcs) == [BatchID(0, 0, 1, "digest1")] vcs = [vc3, vc2, vc2, vc2] assert builder.calc_batches(cp, vcs) == [BatchID(0, 0, 1, "digest1")] vcs = [vc3, vc3, vc3, vc3] assert builder.calc_batches(cp, vcs) == [] vcs = [vc1, vc1, vc2, vc2] assert builder.calc_batches(cp, vcs) is None # since we have enough pre-prepares vcs = [vc2, vc3, vc3, vc3] assert builder.calc_batches(cp, vcs) == [BatchID(0, 0, 1, "digest1")] vcs = [vc2, vc2, vc3, vc3] assert builder.calc_batches(cp, vcs) == [BatchID(0, 0, 1, "digest1")]
def test_calc_batches_empty(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vcs = [ ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[], checkpoints=[cp]), ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[], checkpoints=[cp]), ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[], checkpoints=[cp]), ViewChange(viewNo=0, stableCheckpoint=0, prepared=[], preprepared=[], checkpoints=[cp]), ] assert [] == builder.calc_batches(cp, vcs)
def test_calc_batches_takes_next_view_one_prepared_if_weak_quorum_of_preprepared( builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0, 0)) vc1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (1, 2, "digest2")], preprepared=[(0, 1, "digest1"), (1, 2, "digest2")], checkpoints=[cp]) vc2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1"), (1, 2, "digest2")], checkpoints=[cp]) vc3 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vc4 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1")], preprepared=[(0, 1, "digest1")], checkpoints=[cp]) vcs = [vc1, vc2, vc3, vc4] assert builder.calc_batches( cp, vcs) == [BatchID(0, 1, "digest1"), (1, 2, "digest2")]
def test_calc_checkpoints_quorum(builder): cp1 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest='d1') cp2 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest='d2') vc1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp1]) vc2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp2]) vc2_stable = ViewChange(viewNo=0, stableCheckpoint=10, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp2]) vcs = [vc1, vc1, vc1, vc1] assert builder.calc_checkpoint(vcs) == cp1 vcs = [vc2, vc2, vc2, vc2] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc2_stable, vc2_stable, vc2_stable] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2, vc1, vc1, vc1] assert builder.calc_checkpoint(vcs) == cp1 vcs = [vc2, vc2, vc1, vc1] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2, vc2, vc2, vc1] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc1, vc1, vc1] assert builder.calc_checkpoint(vcs) == cp1 vcs = [vc2_stable, vc2_stable, vc1, vc1] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc2_stable, vc2_stable, vc1] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc2, vc2, vc2] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc2_stable, vc2, vc2] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2_stable, vc2_stable, vc2_stable, vc2] assert builder.calc_checkpoint(vcs) == cp2
def test_calc_checkpoints_selects_max(builder): cp1 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) cp2 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=cp_digest(10)) cp3 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=20, digest=cp_digest(20)) vc1 = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp1]) vc2_not_stable = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp2]) vc2_stable = ViewChange(viewNo=2, stableCheckpoint=10, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp2]) vc3_not_stable = ViewChange(viewNo=2, stableCheckpoint=10, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp3]) vc3_stable = ViewChange(viewNo=2, stableCheckpoint=10, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp3]) for vc3 in (vc3_not_stable, vc3_stable): for vc2 in (vc2_not_stable, vc2_stable): vcs = [vc1, vc2, vc3, vc3] assert builder.calc_checkpoint(vcs) == cp3 vcs = [vc1, vc3, vc3, vc3] assert builder.calc_checkpoint(vcs) == cp3 vcs = [vc2, vc3, vc3, vc3] assert builder.calc_checkpoint(vcs) == cp3 vcs = [vc2, vc2, vc3, vc3] assert builder.calc_checkpoint(vcs) == cp3 vcs = [vc1, vc1, vc3, vc3] assert builder.calc_checkpoint(vcs) == cp3 vcs = [vc1, vc1, vc1, vc3] assert builder.calc_checkpoint(vcs) == cp1 vcs = [vc1, vc1, vc2, vc2] assert builder.calc_checkpoint(vcs) == cp2 vcs = [vc2, vc2, vc2, vc3] assert builder.calc_checkpoint(vcs) == cp2
def test_calc_batches_diff_pp_viewno(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) vc1 = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 0, 1, "digest1"), BatchID(1, 0, 2, "digest2")], preprepared=[BatchID(1, 0, 1, "digest1"), BatchID(1, 0, 2, "digest2")], checkpoints=[cp]) vc2 = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 1, 1, "digest1"), BatchID(1, 1, 2, "digest2")], preprepared=[BatchID(1, 1, 1, "digest1"), BatchID(1, 1, 2, "digest2")], checkpoints=[cp]) vcs = [vc1, vc1, vc2, vc2] assert builder.calc_batches(cp, vcs) is None
def test_calc_checkpoints_digest(builder): d1 = cp_digest(0) d2 = cp_digest(10) cp1_d1 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=d1) cp2_d2 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=d2) cp2_d1 = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=d1) vc1_d1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp1_d1]) vc2_d2 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp2_d2]) vc2_d1 = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp2_d1]) vcs = [vc1_d1, vc1_d1, vc2_d1, vc2_d2] assert builder.calc_checkpoint(vcs) == cp1_d1 vcs = [vc1_d1, vc2_d1, vc2_d2, vc2_d2] assert builder.calc_checkpoint(vcs) == cp2_d2 vcs = [vc1_d1, vc2_d2, vc2_d1, vc2_d1] assert builder.calc_checkpoint(vcs) == cp2_d1 # Here we have 2 nodes malicious (f=1), but calc_checkpoint returns a value depending on the order # Is it OK, or calc_checkpoint should return None (indicating that there is no valid quorum)? vcs = [vc2_d1, vc2_d1, vc2_d2, vc2_d2] assert builder.calc_checkpoint(vcs) == cp2_d1 vcs = [vc2_d2, vc2_d2, vc2_d1, vc2_d1] assert builder.calc_checkpoint(vcs) == cp2_d2
def test_calc_checkpoints_empty(builder): vc = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[]) vcs = [vc, vc, vc, vc] assert builder.calc_checkpoint(vcs) is None
def _view_change(view_no: int): vc = ViewChange(viewNo=view_no, stableCheckpoint=4, prepared=[], preprepared=[], checkpoints=[]) return vc
def test_calc_checkpoints_equal_stable(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=10, digest=cp_digest(0)) vc = ViewChange(viewNo=2, stableCheckpoint=10, prepared=[BatchID(1, 1, 1, "digest1")], preprepared=[BatchID(1, 1, 1, "digest1")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_checkpoint(vcs) == cp
def test_calc_batches_combinations(builder, random): MAX_PP_SEQ_NO = 4 MAX_VIEW_NO = 2 MAX_DIGEST_ID = 4 cp = Checkpoint(instId=0, viewNo=1, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) for i in range(200): for vc_count in range(N - F, N + 1): view_changes = [] # 1. INIT for i in range(vc_count): # PRE-PREPARED num_preprepares = random.integer(0, MAX_PP_SEQ_NO) pre_prepares = [] for i in range(1, num_preprepares + 1): view_no = random.integer(0, MAX_VIEW_NO) batch_id = (view_no, random.integer(0, view_no), i, "digest{}".format(random.integer(1, MAX_DIGEST_ID))) pre_prepares.append(batch_id) # PREPARED prepares_mode = random.sample(['all-preprepared', 'half-preprepared', 'random-preprepared', 'random'], 1) if prepares_mode == ['all-preprepared']: prepares = pre_prepares elif prepares_mode == ['half-preprepared']: prepares = pre_prepares[:(num_preprepares // 2)] elif prepares_mode == ['random-preprepared']: prepares = random.sample(pre_prepares, len(pre_prepares)) elif prepares_mode == ['random']: num_prepares = random.integer(0, MAX_PP_SEQ_NO) prepares = [] for i in range(1, num_prepares + 1): view_no = random.integer(0, MAX_VIEW_NO) batch_id = (view_no, random.integer(0, view_no), i, "digest{}".format(random.integer(1, MAX_DIGEST_ID))) prepares.append(batch_id) else: assert False, str(prepares_mode) # CHECKPOINTS view_changes.append(ViewChange( viewNo=MAX_VIEW_NO, stableCheckpoint=0, prepared=prepares, preprepared=pre_prepares, checkpoints=[cp] )) # 2. EXECUTE batches = builder.calc_batches(cp, view_changes) # 3. VALIDATE committed = calc_committed(view_changes, MAX_PP_SEQ_NO, N, F) if committed and batches is not None: assert set(committed) <= set(batches)
def test_calc_batches_same_data_prev_pp_viewno(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) vc = ViewChange(viewNo=2, stableCheckpoint=0, prepared=[BatchID(1, 0, 1, "digest1"), BatchID(1, 0, 2, "digest2")], preprepared=[BatchID(1, 0, 1, "digest1"), BatchID(1, 0, 2, "digest2")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches(cp, vcs) == [BatchID(1, 0, 1, "digest1"), BatchID(1, 0, 2, "digest2")]
def _view_change(view_no: int): vc = ViewChange( viewNo=view_no, stableCheckpoint=4, prepared=[], preprepared=[], checkpoints=[Checkpoint(instId=0, viewNo=view_no, seqNoStart=0, seqNoEnd=4, digest=cp_digest(4))] ) return vc
def create_view_change(initial_view_no, stable_cp=10, batches=None): if batches is None: batches = create_batches(initial_view_no) digest = cp_digest(stable_cp) cp = Checkpoint(instId=0, viewNo=initial_view_no, seqNoStart=0, seqNoEnd=stable_cp, digest=digest) return ViewChange(viewNo=initial_view_no + 1, stableCheckpoint=stable_cp, prepared=batches, preprepared=batches, checkpoints=[cp])
def test_calc_checkpoints_equal_initial(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest='empty') vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(1, 1, "digest1")], preprepared=[(1, 1, "digest1")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_checkpoint(vcs) == cp
def start_view_change(self): # TODO: Calculate prepared = [] preprepared = [] self._data.view_no += 1 self._data.waiting_for_new_view = True vc = ViewChange(viewNo=self._data.view_no, stableCheckpoint=self._data.stable_checkpoint, prepared=prepared, preprepared=preprepared, checkpoints=self._data.checkpoints) self._network.send(vc)
def test_calc_batches_quorum(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest=cp_digest(0)) vc = ViewChange(viewNo=1, stableCheckpoint=0, prepared=[BatchID(0, 0, 1, "digest1"), BatchID(0, 0, 2, "digest2")], preprepared=[BatchID(0, 0, 1, "digest1"), BatchID(0, 0, 2, "digest2"), BatchID(0, 0, 3, "digest3")], checkpoints=[cp]) vcs = [vc] assert builder.calc_batches(cp, vcs) is None vcs.append(vc) assert builder.calc_batches(cp, vcs) is None vcs.append(vc) assert builder.calc_batches(cp, vcs)
def test_calc_batches_same_data(builder): cp = Checkpoint(instId=0, viewNo=0, seqNoStart=0, seqNoEnd=0, digest='empty') vc = ViewChange(viewNo=0, stableCheckpoint=0, prepared=[(0, 1, "digest1"), (0, 2, "digest2")], preprepared=[(0, 1, "digest1"), (0, 2, "digest2")], checkpoints=[cp]) vcs = [vc, vc, vc, vc] assert builder.calc_batches( cp, vcs) == [BatchID(0, 1, "digest1"), BatchID(0, 2, "digest2")]
def start_view_change(self): # TODO: Calculate prepared = [] preprepared = [] self._data.view_no += 1 self._data.waiting_for_new_view = True self._data.primary_name = self._find_primary(self._data.validators, self._data.view_no) vc = ViewChange(viewNo=self._data.view_no, stableCheckpoint=self._data.stable_checkpoint, prepared=prepared, preprepared=preprepared, checkpoints=self._data.checkpoints) self._network.send(vc)
def test_process_message_req_view_change(message_req_service: MessageReqService, external_bus, data: ConsensusSharedData, view_change_message: ViewChange): frm = "frm" digest = view_change_digest(view_change_message) message_req = MessageReq(**{ f.MSG_TYPE.nm: VIEW_CHANGE, f.PARAMS.nm: {f.INST_ID.nm: data.inst_id, f.DIGEST.nm: digest, f.NAME.nm: frm}, }) data.view_change_votes.add_view_change(view_change_message, frm) external_bus.process_incoming(message_req, frm) assert len(external_bus.sent_messages) == 1 assert external_bus.sent_messages[0] == (MessageRep(message_req.msg_type, message_req.params, view_change_message._asdict()), [frm])
def start_view_change(self, view_no: Optional[int] = None): if view_no is None: view_no = self._data.view_no + 1 self._clear_old_batches(self._old_prepared) self._clear_old_batches(self._old_preprepared) for pp in self._data.prepared: self._old_prepared[pp.ppSeqNo] = self._batch_id(pp) prepared = sorted([tuple(bid) for bid in self._old_prepared.values()]) for pp in self._data.preprepared: new_bid = self._batch_id(pp) pretenders = self._old_preprepared.get(pp.ppSeqNo, []) pretenders = [ bid for bid in pretenders if bid.pp_digest != new_bid.pp_digest ] pretenders.append(new_bid) self._old_preprepared[pp.ppSeqNo] = pretenders preprepared = sorted([ tuple(bid) for bids in self._old_preprepared.values() for bid in bids ]) self._data.view_no = view_no self._data.waiting_for_new_view = True self._data.primary_name = self._find_primary(self._data.validators, self._data.view_no) self._data.preprepared.clear() self._data.prepared.clear() self._votes.clear() self._new_view = None vc = ViewChange(viewNo=self._data.view_no, stableCheckpoint=self._data.stable_checkpoint, prepared=prepared, preprepared=preprepared, checkpoints=list(self._data.checkpoints)) self._network.send(vc) self._votes.add_view_change(vc, self._data.name) self._router.process_all_stashed()
def _build_view_change_msg(self): for batch_id in self._data.prepared: self._old_prepared[batch_id.pp_seq_no] = batch_id prepared = sorted(list(self._old_prepared.values())) for new_bid in self._data.preprepared: pretenders = self._old_preprepared.get(new_bid.pp_seq_no, []) pretenders = [ bid for bid in pretenders if bid.pp_digest != new_bid.pp_digest ] pretenders.append(new_bid) self._old_preprepared[new_bid.pp_seq_no] = pretenders preprepared = sorted( [bid for bids in self._old_preprepared.values() for bid in bids]) return ViewChange(viewNo=self._data.view_no, stableCheckpoint=self._data.stable_checkpoint, prepared=prepared, preprepared=preprepared, checkpoints=list(self._data.checkpoints))
def test_process_message_rep_view_change_from_one(message_req_service: MessageReqService, external_bus, data, view_change_message: ViewChange): frm = "frm" inst_id = data.inst_id digest = view_change_digest(view_change_message) key = (frm, digest) message_req_service.handlers[VIEW_CHANGE].requested_messages[key] = None message_rep_from_primary = MessageRep(**{ f.MSG_TYPE.nm: VIEW_CHANGE, f.PARAMS.nm: {f.INST_ID.nm: inst_id, f.DIGEST.nm: digest, f.NAME.nm: frm}, f.MSG.nm: dict(view_change_message.items()) }) frm = "frm" network_handler = Mock() external_bus.subscribe(ViewChange, network_handler) network_handler.assert_not_called() message_req_service.process_message_rep(message_rep_from_primary, frm) network_handler.assert_called_once_with(view_change_message, frm)
def start_view_change(self, view_no: Optional[int] = None): if view_no is None: view_no = self._data.view_no + 1 self._clear_old_batches(self._old_prepared) self._clear_old_batches(self._old_preprepared) for batch_id in self._data.prepared: self._old_prepared[batch_id.pp_seq_no] = batch_id prepared = sorted([tuple(bid) for bid in self._old_prepared.values()]) for new_bid in self._data.preprepared: pretenders = self._old_preprepared.get(new_bid.pp_seq_no, []) pretenders = [bid for bid in pretenders if bid.pp_digest != new_bid.pp_digest] pretenders.append(new_bid) self._old_preprepared[new_bid.pp_seq_no] = pretenders preprepared = sorted([tuple(bid) for bids in self._old_preprepared.values() for bid in bids]) self._data.view_no = view_no self._data.waiting_for_new_view = True self._data.primary_name = self._primaries_selector.select_primaries(view_no=self._data.view_no, instance_count=self._data.quorums.f + 1, validators=self._data.validators)[0] self._data.preprepared.clear() self._data.prepared.clear() self._votes.clear() self._new_view = None vc = ViewChange( viewNo=self._data.view_no, stableCheckpoint=self._data.stable_checkpoint, prepared=prepared, preprepared=preprepared, checkpoints=list(self._data.checkpoints) ) self._network.send(vc) self._votes.add_view_change(vc, self._data.name) self._router.process_all_stashed()