def verifyMerkleProof(*replies: Tuple[Reply]) -> bool: """ Verifies the correctness of the merkle proof provided in the reply from the node. Returns True if verified to be correct, throws an exception otherwise. :param replies: One or more replies for which Merkle Proofs have to be verified :raises ProofError: The proof is invalid :return: True """ verifier = MerkleVerifier() serializer = ledger_txn_serializer ignored = {F.auditPath.name, F.seqNo.name, F.rootHash.name} for r in replies: seqNo = r[f.RESULT.nm][F.seqNo.name] rootHash = Ledger.strToHash( r[f.RESULT.nm][F.rootHash.name]) auditPath = [Ledger.strToHash(a) for a in r[f.RESULT.nm][F.auditPath.name]] filtered = dict((k, v) for (k, v) in r[f.RESULT.nm].items() if k not in ignored) result = serializer.serialize(filtered) verifier.verify_leaf_inclusion(result, seqNo - 1, auditPath, STH(tree_size=seqNo, sha256_root_hash=rootHash)) return True
def _has_valid_catchup_replies( self, seq_no: int, txns_to_process: List[Tuple[int, Any]]) -> Tuple[bool, str, int]: """ Transforms transactions for ledger! Returns: Whether catchup reply corresponding to seq_no Name of node from which txns came Number of transactions ready to be processed """ # TODO: Remove after stop passing seqNo here assert seq_no == txns_to_process[0][0] # Here seqNo has to be the seqNo of first transaction of # `catchupReplies` # Get the transactions in the catchup reply which has sequence # number `seqNo` node_name, catchup_rep = self._find_catchup_reply_for_seq_no(seq_no) txns = catchup_rep.txns # Add only those transaction in the temporary tree from the above # batch which are not present in the ledger # Integer keys being converted to strings when marshaled to JSON txns = [ self._provider.transform_txn_for_ledger(txn) for s, txn in txns_to_process[:len(txns)] if str(s) in txns ] # Creating a temporary tree which will be used to verify consistency # proof, by inserting transactions. Duplicating a merkle tree is not # expensive since we are using a compact merkle tree. temp_tree = self._ledger.treeWithAppliedTxns(txns) proof = catchup_rep.consProof final_size = self._catchup_till.seqNoEnd final_hash = self._catchup_till.newMerkleRoot try: logger.info("{} verifying proof for {}, {}, {}, {}, {}".format( self, temp_tree.tree_size, final_size, temp_tree.root_hash, Ledger.strToHash(final_hash), [Ledger.strToHash(p) for p in proof])) verified = self._provider.verifier( self._ledger_id).verify_tree_consistency( temp_tree.tree_size, final_size, temp_tree.root_hash, Ledger.strToHash(final_hash), [Ledger.strToHash(p) for p in proof]) except Exception as ex: logger.info("{} could not verify catchup reply {} since {}".format( self, catchup_rep, ex)) verified = False return bool(verified), node_name, len(txns)
def from_ordered(ordered): return ThreePcBatch(ledger_id=ordered.ledgerId, inst_id=ordered.instId, view_no=ordered.viewNo, pp_seq_no=ordered.ppSeqNo, pp_time=ordered.ppTime, valid_txn_count=len(ordered.valid_reqIdr), state_root=Ledger.strToHash(ordered.stateRootHash), txn_root=Ledger.strToHash(ordered.txnRootHash), has_audit_txn=f.AUDIT_TXN_ROOT_HASH.nm in ordered and ordered.auditTxnRootHash is not None)
def from_ordered(ordered): return ThreePcBatch(ledger_id=ordered.ledgerId, inst_id=ordered.instId, view_no=ordered.viewNo, pp_seq_no=ordered.ppSeqNo, pp_time=ordered.ppTime, state_root=Ledger.strToHash(ordered.stateRootHash), txn_root=Ledger.strToHash(ordered.txnRootHash), primaries=ordered.primaries, valid_digests=ordered.valid_reqIdr, has_audit_txn=f.AUDIT_TXN_ROOT_HASH.nm in ordered and ordered.auditTxnRootHash is not None, original_view_no=ordered.originalViewNo)
def from_batch_committed_dict(batch_comitted): return ThreePcBatch( ledger_id=batch_comitted[f.LEDGER_ID.nm], inst_id=batch_comitted[f.INST_ID.nm], view_no=batch_comitted[f.VIEW_NO.nm], pp_seq_no=batch_comitted[f.PP_SEQ_NO.nm], pp_time=batch_comitted[f.PP_TIME.nm], valid_txn_count=batch_comitted[f.SEQ_NO_END.nm] - batch_comitted[f.SEQ_NO_START.nm] + 1, state_root=Ledger.strToHash(batch_comitted[f.STATE_ROOT.nm]), txn_root=Ledger.strToHash(batch_comitted[f.TXN_ROOT.nm]), has_audit_txn=f.AUDIT_TXN_ROOT_HASH.nm in batch_comitted and batch_comitted[f.AUDIT_TXN_ROOT_HASH.nm] is not None)
def from_batch_committed_dict(batch_comitted): valid_req_keys = [ Request(**req_dict).key for req_dict in batch_comitted[f.REQUESTS.nm] ] return ThreePcBatch( ledger_id=batch_comitted[f.LEDGER_ID.nm], inst_id=batch_comitted[f.INST_ID.nm], view_no=batch_comitted[f.VIEW_NO.nm], pp_seq_no=batch_comitted[f.PP_SEQ_NO.nm], pp_time=batch_comitted[f.PP_TIME.nm], state_root=Ledger.strToHash(batch_comitted[f.STATE_ROOT.nm]), txn_root=Ledger.strToHash(batch_comitted[f.TXN_ROOT.nm]), primaries=batch_comitted[f.PRIMARIES.nm], valid_digests=valid_req_keys, has_audit_txn=f.AUDIT_TXN_ROOT_HASH.nm in batch_comitted and batch_comitted[f.AUDIT_TXN_ROOT_HASH.nm] is not None)
def hasValidCatchupReplies(self, ledgerId, ledger, seqNo, catchUpReplies): # Here seqNo has to be the seqNo of first transaction of # `catchupReplies` # Get the batch of transactions in the catchup reply which has sequence # number `seqNo` nodeName, catchupReply = self._getCatchupReplyForSeqNo(ledgerId, seqNo) txns = getattr(catchupReply, f.TXNS.nm) # Add only those transaction in the temporary tree from the above # batch # Integer keys being converted to strings when marshaled to JSON txns = [ self._transform(txn) for s, txn in catchUpReplies[:len(txns)] if str(s) in txns ] # Creating a temporary tree which will be used to verify consistency # proof, by inserting transactions. Duplicating a merkle tree is not # expensive since we are using a compact merkle tree. tempTree = ledger.treeWithAppliedTxns(txns) proof = getattr(catchupReply, f.CONS_PROOF.nm) ledgerInfo = self.getLedgerInfoByType(ledgerId) verifier = ledgerInfo.verifier cp = ledgerInfo.catchUpTill finalSize = getattr(cp, f.SEQ_NO_END.nm) finalMTH = getattr(cp, f.NEW_MERKLE_ROOT.nm) try: logger.debug("{} verifying proof for {}, {}, {}, {}, {}".format( self, tempTree.tree_size, finalSize, tempTree.root_hash, Ledger.strToHash(finalMTH), [Ledger.strToHash(p) for p in proof])) verified = verifier.verify_tree_consistency( tempTree.tree_size, finalSize, tempTree.root_hash, Ledger.strToHash(finalMTH), [Ledger.strToHash(p) for p in proof]) except Exception as ex: logger.info("{} could not verify catchup reply {} since {}".format( self, catchupReply, ex)) verified = False return bool(verified), nodeName, len(txns)