From f596893cd3bc915ac64ee700b526baea759dd54c Mon Sep 17 00:00:00 2001 From: mjalalzai <33738574+MForensic@users.noreply.github.com> Date: Fri, 31 Mar 2023 14:19:11 -0700 Subject: [PATCH] Tests for updating latest_committed_view and high_qc. --- carnot/carnot.py | 10 +++++-- carnot/test_happy_path.py | 61 ++++++++++++++++++++++++++++++++------- requirements.txt | 0 setup.py | 12 ++++++++ 4 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/carnot/carnot.py b/carnot/carnot.py index 6184f93..874c016 100644 --- a/carnot/carnot.py +++ b/carnot/carnot.py @@ -34,6 +34,7 @@ class AggregateQc: Qc: TypeAlias = StandardQc | AggregateQc + @dataclass class Block: view: View @@ -74,6 +75,7 @@ class Overlay: """ Overlay structure for a View """ + @abstractmethod def is_leader(self, _id: Id): """ @@ -272,15 +274,19 @@ class Carnot: return can_commit = ( parent.view == (grand_parent.view + 1) and - isinstance(block.qc, (StandardQc, )) and - isinstance(parent.qc, (StandardQc, )) + isinstance(block.qc, (StandardQc,)) and + isinstance(parent.qc, (StandardQc,)) ) if can_commit: self.committed_blocks[grand_parent.id()] = grand_parent + self.increment_latest_committed_view(grand_parent.view) def increment_voted_view(self, view: View): self.highest_voted_view = max(view, self.highest_voted_view) + def increment_latest_committed_view(self, view: View): + self.latest_committed_view = max(view, self.latest_committed_view) + def increment_view_qc(self, qc: Qc) -> bool: if qc.view < self.current_view: return False diff --git a/carnot/test_happy_path.py b/carnot/test_happy_path.py index eba3d50..0278dee 100644 --- a/carnot/test_happy_path.py +++ b/carnot/test_happy_path.py @@ -35,6 +35,10 @@ class TestCarnotHappyPath(TestCase): carnot.receive_block(block4) self.assertEqual(len(carnot.safe_blocks), 5) # next block is duplicated and as it is already processed should be skipped + + # In my opinion duplicated block is rejected because both blocks have the same ID. + # In reality the IDs of blocks for the same view can be different if we compute ID based on + # the hash of the block content. What do you think? block5 = Block(view=4, qc=StandardQc(block=block3.id(), view=3)) carnot.receive_block(block5) self.assertEqual(len(carnot.safe_blocks), 5) @@ -145,10 +149,56 @@ class TestCarnotHappyPath(TestCase): carnot.receive_block(block5) self.assertEqual(len(carnot.safe_blocks), 5) + def test_receive_block_and_verify_if_latest_committed_view_is_incremented(self): + carnot = Carnot(int_to_id(0)) + genesis_block = self.add_genesis_block(carnot) + # 1 + block1 = Block(view=1, qc=StandardQc(block=genesis_block.id(), view=0)) + carnot.receive_block(block1) + + # 2 + block2 = Block(view=2, qc=StandardQc(block=block1.id(), view=1)) + carnot.receive_block(block2) + + # 3 + block3 = Block(view=3, qc=StandardQc(block=block2.id(), view=2)) + carnot.receive_block(block3) + # 4 + block4 = Block(view=4, qc=StandardQc(block=block3.id(), view=3)) + carnot.receive_block(block4) + + self.assertEqual(len(carnot.safe_blocks), 5) + block5 = Block(view=5, qc=StandardQc(block=block4.id(), view=4)) + carnot.receive_block(block5) + self.assertEqual(carnot.latest_committed_view, 3) + + def test_receive_block_and_verify_if_high_qc_is_updated(self): + carnot = Carnot(int_to_id(0)) + genesis_block = self.add_genesis_block(carnot) + # 1 + block1 = Block(view=1, qc=StandardQc(block=genesis_block.id(), view=0)) + carnot.receive_block(block1) + + # 2 + block2 = Block(view=2, qc=StandardQc(block=block1.id(), view=1)) + carnot.receive_block(block2) + + # 3 + block3 = Block(view=3, qc=StandardQc(block=block2.id(), view=2)) + carnot.receive_block(block3) + # 4 + block4 = Block(view=4, qc=StandardQc(block=block3.id(), view=3)) + carnot.receive_block(block4) + + self.assertEqual(len(carnot.safe_blocks), 5) + block5 = Block(view=5, qc=StandardQc(block=block4.id(), view=4)) + carnot.receive_block(block5) + self.assertEqual(carnot.local_high_qc.view, 4) + # Test cases for vote: # 1: If a node votes for same block twice - def test_vote_for_received_block(self): + def test_vote_for_received_block(self): class MockOverlay(Overlay): def member_of_root_com(self, _id: Id) -> bool: return False @@ -186,12 +236,3 @@ class TestCarnotHappyPath(TestCase): # 6: If a node counts votes of nodes other than it's child committees. # 7: If a node counts distinct votes for a safe block from its child committees. # 8: If 7 is true, will the node vote for the mentioned safe block - - - - - - - - - diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..756c06e --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup + +setup( + name='nomos-specs', + version='', + packages=['carnot'], + url='', + license='', + author='mohammad-az', + author_email='', + description='' +)