Ejemplo n.º 1
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
        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
Ejemplo n.º 2
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

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

        payload = await request.read()
        if not payload:
            return errors.EmptyProtobuf()

        try:
            batch_list = BatchList()
            batch_list.ParseFromString(payload)
        except DecodeError:
            return errors.BadProtobuf()

        # Query validator
        error_traps = [error_handlers.InvalidBatch()]
        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)
Ejemplo n.º 3
0
    def batches_post(self, request):
        """
        Takes protobuf binary from HTTP POST, and sends it to the validator
        """
        # Parse request
        if request.headers['Content-Type'] != 'application/octet-stream':
            return errors.WrongBodyType()

        payload = yield from request.read()
        if not payload:
            return errors.EmptyProtobuf()

        try:
            batch_list = BatchList()
            batch_list.ParseFromString(payload)
        except DecodeError:
            return errors.BadProtobuf()

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

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

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

        if not data:
            status = 202
            data = None
        elif any(s != 'COMMITTED' for _, s in data.items()):
            status = 200
        else:
            status = 201
            data = None
            # Replace with /batches link when implemented
            metadata = None

        return RouteHandler._wrap_response(data=data,
                                           metadata=metadata,
                                           status=status)
Ejemplo n.º 4
0
    async def post_batches(self, batches):
        """POSTs batches to '/batches' with an optional wait parameter
        """
        batch_bytes = BatchList(batches=batches).SerializeToString()

        return await self.client.post(
            '/batches',
            data=batch_bytes,
            headers={'content-type': 'application/octet-stream'})
Ejemplo n.º 5
0
    async def post_batches(self, batches, wait=False):
        """POSTs batches to '/batches' with an optional wait parameter
        """
        batch_bytes = BatchList(batches=batches).SerializeToString()
        query_string = '?wait' if wait else ''
        wait_val = '=' + str(wait) if type(wait) == int else ''

        return await self.client.post(
            '/batches' + query_string + wait_val,
            data=batch_bytes,
            headers={'content-type': 'application/octet-stream'})
Ejemplo n.º 6
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
Ejemplo n.º 7
0
def setup_batch(request):
    """Setup method for posting batches and returning the 
       response
    """
    data = {}
    signer = get_signer()
    expected_trxn_ids = []
    expected_batch_ids = []
    initial_state_length = len(get_state_list())

    LOGGER.info("Creating intkey transactions with set operations")

    txns = [
        create_intkey_transaction("set", 'a', 0, [], signer),
    ]

    for txn in txns:
        data = MessageToDict(txn,
                             including_default_value_fields=True,
                             preserving_proto_field_name=True)

        trxn_id = data['header_signature']
        expected_trxn_ids.append(trxn_id)

    data['expected_trxn_ids'] = expected_trxn_ids

    LOGGER.info("Creating batches for transactions 1trn/batch")

    batches = [create_batch([txn], signer) for txn in txns]

    for batch in batches:
        data = MessageToDict(batch,
                             including_default_value_fields=True,
                             preserving_proto_field_name=True)

        batch_id = data['header_signature']
        expected_batch_ids.append(batch_id)

    data['expected_batch_ids'] = expected_batch_ids
    data['signer_key'] = signer.get_public_key().as_hex()

    post_batch_list = [
        BatchList(batches=[batch]).SerializeToString() for batch in batches
    ]

    LOGGER.info("Submitting batches to the handlers")

    for batch in post_batch_list:
        try:
            response = post_batch(batch)
        except urllib.error.HTTPError as error:
            LOGGER.info("Rest Api is not reachable")
            data = json.loads(error.fp.read().decode('utf-8'))
            LOGGER.info(data['error']['title'])
            LOGGER.info(data['error']['message'])

    block_list = get_blocks()
    data['block_list'] = block_list
    block_ids = [block['header_signature'] for block in block_list]
    data['block_ids'] = block_ids
    batch_ids = [block['header']['batch_ids'][0] for block in block_list]
    data['batch_ids'] = batch_ids
    expected_head_id = block_ids[0]
    data['expected_head_id'] = expected_head_id
    yield data