overriding methods

This commit is contained in:
mjalalzai 2023-10-18 12:35:00 -07:00
parent 758a3c44e0
commit c3c5196bb8

View File

@ -2,6 +2,8 @@ from dataclasses import dataclass
from typing import Union, List, Set, Optional, Type, TypeAlias, Dict
from abc import ABC, abstractmethod
from carnot import Carnot, Overlay
Id = bytes
View = int
Committee = Set[Id]
@ -119,47 +121,11 @@ class Send:
Event: TypeAlias = Union[BroadCast, Send]
class Overlay:
class Overlay2(Overlay):
"""
Overlay structure for a View
"""
@abstractmethod
def is_leader(self, _id: Id):
"""
:param _id: Node id to be checked
:return: true if node is the leader of the current view
"""
return _id == self.leader()
@abstractmethod
def leader(self) -> Id:
"""
:param view:
:return: the leader Id of the specified view
"""
pass
@abstractmethod
def next_leader(self) -> Id:
pass
@abstractmethod
def is_member_of_leaf_committee(self, _id: Id) -> bool:
"""
:param _id: Node id to be checked
:return: true if the participant with Id _id is in the leaf committee of the committee overlay
"""
pass
@abstractmethod
def is_member_of_root_committee(self, _id: Id) -> bool:
"""
:param _id:
:return: true if the participant with Id _id is member of the root committee withing the tree overlay
"""
pass
@abstractmethod
def is_member_of_my_committee(self, _id: Id) -> bool:
"""
@ -168,15 +134,6 @@ class Overlay:
"""
pass
@abstractmethod
def is_member_of_child_committee(self, parent: Id, child: Id) -> bool:
"""
:param parent:
:param child:
:return: true if participant with Id child is member of the child committee of the participant with Id parent
"""
pass
def is_member_of_subtree(self, root_node: Id, child: Id) -> bool:
"""
:param root_node:
@ -185,26 +142,6 @@ class Overlay:
"""
pass
@abstractmethod
def parent_committee(self, _id: Id) -> Optional[Committee]:
"""
:param _id:
:return: Some(parent committee) of the participant with Id _id withing the committee tree overlay
or Empty if the member with Id _id is a participant of the root committee
"""
pass
@abstractmethod
def leaf_committees(self) -> Set[Committee]:
pass
@abstractmethod
def root_committee(self) -> Committee:
"""
:return: returns root committee
"""
pass
@abstractmethod
def my_committee(self, _id: Id) -> Optional[Committee]:
"""
@ -213,13 +150,6 @@ class Overlay:
"""
pass
@abstractmethod
def is_child_of_root_committee(self, _id: Id) -> bool:
"""
:return: returns child committee/s of root committee if present
"""
pass
@abstractmethod
def leader_super_majority_threshold(self, _id: Id) -> int:
"""
@ -237,9 +167,16 @@ class Overlay:
"""
pass
def number_of_committees(self) -> int:
"""
:return: returns total number of committees in the overlay.
"""
pass
class Carnot:
def __init__(self, _id: Id, overlay=Overlay()):
class Carnot2(Carnot):
def __init__(self, _id: Id, overlay=Overlay2()):
self.latest_committed_block = None
self.id: Id = _id
self.current_view: View = 0
self.highest_voted_view: View = -1
@ -264,25 +201,32 @@ class Carnot:
# Return True if both conditions are met
return is_view_incremented and is_standard_qc
def latest_committed_view(self) -> View:
return self.latest_committed_block().view
@abstractmethod
def commit_block(self, block: Block) -> bool:
pass
# Return a list of blocks received by a node for a specific view.
# More than one block is returned only in case of a malicious leader.
def blocks_in_view(self, view: View) -> List[Block]:
return [block for block in self.safe_blocks.values() if block.view == view]
def commit_the_chain(self, grand_parent: Block):
# Create an empty stack to store the blocks in reverse order
block_stack = []
def genesis_block(self) -> Block:
return self.blocks_in_view(0)[0]
# Start with the grand_parent block
current_block = grand_parent
def latest_committed_block(self) -> Block:
for view in range(self.current_view, 0, -1):
for block in self.blocks_in_view(view):
if self.can_commit_grandparent(block):
return self.safe_blocks.get(self.safe_blocks.get(block.parent()).parent())
# The genesis block is always considered committed.
return self.genesis_block()
# Push blocks onto the stack until we reach the parent of the latest_committed_block
while current_block != self.latest_committed_block.parent():
block_stack.append(current_block)
current_block = self.safe_blocks.get(current_block.parent())
# Pop and commit blocks from the stack to execute them in order
while block_stack:
block_to_commit = block_stack.pop()
# Commit the transactions of the block using your commit_block method
self.commit_block(block_to_commit)
latest_committed_block = block_to_commit
# Update the latest committed block to be the latest_committed_block
self.latest_committed_block = latest_committed_block
# The the check for the first block generated after unhappy path is added.
def block_is_safe(self, block: Block) -> bool:
if isinstance(block.qc, StandardQc):
return block.view_num == block.qc.view() + 1
@ -308,29 +252,15 @@ class Carnot:
self.local_high_qc = new_qc.high_qc()
# If my view is not updated, I update it when I see a QC for that view
# If there is any missing blocks then these blocks should be downloaded.
if qc.view >= self.current_view:
self.current_view = qc.view + 1
# Feel free to remove, just added for simplicity.
def update_timeout_qc(self, timeout_qc: TimeoutQc):
if not self.last_view_timeout_qc or timeout_qc.view > self.last_view_timeout_qc.view:
self.last_view_timeout_qc = timeout_qc
def receive_block(self, block: Block):
assert block.parent() in self.safe_blocks
# Check if the block is already in safe_blocks, if it's from a previous view,
# or if there are existing blocks for the same view
if block.id() in self.safe_blocks or block.view <= self.latest_committed_view() or self.blocks_in_view(
block.view):
# TODO: Report malicious leader or handle potential fork divergence
return
# TODO: Verify if the proposer is indeed the leader
# If the block is safe, add it to safe_blocks and update the high QC
if self.block_is_safe(block):
self.safe_blocks[block.id()] = block
self.update_high_qc(block.qc)
def approve_block(self, block: Block, votes: Set[Vote]) -> Event:
# Assertions for input validation
@ -340,7 +270,7 @@ class Carnot:
# When there is the first timeout t1 for the fast path and the protocol operates in the slower path
# in this case the node will prepare a QC from votes it has received.
# assert len(votes) == self.overlay.super_majority_threshold(self.id)
# assert all(self.overlay.is_member_of_my_committee(self.id, vote.voter) for vote in votes)
assert all(self.overlay.is_member_of_subtree(self.id, vote.voter) for vote in votes)
assert all(vote.block == block.id() for vote in votes)
assert self.highest_voted_view < block.view
@ -362,8 +292,10 @@ class Carnot:
# When a QC is formed from 2/3rd of subtree votes, it's forwarded to the parent committee.
# If a Type 1 timeout occurs, a QC is built from available votes and QCs and sent to the parent.
# Subsequent votes are forwarded to the parent committee members.
recipient = self.overlay.my_committee(self.id)
if self.overlay.number_of_committees==1:
recipient = self.overlay.leader(block.view + 1)
else:
recipient = self.overlay.my_committee(self.id)
# Return a Send event to the appropriate recipient
return Send(to=recipient, payload=vote)