Beispiel #1
0
    def canProcessPrePrepare(self, pp: PrePrepare, sender: str) -> bool:
        """
        Decide whether this replica is eligible to process a PRE-PREPARE,
        based on the following criteria:

        - this replica is non-primary replica
        - the request isn't in its list of received PRE-PREPAREs
        - the request is waiting to for PRE-PREPARE and the digest value matches

        :param pp: a PRE-PREPARE msg to process
        :param sender: the name of the node that sent the PRE-PREPARE msg
        :return: True if processing is allowed, False otherwise
        """
        # TODO: Check whether it is rejecting PRE-PREPARE from previous view
        # PRE-PREPARE should not be sent from non primary
        if not self.isMsgFromPrimary(pp, sender):
            raise SuspiciousNode(sender, Suspicions.PPR_FRM_NON_PRIMARY, pp)

        # A PRE-PREPARE is being sent to primary
        if self.isPrimaryForMsg(pp) is True:
            raise SuspiciousNode(sender, Suspicions.PPR_TO_PRIMARY, pp)

        # A PRE-PREPARE is sent that has already been received
        if (pp.viewNo, pp.ppSeqNo) in self.prePrepares:
            raise SuspiciousNode(sender, Suspicions.DUPLICATE_PPR_SENT, pp)

        key = (pp.identifier, pp.reqId)

        # A PRE-PREPARE is sent that does not match request digest
        if (key in self.reqsPendingPrePrepare
                and self.reqsPendingPrePrepare[key] != pp.digest):
            raise SuspiciousNode(sender, Suspicions.PPR_DIGEST_WRONG, pp)

        return True
Beispiel #2
0
    def isValidCommit(self, commit: Commit, sender: str) -> bool:
        """
        Return whether the COMMIT specified is valid.

        :param commit: the COMMIT to validate
        :return: True if `request` is valid, False otherwise
        """
        primaryStatus = self.isPrimaryForMsg(commit)
        ppReqs = self.sentPrePrepares if primaryStatus else self.prePrepares
        key = (commit.viewNo, commit.ppSeqNo)
        if key not in ppReqs:
            self.enqueueCommit(commit, sender)
            return False

        if (key not in self.prepares
                and key not in self.preparesWaitingForPrePrepare):
            logger.debug(
                "{} rejecting COMMIT{} due to lack of prepares".format(
                    self, key))
            # raise SuspiciousNode(sender, Suspicions.UNKNOWN_CM_SENT, commit)
            return False
        elif self.commits.hasCommitFrom(commit, sender):
            raise SuspiciousNode(sender, Suspicions.DUPLICATE_CM_SENT, commit)
        elif commit.digest != self.getDigestFor3PhaseKey(ThreePhaseKey(*key)):
            raise SuspiciousNode(sender, Suspicions.CM_DIGEST_WRONG, commit)
        elif key in ppReqs and commit.ppTime != ppReqs[key][1]:
            raise SuspiciousNode(sender, Suspicions.CM_TIME_WRONG, commit)
        else:
            return True
Beispiel #3
0
def test_process_pre_prepare_with_incorrect_audit_txn_root(orderer_with_requests,
                                                           state_roots, txn_roots, multi_sig, fake_requests):
    if not orderer_with_requests.is_master:
        return
    handler = Mock()
    orderer_with_requests._bus.subscribe(RaisedSuspicion, handler)
    pre_prepare_params = create_pre_prepare_params(state_root=state_roots[DOMAIN_LEDGER_ID],
                                                   ledger_id=DOMAIN_LEDGER_ID,
                                                   txn_root=txn_roots[DOMAIN_LEDGER_ID],
                                                   bls_multi_sig=multi_sig,
                                                   view_no=orderer_with_requests.view_no,
                                                   inst_id=0,
                                                   pool_state_root=state_roots[POOL_LEDGER_ID],
                                                   # INVALID!
                                                   audit_txn_root="HSai3sMHKeAva4gWMabDrm1yNhezvPHfXnGyHf2ex1L4",
                                                   reqs=fake_requests,
                                                   pp_seq_no=1)
    pre_prepare = PrePrepare(*pre_prepare_params)
    _register_pp_ts(orderer_with_requests, pre_prepare, orderer_with_requests.primary_name)

    orderer_with_requests.process_preprepare(pre_prepare, orderer_with_requests.primary_name)
    check_suspicious(handler, RaisedSuspicion(inst_id=orderer_with_requests._data.inst_id,
                                              ex=SuspiciousNode(orderer_with_requests.primary_name,
                                                                Suspicions.PPR_AUDIT_TXN_ROOT_HASH_WRONG,
                                                                pre_prepare)))
Beispiel #4
0
def test_suspicious_on_wrong_list_of_primaries(orderer_with_requests,
                                               state_roots, txn_roots, multi_sig, fake_requests):
    if not orderer_with_requests.is_master:
        return
    handler = Mock()
    orderer_with_requests._bus.subscribe(RaisedSuspicion, handler)
    pre_prepare_params = create_pre_prepare_params(state_root=state_roots[DOMAIN_LEDGER_ID],
                                                   ledger_id=DOMAIN_LEDGER_ID,
                                                   txn_root=txn_roots[DOMAIN_LEDGER_ID],
                                                   bls_multi_sig=multi_sig,
                                                   view_no=orderer_with_requests.view_no,
                                                   inst_id=0,
                                                   pool_state_root=state_roots[POOL_LEDGER_ID],
                                                   audit_txn_root=state_roots[AUDIT_LEDGER_ID],
                                                   reqs=fake_requests,
                                                   pp_seq_no=1,
                                                   primaries=["Some", "Other", "Primaries"])
    pre_prepare = PrePrepare(*pre_prepare_params)
    _register_pp_ts(orderer_with_requests, pre_prepare, orderer_with_requests.primary_name)

    orderer_with_requests.process_preprepare(pre_prepare, orderer_with_requests.primary_name)
    check_suspicious(handler, RaisedSuspicion(inst_id=orderer_with_requests._data.inst_id,
                                              ex=SuspiciousNode(orderer_with_requests.primary_name,
                                                                Suspicions.PPR_WITH_WRONG_PRIMARIES,
                                                                pre_prepare)))
def test_validate_prepare_from_primary(o, prepare):
    handler = Mock()
    o._bus.subscribe(RaisedSuspicion, handler)
    o._validate_prepare(prepare, PRIMARY_NAME)
    check_suspicious(
        handler,
        RaisedSuspicion(inst_id=o._data.inst_id,
                        ex=SuspiciousNode(PRIMARY_NAME,
                                          Suspicions.PR_FRM_PRIMARY, prepare)))
Beispiel #6
0
    def isValidPrepare(self, prepare: Prepare, sender: str) -> bool:
        """
        Return whether the PREPARE specified is valid.

        :param prepare: the PREPARE to validate
        :param sender: the name of the node that sent the PREPARE
        :return: True if PREPARE is valid, False otherwise
        """
        key = (prepare.viewNo, prepare.ppSeqNo)
        primaryStatus = self.isPrimaryForMsg(prepare)

        ppReqs = self.sentPrePrepares if primaryStatus else self.prePrepares

        # If a non primary replica and receiving a PREPARE request before a
        # PRE-PREPARE request, then proceed

        # PREPARE should not be sent from primary
        if self.isMsgFromPrimary(prepare, sender):
            raise SuspiciousNode(sender, Suspicions.PR_FRM_PRIMARY, prepare)

        # If non primary replica
        if primaryStatus is False:
            if self.prepares.hasPrepareFrom(prepare, sender):
                raise SuspiciousNode(sender, Suspicions.DUPLICATE_PR_SENT,
                                     prepare)
            # If PRE-PREPARE not received for the PREPARE, might be slow network
            if key not in ppReqs:
                self.enqueuePrepare(prepare, sender)
                return False
            elif prepare.digest != self.requests.digest(ppReqs[key][0]):
                raise SuspiciousNode(sender, Suspicions.PR_DIGEST_WRONG,
                                     prepare)
            elif prepare.ppTime != ppReqs[key][1]:
                raise SuspiciousNode(sender, Suspicions.PR_TIME_WRONG, prepare)
            else:
                return True
        # If primary replica
        else:
            if self.prepares.hasPrepareFrom(prepare, sender):
                raise SuspiciousNode(sender, Suspicions.DUPLICATE_PR_SENT,
                                     prepare)
            # If PRE-PREPARE was not sent for this PREPARE, certainly
            # malicious behavior
            elif key not in ppReqs:
                raise SuspiciousNode(sender, Suspicions.UNKNOWN_PR_SENT,
                                     prepare)
            elif prepare.digest != self.requests.digest(ppReqs[key][0]):
                raise SuspiciousNode(sender, Suspicions.PR_DIGEST_WRONG,
                                     prepare)
            elif prepare.ppTime != ppReqs[key][1]:
                raise SuspiciousNode(sender, Suspicions.PR_TIME_WRONG, prepare)
            else:
                return True
def test_validate_prepare_wrong_state_root(o, pre_prepare, prepare):
    handler = Mock()
    o._bus.subscribe(RaisedSuspicion, handler)
    o.process_preprepare(pre_prepare, PRIMARY_NAME)
    prepare = updateNamedTuple(prepare, stateRootHash=generate_state_root())
    o._validate_prepare(prepare, NON_PRIMARY_NAME)
    check_suspicious(
        handler,
        RaisedSuspicion(inst_id=o._data.inst_id,
                        ex=SuspiciousNode(NON_PRIMARY_NAME,
                                          Suspicions.PR_STATE_WRONG, prepare)))
def test_validate_prepare_wrong_digest(o, pre_prepare, prepare):
    handler = Mock()
    o._bus.subscribe(RaisedSuspicion, handler)
    o.process_preprepare(pre_prepare, PRIMARY_NAME)
    prepare = updateNamedTuple(prepare, digest='fake_digest')
    o._validate_prepare(prepare, NON_PRIMARY_NAME)
    check_suspicious(
        handler,
        RaisedSuspicion(inst_id=o._data.inst_id,
                        ex=SuspiciousNode(NON_PRIMARY_NAME,
                                          Suspicions.PR_DIGEST_WRONG,
                                          prepare)))
def test_validate_duplicate_prepare(o, pre_prepare, prepare):
    handler = Mock()
    o._bus.subscribe(RaisedSuspicion, handler)
    o.process_preprepare(pre_prepare, PRIMARY_NAME)
    o.process_prepare(prepare, NON_PRIMARY_NAME)
    o._validate_prepare(prepare, NON_PRIMARY_NAME)
    check_suspicious(
        handler,
        RaisedSuspicion(inst_id=o._data.inst_id,
                        ex=SuspiciousNode(NON_PRIMARY_NAME,
                                          Suspicions.DUPLICATE_PR_SENT,
                                          prepare)))
Beispiel #10
0
    def isValidCommit(self, commit: Commit, sender: str):
        """
        Return whether the COMMIT specified is valid.

        :param commit: the COMMIT to validate
        :return: True if `request` is valid, False otherwise
        """
        primaryStatus = self.isPrimaryForMsg(commit)
        ppReqs = self.sentPrePrepares if primaryStatus else self.prePrepares
        key = (commit.viewNo, commit.ppSeqNo)
        if (key not in self.prepares
                and key not in self.preparesWaitingForPrePrepare):
            raise SuspiciousNode(sender, Suspicions.UNKNOWN_CM_SENT, commit)
        elif self.commits.hasCommitFrom(commit, sender):
            raise SuspiciousNode(sender, Suspicions.DUPLICATE_CM_SENT, commit)
        elif commit.digest != self.getDigestFromPrepare(*key):
            raise SuspiciousNode(sender, Suspicions.CM_DIGEST_WRONG, commit)
        elif key in ppReqs and commit.ppTime != ppReqs[key][1]:
            raise SuspiciousNode(sender, Suspicions.CM_TIME_WRONG, commit)
        else:
            return True
Beispiel #11
0
    def canProcessPrePrepare(self, pp: PrePrepare, sender: str):
        """
        Decide whether this replica is eligible to process a PRE-PREPARE,
        based on the following criteria:

        - this replica is non-primary replica
        - the request isn't in its list of received PRE-PREPAREs
        - the request is waiting to for PRE-PREPARE and the digest value matches

        :param pp: a PRE-PREPARE msg to process
        :param sender: the name of the node that sent the PRE-PREPARE msg
        :return: True if processing is allowed, False otherwise
        """
        # PRE-PREPARE should not be sent from non primary
        if not self.isMsgFromPrimary(pp, sender):
            raise SuspiciousNode(sender, Suspicions.PPR_FRM_NON_PRIMARY, pp)

        # A PRE-PREPARE is being sent to primary
        if self.isPrimaryForMsg(pp) is True:
            raise SuspiciousNode(sender, Suspicions.PPR_TO_PRIMARY, pp)

        if (pp.viewNo, pp.ppSeqNo) in self.prePrepares:
            raise SuspiciousNode(sender, Suspicions.DUPLICATE_PPR_SENT, pp)

        #TODO: Fix this, how to check last preprepare seq num
        # if self.prePrepares:
        #     lastProcessedPrePrepareSeqNo = max([key[1] for key in self.prePrepares.keys()])
        #     if pp.ppSeqNo > lastProcessedPrePrepareSeqNo + 1:
        #         raise SuspiciousNode(sender, Suspicions.WRONG_PPSEQ_NO, pp)

        key = (pp.identifier, pp.reqId)

        if (key in self.reqsPendingPrePrepare
                and self.reqsPendingPrePrepare[key] != pp.digest):
            raise SuspiciousNode(sender, Suspicions.PPR_DIGEST_WRONG, pp)

        return True
def test_validate_prepare_no_preprepare(o, prepare):
    # must sent PrePrepare before processing the Prepare
    if o.name == PRIMARY_NAME:
        handler = Mock()
        o._bus.subscribe(RaisedSuspicion, handler)
        o._validate_prepare(prepare, NON_PRIMARY_NAME)
        check_suspicious(
            handler,
            RaisedSuspicion(inst_id=o._data.inst_id,
                            ex=SuspiciousNode(NON_PRIMARY_NAME,
                                              Suspicions.UNKNOWN_PR_SENT,
                                              prepare)))
    # PrePrepare can be delayed, so just enqueue
    else:
        o._validate_prepare(prepare, NON_PRIMARY_NAME)
        assert (prepare, NON_PRIMARY_NAME
                ) in o.preparesWaitingForPrePrepare[prepare.viewNo,
                                                    prepare.ppSeqNo]
Beispiel #13
0
def test_process_pre_prepare_with_ordered_request(orderer, pre_prepare):
    handler = Mock()
    orderer._bus.subscribe(RaisedSuspicion, handler)

    orderer.db_manager.stores[SEQ_NO_DB_LABEL] = FakeSomething(get_by_full_digest=lambda req: 'sample',
                                                               get_by_payload_digest=lambda req: (1, 1))
    orderer._non_finalised_reqs = lambda a: pre_prepare.reqIdr

    def request_propagates(reqs):
        assert False, "Requested propagates for: {}".format(reqs)

    orderer._bus.subscribe(RequestPropagates, request_propagates)

    orderer.process_preprepare(pre_prepare, orderer.primary_name)
    check_suspicious(handler, RaisedSuspicion(inst_id=orderer._data.inst_id,
                                              ex=SuspiciousNode(orderer.primary_name,
                                                                Suspicions.PPR_WITH_ORDERED_REQUEST,
                                                                pre_prepare)))
Beispiel #14
0
def malicious_behaviors(suspicion_code, node_name):
    if suspicion_code == Suspicions.PPR_STATE_WRONG:
        raise SuspiciousNode(node_name,
                             suspicion_code,
                             "It looks like ViewChange should be forced "
                             "because Pre-Prepare message has incorrect state trie root")