<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def executeBatch(self, three_pc_batch: ThreePcBatch, valid_reqs_keys: List, invalid_reqs_keys: List, audit_txn_root) -> None: """ Execute the REQUEST sent to this Node :param view_no: the view number (See glossary) :param pp_time: the time at which PRE-PREPARE was sent :param valid_reqs: list of valid client requests keys :param valid_reqs: list of invalid client requests keys """


        # We need hashes in apply and str in commit
        three_pc_batch.txn_root = Ledger.hashToStr(three_pc_batch.txn_root)
        three_pc_batch.state_root = Ledger.hashToStr(three_pc_batch.state_root)

        for req_key in valid_reqs_keys:
            self.execute_hook(NodeHooks.PRE_REQUEST_COMMIT, req_key=req_key,
                              pp_time=three_pc_batch.pp_time,
                              state_root=three_pc_batch.state_root,
                              txn_root=three_pc_batch.txn_root)

        self.execute_hook(NodeHooks.PRE_BATCH_COMMITTED,
                          ledger_id=three_pc_batch.ledger_id,
                          pp_time=three_pc_batch.pp_time,
                          reqs_keys=valid_reqs_keys,
                          state_root=three_pc_batch.state_root,
                          txn_root=three_pc_batch.txn_root)

        try:
            committedTxns = self.get_executer(three_pc_batch.ledger_id)(three_pc_batch)
        except Exception as exc:
            logger.error(
                "{} commit failed for batch request, error {}, view no {}, "
                "ppSeqNo {}, ledger {}, state root {}, txn root {}, "
                "requests: {}".format(
                    self, repr(exc), three_pc_batch.view_no, three_pc_batch.pp_seq_no,
                    three_pc_batch.ledger_id, three_pc_batch.state_root,
                    three_pc_batch.txn_root, [req_idr for req_idr in valid_reqs_keys]
                )
            )
            raise

        for req_key in valid_reqs_keys + invalid_reqs_keys:
            if req_key in self.requests:
                self.mark_request_as_executed(self.requests[req_key].request)
            else:
                # Means that this request is dropped from the main requests queue due to timeout,
                # but anyway it is ordered and executed normally
                logger.debug('{} normally executed request {} which object has been dropped '
                             'from the requests queue'.format(self, req_key))
                pass

        # TODO is it possible to get len(committedTxns) != len(valid_reqs)
        # someday
        if not committedTxns:
            return

        logger.debug("{} committed batch request, view no {}, ppSeqNo {}, "
                     "ledger {}, state root {}, txn root {}, requests: {}".
                     format(self, three_pc_batch.view_no, three_pc_batch.pp_seq_no,
                            three_pc_batch.ledger_id, three_pc_batch.state_root,
                            three_pc_batch.txn_root, [key for key in valid_reqs_keys]))

        for txn in committedTxns:
            self.execute_hook(NodeHooks.POST_REQUEST_COMMIT, txn=txn,
                              pp_time=three_pc_batch.pp_time, state_root=three_pc_batch.state_root,
                              txn_root=three_pc_batch.txn_root)

        first_txn_seq_no = get_seq_no(committedTxns[0])
        last_txn_seq_no = get_seq_no(committedTxns[-1])

        reqs = []
        reqs_list_built = True
        for req_key in valid_reqs_keys:
            if req_key in self.requests:
                reqs.append(self.requests[req_key].request.as_dict)
            else:
                logger.warning("Could not build requests list for observers due to non-existent requests")
                reqs_list_built = False
                break

        if reqs_list_built:
            batch_committed_msg = BatchCommitted(reqs,
                                                 three_pc_batch.ledger_id,
                                                 0,
                                                 three_pc_batch.view_no,
                                                 three_pc_batch.pp_seq_no,
                                                 three_pc_batch.pp_time,
                                                 three_pc_batch.state_root,
                                                 three_pc_batch.txn_root,
                                                 first_txn_seq_no,
                                                 last_txn_seq_no,
                                                 audit_txn_root,
                                                 three_pc_batch.primaries)
            self._observable.append_input(batch_committed_msg, self.name)