github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/cli/sawtooth_cli/batch.py (about)

     1  # Copyright 2017 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the 'License');
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  # ------------------------------------------------------------------------------
    15  
    16  import argparse
    17  import time
    18  
    19  from sys import maxsize
    20  
    21  from sawtooth_cli import format_utils as fmt
    22  from sawtooth_cli.rest_client import RestClient
    23  from sawtooth_cli.exceptions import CliException
    24  from sawtooth_cli.parent_parsers import base_http_parser
    25  from sawtooth_cli.parent_parsers import base_list_parser
    26  from sawtooth_cli.parent_parsers import base_show_parser
    27  import sawtooth_cli.protobuf.batch_pb2 as batch_pb2
    28  
    29  
    30  def add_batch_parser(subparsers, parent_parser):
    31      """Adds arguments parsers for the batch list, batch show and batch status
    32      commands
    33  
    34          Args:
    35              subparsers: Add parsers to this subparser object
    36              parent_parser: The parent argparse.ArgumentParser object
    37      """
    38      parser = subparsers.add_parser(
    39          'batch',
    40          help='Displays information about batches and submit new batches',
    41          description='Provides subcommands to display Batch information and '
    42          'submit Batches to the validator via the REST API.')
    43  
    44      grand_parsers = parser.add_subparsers(title='subcommands',
    45                                            dest='subcommand')
    46      grand_parsers.required = True
    47      add_batch_list_parser(grand_parsers, parent_parser)
    48      add_batch_show_parser(grand_parsers, parent_parser)
    49      add_batch_status_parser(grand_parsers, parent_parser)
    50      add_batch_submit_parser(grand_parsers, parent_parser)
    51  
    52  
    53  def add_batch_list_parser(subparsers, parent_parser):
    54      description = (
    55          'Displays all information about all committed Batches for '
    56          'the specified validator, including the Batch id, public keys of all '
    57          'signers, and number of transactions in each Batch.')
    58  
    59      subparsers.add_parser(
    60          'list',
    61          description=description,
    62          parents=[base_http_parser(), base_list_parser()],
    63          formatter_class=argparse.RawDescriptionHelpFormatter)
    64  
    65  
    66  def add_batch_show_parser(subparsers, parent_parser):
    67      show_parser = subparsers.add_parser(
    68          'show',
    69          description='Displays information for the specified Batch.',
    70          parents=[base_http_parser(), base_show_parser()],
    71          formatter_class=argparse.RawDescriptionHelpFormatter)
    72  
    73      show_parser.add_argument(
    74          'batch_id',
    75          type=str,
    76          help='id (header_signature) of the batch')
    77  
    78  
    79  def add_batch_status_parser(subparsers, parent_parser):
    80      status_parser = subparsers.add_parser(
    81          'status',
    82          description='Displays the status of the specified Batch id or ids.',
    83          parents=[base_http_parser()])
    84  
    85      status_parser.add_argument(
    86          '--wait',
    87          nargs='?',
    88          const=maxsize,
    89          type=int,
    90          help='set time, in seconds, to wait for commit')
    91  
    92      status_parser.add_argument(
    93          'batch_ids',
    94          type=str,
    95          help='single batch id or comma-separated list of batch ids')
    96  
    97      status_parser.add_argument(
    98          '-F', '--format',
    99          action='store',
   100          default='yaml',
   101          choices=['yaml', 'json'],
   102          help='choose the output format (default: yaml)')
   103  
   104  
   105  def add_batch_submit_parser(subparsers, parent_parser):
   106      submit_parser = subparsers.add_parser(
   107          'submit',
   108          description='Sends Batches to the REST API to be submitted to the '
   109          'validator. The input must be a binary file containing a '
   110          'binary-encoded BatchList of one or more batches with any number '
   111          'of transactions.',
   112          parents=[base_http_parser(), parent_parser])
   113  
   114      submit_parser.add_argument(
   115          '--wait',
   116          nargs='?',
   117          const=maxsize,
   118          type=int,
   119          help='set time, in seconds, to wait for batches to commit')
   120  
   121      submit_parser.add_argument(
   122          '-f', '--filename',
   123          type=str,
   124          help='specify location of input file',
   125          default='batches.intkey')
   126  
   127      submit_parser.add_argument(
   128          '--batch-size-limit',
   129          type=int,
   130          help='set maximum batch size; batches are split for processing '
   131          'if they exceed this size',
   132          default=100
   133      )
   134  
   135  
   136  def do_batch(args):
   137      """Runs the batch list, batch show or batch status command, printing output
   138      to the console
   139  
   140          Args:
   141              args: The parsed arguments sent to the command at runtime
   142      """
   143      if args.subcommand == 'list':
   144          do_batch_list(args)
   145  
   146      if args.subcommand == 'show':
   147          do_batch_show(args)
   148  
   149      if args.subcommand == 'status':
   150          do_batch_status(args)
   151  
   152      if args.subcommand == 'submit':
   153          do_batch_submit(args)
   154  
   155  
   156  def do_batch_list(args):
   157      rest_client = RestClient(args.url, args.user)
   158      batches = rest_client.list_batches()
   159      keys = ('batch_id', 'txns', 'signer')
   160      headers = tuple(k.upper() for k in keys)
   161  
   162      def parse_batch_row(batch):
   163          return (
   164              batch['header_signature'],
   165              len(batch.get('transactions', [])),
   166              batch['header']['signer_public_key'])
   167  
   168      if args.format == 'default':
   169          fmt.print_terminal_table(headers, batches, parse_batch_row)
   170  
   171      elif args.format == 'csv':
   172          fmt.print_csv(headers, batches, parse_batch_row)
   173  
   174      elif args.format == 'json' or args.format == 'yaml':
   175          data = [{k: d for k, d in zip(keys, parse_batch_row(b))}
   176                  for b in batches]
   177  
   178          if args.format == 'yaml':
   179              fmt.print_yaml(data)
   180          elif args.format == 'json':
   181              fmt.print_json(data)
   182          else:
   183              raise AssertionError('Missing handler: {}'.format(args.format))
   184  
   185      else:
   186          raise AssertionError('Missing handler: {}'.format(args.format))
   187  
   188  
   189  def do_batch_show(args):
   190      rest_client = RestClient(args.url, args.user)
   191      output = rest_client.get_batch(args.batch_id)
   192  
   193      if args.key:
   194          if args.key in output:
   195              output = output[args.key]
   196          elif args.key in output['header']:
   197              output = output['header'][args.key]
   198          else:
   199              raise CliException(
   200                  'key "{}" not found in batch or header'.format(args.key))
   201  
   202      if args.format == 'yaml':
   203          fmt.print_yaml(output)
   204      elif args.format == 'json':
   205          fmt.print_json(output)
   206      else:
   207          raise AssertionError('Missing handler: {}'.format(args.format))
   208  
   209  
   210  def do_batch_status(args):
   211      """Runs the batch-status command, printing output to the console
   212  
   213          Args:
   214              args: The parsed arguments sent to the command at runtime
   215      """
   216      rest_client = RestClient(args.url, args.user)
   217      batch_ids = args.batch_ids.split(',')
   218  
   219      if args.wait and args.wait > 0:
   220          statuses = rest_client.get_statuses(batch_ids, args.wait)
   221      else:
   222          statuses = rest_client.get_statuses(batch_ids)
   223  
   224      if args.format == 'yaml':
   225          fmt.print_yaml(statuses)
   226      elif args.format == 'json':
   227          fmt.print_json(statuses)
   228      else:
   229          raise AssertionError('Missing handler: {}'.format(args.format))
   230  
   231  
   232  def _split_batch_list(args, batch_list):
   233      new_list = []
   234      for batch in batch_list.batches:
   235          new_list.append(batch)
   236          if len(new_list) == args.batch_size_limit:
   237              yield batch_pb2.BatchList(batches=new_list)
   238              new_list = []
   239      if new_list:
   240          yield batch_pb2.BatchList(batches=new_list)
   241  
   242  
   243  def do_batch_submit(args):
   244  
   245      try:
   246          with open(args.filename, mode='rb') as fd:
   247              batches = batch_pb2.BatchList()
   248              batches.ParseFromString(fd.read())
   249      except IOError as e:
   250          raise CliException(e)
   251  
   252      rest_client = RestClient(args.url, args.user)
   253  
   254      start = time.time()
   255  
   256      for batch_list in _split_batch_list(args, batches):
   257          rest_client.send_batches(batch_list)
   258  
   259      stop = time.time()
   260  
   261      print('batches: {},  batch/sec: {}'.format(
   262          str(len(batches.batches)),
   263          len(batches.batches) / (stop - start)))
   264  
   265      if args.wait and args.wait > 0:
   266          batch_ids = [b.header_signature for b in batches.batches]
   267          wait_time = 0
   268          start_time = time.time()
   269  
   270          while wait_time < args.wait:
   271              statuses = rest_client.get_statuses(
   272                  batch_ids,
   273                  args.wait - int(wait_time))
   274              wait_time = time.time() - start_time
   275  
   276              if all(s['status'] == 'COMMITTED' for s in statuses):
   277                  print('All batches committed in {:.6} sec'.format(wait_time))
   278                  return
   279  
   280              # Wait a moment so as not to send another request immediately
   281              time.sleep(0.2)
   282  
   283          print('Wait timed out! Some batches have not yet been committed...')
   284          for batch_id, status in statuses[0].items():
   285              print('{}  {}'.format(batch_id, status))
   286          exit(1)