def test_get_msgs_for_lagged_nodes(tmpdir): ledgerInfo = ( # ledger id, ledger length, merkle root (0, 10, '7toTJZHzaxQ7cGZv18MR4PMBfuUecdEQ1JRqJVeJBvmd'), (1, 5, 'Hs9n4M3CrmrkWGVviGq48vSbMpCrk6WgSBZ7sZAWbJy3'), ) messages = [ (ViewChangeDone( viewNo=0, name='Node2', ledgerInfo=ledgerInfo), 'Node1'), (ViewChangeDone( viewNo=0, name='Node3', ledgerInfo=ledgerInfo), 'Node2')] node = FakeNode(str(tmpdir)) selector = PrimarySelector(node) for message in messages: selector._processViewChangeDoneMessage(*message) messages_for_lagged = selector.get_msgs_for_lagged_nodes() assert {m for m in messages_for_lagged} == { m[0] for m in messages if m[1] == node.name}
def testProcessViewChangeDone(): ledgerInfo = ( # ledger id, ledger length, merkle root (0, 10, '7toTJZHzaxQ7cGZv18MR4PMBfuUecdEQ1JRqJVeJBvmd'), (1, 5, 'Hs9n4M3CrmrkWGVviGq48vSbMpCrk6WgSBZ7sZAWbJy3')) msg = ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo) node = FakeNode() selector = PrimarySelector(node) quorum = selector.quorum for i in range(quorum): selector._processViewChangeDoneMessage(msg, 'Node2') assert selector._view_change_done assert not node.is_primary_found() selector._processViewChangeDoneMessage(msg, 'Node1') assert selector._view_change_done assert not node.is_primary_found() selector._processViewChangeDoneMessage(msg, 'Node3') assert selector._verify_primary(msg.name, msg.ledgerInfo) selector._startSelection() assert selector._view_change_done # Since the FakeNode does not have setting of mode # assert node.is_primary_found() selector.view_change_started(1) assert not selector._view_change_done
def test_process_view_change_done(tdir, tconf): ledgerInfo = ( # ledger id, ledger length, merkle root (0, 10, '7toTJZHzaxQ7cGZv18MR4PMBfuUecdEQ1JRqJVeJBvmd'), (1, 5, 'Hs9n4M3CrmrkWGVviGq48vSbMpCrk6WgSBZ7sZAWbJy3') ) msg = ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo) node = FakeNode(str(tdir), tconf) quorum = node.view_changer.quorum for i in range(quorum): node.view_changer.process_vchd_msg(msg, 'Node2') assert node.view_changer._view_change_done assert not node.is_primary_found() node.view_changer.process_vchd_msg(msg, 'Node1') assert node.view_changer._view_change_done assert not node.is_primary_found() node.view_changer.process_vchd_msg(msg, 'Node3') assert node.view_changer._verify_primary(msg.name, msg.ledgerInfo) node.view_changer._start_selection() assert node.view_changer._view_change_done # Since the FakeNode does not have setting of mode # assert node.is_primary_found() node.view_changer.pre_vc_strategy = None node.view_changer.start_view_change(1) assert not node.view_changer._view_change_done
def test_get_msgs_for_lagged_nodes(tconf, tdir): ledgerInfo = ( # ledger id, ledger length, merkle root (0, 10, '7toTJZHzaxQ7cGZv18MR4PMBfuUecdEQ1JRqJVeJBvmd'), (1, 5, 'Hs9n4M3CrmrkWGVviGq48vSbMpCrk6WgSBZ7sZAWbJy3'), ) messages = [(ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo), 'Node1'), (ViewChangeDone(viewNo=0, name='Node3', ledgerInfo=ledgerInfo), 'Node2')] node = FakeNode(str(tdir), tconf) for message in messages: node.view_changer.process_vchd_msg(*message) messages_for_lagged = node.view_changer.get_msgs_for_lagged_nodes() assert {m for m in messages_for_lagged } == {m[0] for m in messages if m[1] == node.name}
def _send_view_change_done_message(self): """ Sends ViewChangeDone message to other protocol participants """ new_primary_name = self.next_primary_node_name(0) ledger_summary = self.ledger_summary message = ViewChangeDone(self.viewNo, new_primary_name, ledger_summary) self.send(message) self._track_view_change_done(self.name, new_primary_name, ledger_summary)
def get_msgs_for_lagged_nodes(self) -> List[ViewChangeDone]: # Should not return a list, only done for compatibility with interface """ Returns the last accepted `ViewChangeDone` message. If no view change has happened returns ViewChangeDone with view no 0 to a newly joined node """ # TODO: Consider a case where more than one node joins immediately, # then one of the node might not have an accepted # ViewChangeDone message messages = [] accepted = self._accepted_view_change_done_message if accepted: messages.append(ViewChangeDone(self.last_completed_view_no, *accepted)) elif self.name in self._view_change_done: messages.append(ViewChangeDone(self.last_completed_view_no, *self._view_change_done[self.name])) else: logger.info('{} has no ViewChangeDone message to send for view {}'. format(self, self.view_no)) return messages
def test_send_view_change_done_message(tdir, tconf): node = FakeNode(str(tdir), tconf) node.view_changer._send_view_change_done_message() ledgerInfo = [ # ledger id, ledger length, merkle root (0, 10, '4F7BsTMVPKFshM1MwLf6y23cid6fL3xMpazVoF9krzUw'), (1, 5, '4K2V1kpVycZ6qSFsNdz2FtpNxnJs17eBNzf9rdCMcKoe'), ] messages = [ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo)] assert len(node.view_changer.outBox) == 1 assert list(node.view_changer.outBox) == messages
def test_future_vcdone_vc(fake_node, view_change_in_progress): """ If from_current_state is False, then message should be put only into msgsForFutureViews queue """ frm = 'Node3' fake_node.view_changer.view_change_in_progress = view_change_in_progress current_view = fake_node.viewNo proposed_view_no = current_view + 1 msg = ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) res = Node.msgHasAcceptableViewNo(fake_node, msg, frm) assert proposed_view_no in fake_node.msgsForFutureViews assert proposed_view_no not in fake_node.msgsToViewChanger assert not res
def _send_view_change_done_message(self): """ Sends ViewChangeDone message to other protocol participants """ new_primary_name = self.node.elector.next_primary_node_name(0) ledger_summary = self.node.ledger_summary message = ViewChangeDone(self.view_no, new_primary_name, ledger_summary) logger.debug("{} is sending ViewChangeDone msg to all : {}" "".format(self, message)) self.send(message) self._on_verified_view_change_done_msg(message, self.name)
def test_future_vcdone_when_propagate_primary_no_quorum(fake_node): """ Check, that view_change would not be started without quorum of future_view_change_done messages if propagate_primary is True """ frm = 'Node3' current_view = fake_node.view_changer.last_completed_view_no proposed_view_no = current_view + 1 msg = ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) fake_node.view_changer._next_view_indications[proposed_view_no] = {} fake_node.view_changer._next_view_indications[proposed_view_no][frm] = msg view_changer = fake_node.view_changer res = view_changer._do_view_change_by_future_vcd(proposed_view_no) assert res is False
def test_get_msgs_for_lagged_node_if_no_accepted(node_with_nodestack): """ If _accepted_view_change_done_message is empty, then ViewChangeDone messages will be compiled from _view_change_done dict """ fake_view_changer = node_with_nodestack.view_changer fake_view_changer._accepted_view_change_done_message = () current_view = fake_view_changer.last_completed_view_no fake_view_changer._view_change_done[node_with_nodestack.name] = ( 'SomeNewPrimary', node_with_nodestack.ledger_summary) vch_messages = fake_view_changer.get_msgs_for_lagged_nodes() assert vch_messages == [ ViewChangeDone( current_view, *fake_view_changer._view_change_done[node_with_nodestack.name]) ]
def test_future_vcdone_with_is_initial_propagate_primary_no_quorum(fake_node): """ Check, that view_change would be not started without quorum of propagate_primary view_change_done messages if is_initial_propagate_primary is True """ frm = 'Node3' current_view = fake_node.view_changer.last_completed_view_no proposed_view_no = current_view + 1 msg = ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) fake_node.view_changer._next_view_indications[proposed_view_no] = {} fake_node.view_changer._next_view_indications[proposed_view_no][frm] = msg view_changer = fake_node.view_changer res = view_changer._start_view_change_if_possible( proposed_view_no, is_initial_propagate_primary=True) assert res is False
def test_from_current_state(fake_node): """ If from_current_state is True and is initial propagate primary (current viewNo is 0), then message should be put into msgsToViewChanger queue with from_current_state flag as True """ frm = 'Node3' fake_node.view_changer.view_change_in_progress = False current_view = fake_node.view_changer.last_completed_view_no proposed_view_no = current_view + 1 msg = ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) res = Node.msgHasAcceptableViewNo(fake_node, msg, frm, from_current_state=True) msg, frm = fake_node.msgsToViewChanger[0] assert len(fake_node.msgsToViewChanger) == 1 assert msg.from_current_state assert res is False
def test_send_view_change_done_message(tdir, tconf): node = FakeNode(str(tdir), tconf) view_no = node.view_changer.view_no new_primary_name = node.elector.node.get_name_by_rank( node.elector._get_master_primary_id(view_no, node.totalNodes)) node.view_changer._send_view_change_done_message() ledgerInfo = [ # ledger id, ledger length, merkle root (0, 10, '4F7BsTMVPKFshM1MwLf6y23cid6fL3xMpazVoF9krzUw'), (1, 5, '4K2V1kpVycZ6qSFsNdz2FtpNxnJs17eBNzf9rdCMcKoe'), ] messages = [ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo)] assert len(node.view_changer.outBox) == 1 print(list(node.view_changer.outBox)) print(messages) assert list(node.view_changer.outBox) == messages
def test_future_vcdone_now_when_propagate_primary_with_quorum(fake_node): """ Check, that view_change would be started without quorum of future_view_change_done messages if propagate_primary is False """ quorum = fake_node.totalNodes - fake_node.f frms = fake_node.allNodeNames[-quorum:] current_view = fake_node.view_changer.last_completed_view_no proposed_view_no = current_view + 1 msgs = [ ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) for frm in frms ] fake_node.view_changer._next_view_indications[proposed_view_no] = {} for i in range(len(msgs)): fake_node.view_changer._next_view_indications[proposed_view_no][ frms[i]] = msgs[i] view_changer = fake_node.view_changer res = view_changer._do_view_change_by_future_vcd(proposed_view_no) assert res is True
def test_send_view_change_done_message(): node = FakeNode() selector = PrimarySelector(node) instance_id = 0 view_no = selector.viewNo new_primary_name = selector.node.get_name_by_rank( selector._get_primary_id(view_no, instance_id)) selector._send_view_change_done_message() ledgerInfo = [ # ledger id, ledger length, merkle root (0, 10, '4F7BsTMVPKFshM1MwLf6y23cid6fL3xMpazVoF9krzUw'), (1, 5, '4K2V1kpVycZ6qSFsNdz2FtpNxnJs17eBNzf9rdCMcKoe'), ] messages = [ViewChangeDone(viewNo=0, name='Node2', ledgerInfo=ledgerInfo)] assert len(selector.outBox) == 1 print(list(selector.outBox)) print(messages) assert list(selector.outBox) == messages
def test_future_vcdone_without_is_initial_propagate_primary_no_quorum( fake_node): """ Check, that view_change would be not started without quorum of propagate_primary view_change_done messages if is_initial_propagate_primary is False """ quorum = fake_node.f + 1 frms = fake_node.allNodeNames[-quorum:] current_view = fake_node.view_changer.last_completed_view_no proposed_view_no = current_view + 1 msgs = [ ViewChangeDone(proposed_view_no, frm, fake_node.ledger_summary) for frm in frms ] fake_node.view_changer._next_view_indications[proposed_view_no] = {} for i in range(len(msgs)): fake_node.view_changer._next_view_indications[proposed_view_no][ frms[i]] = msgs[i] view_changer = fake_node.view_changer res = view_changer._start_view_change_if_possible( proposed_view_no, is_initial_propagate_primary=False) assert res is False