async def submit_batches(self, request):
        """Accepts a binary encoded BatchList and submits it to the validator.

        Request:
            body: octet-stream BatchList of one or more Batches
        Response:
            status:
                 - 202: Batches submitted and pending
            link: /batches or /batch_statuses link for submitted batches

        """
        timer_ctx = self._post_batches_total_time.time()
        self._post_batches_count.inc()

        # Parse request
        if request.headers['Content-Type'] != 'application/octet-stream':
            LOGGER.debug('Submission headers had wrong Content-Type: %s',
                         request.headers['Content-Type'])
            self._post_batches_error.inc()
            raise errors.SubmissionWrongContentType()

        body = await request.read()
        if not body:
            LOGGER.debug('Submission contained an empty body')
            self._post_batches_error.inc()
            raise errors.NoBatchesSubmitted()

        try:
            batch_list = BatchList()
            batch_list.ParseFromString(body)
        except DecodeError:
            LOGGER.debug('Submission body could not be decoded: %s', body)
            self._post_batches_error.inc()
            raise errors.BadProtobufSubmitted()

        # Query validator
        error_traps = [
            error_handlers.BatchInvalidTrap, error_handlers.BatchQueueFullTrap
        ]
        validator_query = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=batch_list.batches)

        with self._post_batches_validator_time.time():
            await self._query_validator(
                Message.CLIENT_BATCH_SUBMIT_REQUEST,
                client_batch_submit_pb2.ClientBatchSubmitResponse,
                validator_query, error_traps)

        # Build response envelope
        id_string = ','.join(b.header_signature for b in batch_list.batches)

        status = 202
        link = self._build_url(request, path='/batch_statuses', id=id_string)

        retval = self._wrap_response(request,
                                     metadata={'link': link},
                                     status=status)

        timer_ctx.stop()
        return retval
示例#2
0
    async def client_reader(self, request):
        """Fetches encrypted data from a specific address in the validator's state tree.
		    will forward read request to TP and return encrypted respond

        Request:
            query:
                - encrypted_request: request encrypted with one time key for specific address 
                  as define in private ledger crypto documentation

        Response:
            data: The data stored at that address, encrypted back with the one time key for requester
        """

        encrypted_request = request.match_info.get('encrypted_request', '')
        # convert back from url safe base64 encoding to regular base64 encoding
        try:
            enc_data_url = base64.urlsafe_b64decode(encrypted_request)
            encrypted_data = base64.b64encode(enc_data_url)
        except base64.binascii.Error:
            LOGGER.error('binascii.Error')
            raise errors.SubmissionWrongContentType()
        if (encrypted_data[-1] != b'\x00'):
            encrypted_data += b'\x00'

        try:
            # get the encrypted addres data from TP
            enc_res = await self._exchange_data_with_TP(encrypted_data)
        except Exception as e:
            LOGGER.error('exchange_data_with_TP exception')
            traceback.print_exc()
            raise errors.StatusResponseMissing()
        return self._wrap_response(request, data=enc_res, metadata=None)
    async def submit_batches(self, request):
        """Accepts a binary encoded BatchList and submits it to the validator.

        Request:
            body: octet-stream BatchList of one or more Batches
            query:
                - wait: Request should not return until all batches committed

        Response:
            status:
                 - 200: Batches submitted, but wait timed out before committed
                 - 201: All batches submitted and committed
                 - 202: Batches submitted and pending (not told to wait)
            data: Status of uncommitted batches (if any, when told to wait)
            link: /batches or /batch_status link for submitted batches

        """
        # Parse request
        if request.headers['Content-Type'] != 'application/octet-stream':
            raise errors.SubmissionWrongContentType()

        body = await request.read()
        if not body:
            raise errors.NoBatchesSubmitted()

        try:
            batch_list = BatchList()
            batch_list.ParseFromString(body)
        except DecodeError:
            raise errors.BadProtobufSubmitted()

        # Query validator
        error_traps = [error_handlers.BatchInvalidTrap]
        validator_query = client_pb2.ClientBatchSubmitRequest(
            batches=batch_list.batches)
        self._set_wait(request, validator_query)

        response = await self._query_validator(
            Message.CLIENT_BATCH_SUBMIT_REQUEST,
            client_pb2.ClientBatchSubmitResponse, validator_query, error_traps)

        # Build response envelope
        data = response['batch_statuses'] or None
        link = '{}://{}/batch_status?id={}'.format(
            request.scheme, request.host,
            ','.join(b.header_signature for b in batch_list.batches))

        if data is None:
            status = 202
        elif any(s != 'COMMITTED' for _, s in data.items()):
            status = 200
        else:
            status = 201
            data = None
            link = link.replace('batch_status', 'batches')

        return self._wrap_response(data=data,
                                   metadata={'link': link},
                                   status=status)
示例#4
0
    async def submit_batches(self, request):
        """Accepts a binary encoded BatchList and submits it to the validator.

        Request:
            body: octet-stream BatchList of one or more Batches
            query:
                - wait: Request should not return until all batches committed

        Response:
            status:
                 - 200: Batches submitted, but wait timed out before committed
                 - 201: All batches submitted and committed
                 - 202: Batches submitted and pending (not told to wait)
            data: Status of uncommitted batches (if any, when told to wait)
            link: /batches or /batch_status link for submitted batches

        """
        timer_ctx = self._post_batches_total_time.time()
        self._post_batches_count.inc()

        # Parse request
        if request.headers['Content-Type'] != 'application/octet-stream':
            LOGGER.debug('Submission headers had wrong Content-Type: %s',
                         request.headers['Content-Type'])
            self._post_batches_error.inc()
            raise errors.SubmissionWrongContentType()

        body = await request.read()
        if not body:
            LOGGER.debug('Submission contained an empty body')
            self._post_batches_error.inc()
            raise errors.NoBatchesSubmitted()

        try:
            batch_list = BatchList()
            batch_list.ParseFromString(body)
        except DecodeError:
            LOGGER.debug('Submission body could not be decoded: %s', body)
            self._post_batches_error.inc()
            raise errors.BadProtobufSubmitted()

        # Query validator
        error_traps = [error_handlers.BatchInvalidTrap]
        validator_query = client_pb2.ClientBatchSubmitRequest(
            batches=batch_list.batches)
        self._set_wait(request, validator_query)

        with self._post_batches_validator_time.time():
            response = await self._query_validator(
                Message.CLIENT_BATCH_SUBMIT_REQUEST,
                client_pb2.ClientBatchSubmitResponse, validator_query,
                error_traps)

        # Build response envelope
        data = self._drop_id_prefixes(
            self._drop_empty_props(response['batch_statuses'])) or None
        id_string = ','.join(b.header_signature for b in batch_list.batches)

        if data is None or any(d['status'] != 'COMMITTED' for d in data):
            status = 202
            link = self._build_url(request, path='/batch_status', id=id_string)
        else:
            status = 201
            data = None
            link = self._build_url(request, wait=False, id=id_string)

        retval = self._wrap_response(request,
                                     data=data,
                                     metadata={'link': link},
                                     status=status)

        timer_ctx.stop()
        return retval