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)