def __init__(self, node: 'plenum.server.node.Node', instId: int, isMaster: bool = False): """ Create a new replica. :param node: Node on which this replica is located :param instId: the id of the protocol instance the replica belongs to :param isMaster: is this a replica of the master protocol instance """ HasActionQueue.__init__(self) self.stats = Stats(TPCStat) self.config = getConfig() routerArgs = [(ReqDigest, self._preProcessReqDigest)] for r in [PrePrepare, Prepare, Commit]: routerArgs.append((r, self.processThreePhaseMsg)) routerArgs.append((Checkpoint, self.processCheckpoint)) routerArgs.append((ThreePCState, self.process3PhaseState)) self.inBoxRouter = Router(*routerArgs) self.threePhaseRouter = Router((PrePrepare, self.processPrePrepare), (Prepare, self.processPrepare), (Commit, self.processCommit)) self.node = node self.instId = instId self.name = self.generateName(node.name, self.instId) self.outBox = deque() """ This queue is used by the replica to send messages to its node. Replica puts messages that are consumed by its node """ self.inBox = deque() """ This queue is used by the replica to receive messages from its node. Node puts messages that are consumed by the replica """ self.inBoxStash = deque() """ If messages need to go back on the queue, they go here temporarily and are put back on the queue on a state change """ self.isMaster = isMaster # Indicates name of the primary replica of this protocol instance. # None in case the replica does not know who the primary of the # instance is self._primaryName = None # type: Optional[str] # Requests waiting to be processed once the replica is able to decide # whether it is primary or not self.postElectionMsgs = deque() # PRE-PREPAREs that are waiting to be processed but do not have the # corresponding request digest. Happens when replica has not been # forwarded the request by the node but is getting 3 phase messages. # The value is a list since a malicious entry might send PRE-PREPARE # with a different digest and since we dont have the request finalised, # we store all PRE-PPREPARES self.prePreparesPendingReqDigest = { } # type: Dict[Tuple[str, int], List] # PREPAREs that are stored by non primary replica for which it has not # got any PRE-PREPARE. Dictionary that stores a tuple of view no and # prepare sequence number as key and a deque of PREPAREs as value. # This deque is attempted to be flushed on receiving every # PRE-PREPARE request. self.preparesWaitingForPrePrepare = {} # type: Dict[Tuple[int, int], deque] # COMMITs that are stored for which there are no PRE-PREPARE or PREPARE # received self.commitsWaitingForPrepare = {} # type: Dict[Tuple[int, int], deque] # Dictionary of sent PRE-PREPARE that are stored by primary replica # which it has broadcasted to all other non primary replicas # Key of dictionary is a 2 element tuple with elements viewNo, # pre-prepare seqNo and value is a tuple of Request Digest and time self.sentPrePrepares = {} # type: Dict[Tuple[int, int], Tuple[Tuple[str, int], float]] # Dictionary of received PRE-PREPAREs. Key of dictionary is a 2 # element tuple with elements viewNo, pre-prepare seqNo and value is # a tuple of Request Digest and time self.prePrepares = {} # type: Dict[Tuple[int, int], Tuple[Tuple[str, int], float]] # Dictionary of received Prepare requests. Key of dictionary is a 2 # element tuple with elements viewNo, seqNo and value is a 2 element # tuple containing request digest and set of sender node names(sender # replica names in case of multiple protocol instances) # (viewNo, seqNo) -> ((identifier, reqId), {senders}) self.prepares = Prepares() # type: Dict[Tuple[int, int], Tuple[Tuple[str, int], Set[str]]] self.commits = Commits() # type: Dict[Tuple[int, int], # Tuple[Tuple[str, int], Set[str]]] # Set of tuples to keep track of ordered requests. Each tuple is # (viewNo, ppSeqNo) self.ordered = OrderedSet() # type: OrderedSet[Tuple[int, int]] # Dictionary to keep track of the which replica was primary during each # view. Key is the view no and value is the name of the primary # replica during that view self.primaryNames = {} # type: Dict[int, str] # Holds msgs that are for later views self.threePhaseMsgsForLaterView = deque() # type: deque[(ThreePhaseMsg, str)] # Holds tuple of view no and prepare seq no of 3-phase messages it # received while it was not participating self.stashingWhileCatchingUp = set() # type: Set[Tuple] # Commits which are not being ordered since commits with lower view # numbers and sequence numbers have not been ordered yet. Key is the # viewNo and value a map of pre-prepare sequence number to commit self.stashedCommitsForOrdering = {} # type: Dict[int, # Dict[int, Commit]] self.checkpoints = SortedDict(lambda k: k[0]) self.stashingWhileOutsideWaterMarks = deque() # Low water mark self._h = 0 # type: int # High water mark self.H = self._h + self.config.LOG_SIZE # type: int self.lastPrePrepareSeqNo = self.h # type: int
def __init__(self, name: str, validators: List[str], inst_id: int, is_master: bool = True): self._name = name self.inst_id = inst_id self.view_no = 0 self.waiting_for_new_view = False self.primaries = [] self.is_master = is_master self.legacy_vc_in_progress = False self.requests = Requests() self.last_ordered_3pc = (0, 0) # Indicates name of the primary replica of this protocol instance. # None in case the replica does not know who the primary of the # instance is # TODO: Replace this by read-only property which uses primaries and inst_id self.primary_name = None # seqNoEnd of the last stabilized checkpoint self.stable_checkpoint = 0 # Checkpoint messages which the current node sent. # TODO: Replace sorted list with dict self.checkpoints = SortedListWithKey( key=lambda checkpoint: checkpoint.seqNoEnd) self.checkpoints.append(self.initial_checkpoint) # List of BatchIDs of PrePrepare messages for which quorum of Prepare messages is not reached yet self.preprepared = [] # type: List[BatchID] # List of BatchIDs of PrePrepare messages for which quorum of Prepare messages is reached self.prepared = [] # type: List[BatchID] self._validators = None self.quorums = None self.view_change_votes = ViewChangeVotesForView( Quorums(len(validators))) # a list of validator node names ordered by rank (historical order of adding) self.set_validators(validators) self.low_watermark = 0 self.log_size = getConfig().LOG_SIZE self.high_watermark = self.low_watermark + self.log_size self.pp_seq_no = 0 self.node_mode = Mode.starting # ToDo: it should be set in view_change_service before view_change starting # 3 phase key for the last prepared certificate before view change # started, applicable only to master instance self.legacy_last_prepared_before_view_change = None self.prev_view_prepare_cert = None # Dictionary of sent PRE-PREPARE that are stored by primary replica # which it has broadcasted to all other non primary replicas # Key of dictionary is a 2 element tuple with elements viewNo, # pre-prepare seqNo and value is the received PRE-PREPARE self.sent_preprepares = SortedDict(lambda k: (k[0], k[1])) # type: Dict[Tuple[int, int], PrePrepare] # Dictionary of all Prepare requests. Key of dictionary is a 2 # element tuple with elements viewNo, seqNo and value is a 2 element # tuple containing request digest and set of sender node names(sender # replica names in case of multiple protocol instances) # (viewNo, seqNo) -> ((identifier, reqId), {senders}) self.prepares = Prepares() # type: Dict[Tuple[int, int], Tuple[Tuple[str, int], Set[str]]] self.commits = Commits() # type: Dict[Tuple[int, int], Tuple[Tuple[str, int], Set[str]]] # Tracks for which keys PRE-PREPAREs have been requested. # Cleared in `gc` self.requested_pre_prepares = {}
def __init__(self, node: 'plenum.server.node.Node', instId: int, isMaster: bool = False): """ Create a new replica. :param node: Node on which this replica is located :param instId: the id of the protocol instance the replica belongs to :param isMaster: is this a replica of the master protocol instance """ super().__init__() self.stats = Stats(TPCStat) routerArgs = [(ReqDigest, self._preProcessReqDigest)] for r in [PrePrepare, Prepare, Commit]: routerArgs.append((r, self.processThreePhaseMsg)) self.inBoxRouter = Router(*routerArgs) self.threePhaseRouter = Router((PrePrepare, self.processPrePrepare), (Prepare, self.processPrepare), (Commit, self.processCommit)) self.node = node self.instId = instId self.name = self.generateName(node.name, self.instId) self.outBox = deque() """ This queue is used by the replica to send messages to its node. Replica puts messages that are consumed by its node """ self.inBox = deque() """ This queue is used by the replica to receive messages from its node. Node puts messages that are consumed by the replica """ self.inBoxStash = deque() """ If messages need to go back on the queue, they go here temporarily and are put back on the queue on a state change """ self.isMaster = isMaster # Indicates name of the primary replica of this protocol instance. # None in case the replica does not know who the primary of the # instance is self._primaryName = None # type: Optional[str] # Requests waiting to be processed once the replica is able to decide # whether it is primary or not self.postElectionMsgs = deque() # Requests that are stored by non primary replica for which it is # expecting corresponding pre prepare requests Dictionary that stores # a tuple of client id and request id(sequence no) as key and digest as # value. Not creating a set of Tuple3(identifier, reqId, digest) as such a # big hashable element is not good. Also this way we can look for the # request on the basis of (identifier, reqId) and compare the digest with # the received PrePrepare request's digest. self.reqsPendingPrePrepare = {} # type: Dict[Tuple[str, int], str] # PREPARE that are stored by non primary replica for which it has not # got any PRE-PREPARE. Dictionary that stores a tuple of view no and # prepare sequence number as key and a deque of PREPAREs as value. # This deque is attempted to be flushed on receiving every # PRE-PREPARE request. self.preparesWaitingForPrePrepare = {} # type: Dict[Tuple[int, int], deque] # Dictionary of sent PRE-PREPARE that are stored by primary replica # which it has broadcasted to all other non primary replicas # Key of dictionary is a 2 element tuple with elements viewNo, # pre-prepare seqNo and value is a Request Digest self.sentPrePrepares = {} # type: Dict[Tuple[int, int], Tuple[ReqDigest, float]] # Dictionary of received PRE-PREPAREs. Key of dictionary is a 2 # element tuple with elements viewNo, pre-prepare seqNo and value is # a Request Digest self.prePrepares = {} # type: Dict[Tuple[int, int], Tuple[ReqDigest, float]] self.prePrepareSeqNo = 0 # type: int # Dictionary of received Prepare requests. Key of dictionary is a 2 # element tuple with elements viewNo, seqNo and value is a 2 element # tuple containing request digest and set of sender node names(sender # replica names in case of multiple protocol instances) # (viewNo, seqNo) -> (digest, {senders}) self.prepares = Prepares() # type: Dict[Tuple[int, int], Tuple[str, Set[str]]] self.commits = Commits() # Set of tuples to keep track of ordered requests self.ordered = set() # type: Set[Tuple[int, int]] # Requests with sufficient commits so they can be ordered but have not # received request digest from node and neither PRE-PREPARE or PREPARE. # Key can be a digest to a tuple of viewNo and ppSeqNo self.commitsPendedForOrdering = {} # Dictionary to keep track of the which replica was primary during each # view. Key is the view no and value is the name of the primary # replica during that view self.primaryNames = {} # type: Dict[int, str] # Holds msgs that are for later views self.threePhaseMsgsForLaterView = deque() # type: deque[(ThreePhaseMsg, str)] # Holds tuple of view no and prepare seq no of 3-phase messages it # received while it was not participating self.stashingWhileCatchingUp = set() # type: Set[Tuple]