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
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)
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)
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'})
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'})
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
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