diff --git a/carnot/carnot-vote-aggregation.py b/carnot/carnot-vote-aggregation.py index 63d5242..3fe316a 100644 --- a/carnot/carnot-vote-aggregation.py +++ b/carnot/carnot-vote-aggregation.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Union, List, Set, Optional, Type, TypeAlias +from typing import Union, List, Set, Optional, Type, TypeAlias, Dict from abc import ABC, abstractmethod Id = bytes @@ -102,4 +102,136 @@ class NewView: Quorum: TypeAlias = Union[Set[Vote], Set[NewView]] -Payload: TypeAlias = Union[Block, Vote, Timeout, NewView, TimeoutQc] +Payload: TypeAlias = Union[Block, Vote, Timeout, NewView, TimeoutQc] + + +@dataclass +class BroadCast: + payload: Payload + + +@dataclass +class Send: + to: [Id] + payload: Payload + + +Event: TypeAlias = BroadCast | Send + + +class 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_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 + + @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 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: + """ + Amount of distinct number of messages for a node with Id _id member of a committee + The return value may change depending on which committee the node is member of, including the leader + :return: + """ + pass + + @abstractmethod + def super_majority_threshold(self, _id: Id) -> int: + pass + + +class Carnot: + def __init__(self, _id: Id, overlay=Overlay()): + self.id: Id = _id + self.current_view: View = 0 + self.highest_voted_view: View = -1 + self.local_high_qc: Type[Qc] = None + self.safe_blocks: Dict[Id, Block] = dict() + self.last_view_timeout_qc: Type[TimeoutQc] = None + self.overlay: Overlay = overlay + + def can_commit_grandparent(self, block) -> bool: + # Get the parent block and grandparent block from the safe_blocks dictionary + parent = self.safe_blocks.get(block.parent()) + grandparent = self.safe_blocks.get(parent.parent()) + + # Check if both parent and grandparent exist + if parent is None or grandparent is None: + return False + + # Check if the view numbers and QC types match the expected criteria + is_view_incremented = parent.view == grandparent.view + 1 + is_standard_qc = isinstance(block.qc, StandardQc) and isinstance(parent.qc, StandardQc) + + # Return True if both conditions are met + return is_view_incremented and is_standard_qc