adding highest voted view so that a node doesn't vote twice.

This commit is contained in:
mjalalzai 2023-03-30 20:38:30 -07:00
parent 19c5fa3592
commit 88a3fa04a6
2 changed files with 69 additions and 10 deletions

View File

@ -158,6 +158,7 @@ class Carnot:
def __init__(self, _id: Id):
self.id: Id = _id
self.current_view: View = 0
self.highest_voted_view:View=0
self.local_high_qc: Optional[Qc] = None
self.latest_committed_view: View = 0
self.safe_blocks: Dict[Id, Block] = dict()
@ -203,14 +204,13 @@ class Carnot:
self.safe_blocks[block.id()] = block
self.update_high_qc(block.qc)
self.try_commit_grand_parent(block)
self.increment_view_qc(block.qc)
def vote(self, block: Block, votes: Set[Vote]):
assert block.id() in self.safe_blocks
assert len(votes) == self.overlay.super_majority_threshold(self.id)
assert all(self.overlay.child_committee(self.id, vote.voter) for vote in votes)
assert all(vote.block == block.id() for vote in votes)
assert (block.view>highest_voted_view)
if self.overlay.member_of_root_com(self.id):
vote: Vote = Vote(
block=block.id(),
@ -227,6 +227,8 @@ class Carnot:
qc=None
)
self.send(vote, *self.overlay.parent_committee(self.id))
self.increment_voted_view(block.view)
self.increment_view_qc(block.qc)
def forward_vote(self, vote: Vote):
assert vote.block in self.safe_blocks
@ -248,6 +250,7 @@ class Carnot:
def local_timeout(self, new_overlay: Overlay):
self.last_timeout_view = self.current_view
increment_voted_view(self.current_view) # to avoid voting again for this view.
self.overlay = new_overlay
if self.overlay.member_of_leaf_committee(self.id):
raise NotImplementedError()
@ -275,6 +278,8 @@ class Carnot:
)
if can_commit:
self.committed_blocks[block.id()] = block
def increment_voted_view(self,view: View):
highest_voted_view =max(view,highest_voted_view)
def increment_view_qc(self, qc: Qc) -> bool:
if qc.view < self.current_view:

View File

@ -36,9 +36,9 @@ class TestCarnotHappyPath(TestCase):
carnot.receive_block(block4)
# This test seem to fail because safe_block dict checks for id of
#the block and we can receive blocks with different ids for the same view.
#the block, and we can receive blocks with different ids for the same view.
# There must be only one block per view at most.
# May be we have a dict with view as key and dict[block.id()]block as value?
# Maybe we have a dict with view as key and dict[block.id()]block as value?
block5 = Block(view=4, qc=StandardQc(block=block3.id(), view=3))
carnot.receive_block(block5)
@ -62,17 +62,13 @@ class TestCarnotHappyPath(TestCase):
block4 = Block(view=4, qc=StandardQc(block=block3.id(), view=3))
carnot.receive_block(block4)
# 5 This is the old standard qc of block number 3. For standarnd QC we must always have qc.view==block.view-1.
# This block should be rejected based on the condition below in block_is_safe().
# block.view >= self.latest_committed_view and block.view == (standard.view + 1)
# block_is_safe() should return false.
block5 = Block(view=3, qc=StandardQc(block=block4.id(), view=4))
carnot.receive_block(block5)
def test_receive_block_has_an_old_qc(self):
def test_receive_block_has_an_old_qc(self):
carnot = Carnot(int_to_id(0))
genesis_block = self.add_genesis_block(carnot)
# 1
@ -95,4 +91,62 @@ class TestCarnotHappyPath(TestCase):
# block.view >= self.latest_committed_view and block.view == (standard.view + 1)
# block_is_safe() should return false.
block5 = Block(view=5, qc=StandardQc(block=block3.id(), view=3))
carnot.receive_block(block5)
carnot.receive_block(block5)
#Any block with block.view < 4 must be committed
def test_receive_block_and_commit_its_grand_parent_chain(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)
block5 = Block(view=5, qc=StandardQc(block=block3.id(), view=3))
carnot.receive_block(block5)
# Block3 must be committed as it is the grandparent of block5. Hence, it should not be possible
#to avert it.
def test_receive_block_has_an_old_qc_and_tries_to_revert_a_committed_block(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)
# 5 This is the old standard qc of block number 2. By using the QC for block2, block5 tries to form a fork
# to avert block3 and block b4. Block3 is a committed block
# block_is_safe() should return false.
block5 = Block(view=5, qc=StandardQc(block=block2.id(), view=2))
carnot.receive_block(block5)