def do_store(args): subcommands = ['list', 'show'] if args.subcommand not in subcommands: print('Unknown sub-command, expecting one of {0}'.format( subcommands)) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': transaction_type_name = web_client.get_store_list() print(pretty_print_dict(transaction_type_name)) return elif args.subcommand == 'show': store_info = \ web_client.get_store_by_name( txn_type_or_name=args.transactionTypeName, key=args.key, block_id=args.blockID, delta=args.incremental) print(pretty_print_dict(store_info)) return except MessageException as e: raise CliException(e)
def do_store(args): subcommands = ['list', 'show'] if args.subcommand not in subcommands: print('Unknown sub-command, expecting one of {0}'.format(subcommands)) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': transaction_type_name = web_client.get_store_list() print(pretty_print_dict(transaction_type_name)) return elif args.subcommand == 'show': store_info = \ web_client.get_store_by_name( txn_type_or_name=args.transactionTypeName, key=args.key, block_id=args.blockID, delta=args.incremental) print(pretty_print_dict(store_info)) return except MessageException as e: raise CliException(e)
def post_shutdown(self): client = SawtoothClient(self.url) msg = shutdown_message.ShutdownMessage({}) msg.SenderID = self._admin_node.Address msg.sign_from_node(self._admin_node) try: client.forward_message(msg) except MessageException as me: print me
def post_shutdown(self): client = SawtoothClient(self.url) msg = shutdown_message.ShutdownMessage({}) msg.SenderID = self._admin_node.Address msg.sign_from_node(self._admin_node) try: client.forward_message(msg) except MessageException as me: print(me)
def __init__(self, baseurl, keystring=None): cmd.Cmd.__init__(self) self.prompt = 'client> ' self._current_state = {} self._client = SawtoothClient(baseurl) signingkey = generate_signing_key( wifstr=keystring) if keystring else generate_signing_key() identifier = generate_identifier(signingkey) self._local_node = Node(identifier=identifier, signingkey=signingkey, name="txnclient")
def is_started(self, url=None): if not url: url = self.url client = SawtoothClient(url) sta = None try: sta = client.get_status(timeout=2) except MessageException as e: print e.message return False if sta is not None: return sta.get('Status', '') == 'started' return False
def is_started(self, url=None): if not url: url = self.url client = SawtoothClient(url) sta = None try: sta = client.get_status(timeout=2) except MessageException as e: print(e.message) return False if sta is not None: return sta.get('Status', '') == 'started' return False
def do_transaction(args): subcommands = ['list', 'show', 'status'] if args.subcommand not in subcommands: print('Unknown sub-command, expecting one of {0}'.format( subcommands)) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': if args.all: tsctids = web_client.get_transaction_list() else: tsctids = \ web_client.get_transaction_list( block_count=args.blockcount) print_trans_info(args, web_client, tsctids) elif args.subcommand == 'show': tsct_info = \ web_client.get_transaction( transaction_id=args.transactionID, field=args.key) print(pretty_print_dict(tsct_info)) return elif args.subcommand == 'status': tsct_status = web_client.get_transaction_status(args.transactionID) if tsct_status == transaction.Status.committed: print('transaction committed') elif tsct_status == transaction.Status.pending: print('transaction still uncommitted') elif tsct_status == transaction.Status.unknown: print('unknown transaction') elif tsct_status == transaction.Status.failed: print('transaction failed to validate.') else: print('transaction returned unexpected status code {0}' .format(tsct_status)) return except MessageException as e: raise CliException(e)
def test_initial_connectivity_n_minus_1(self): try: self.vnm.validator_config['LedgerURL'] = "**none**" validator = self.vnm.launch_node(genesis=True) validators = [validator] with Progress("Launching validator network") as p: self.vnm.validator_config['LedgerURL'] = validator.url node_identifiers = [validator.Address] for i in range(1, 5): self.vnm.validator_config['InitialConnectivity'] = i v = self.vnm.launch_node(genesis=False, daemon=False) validators.append(v) node_identifiers.append(v.Address) p.step() self.vnm.wait_for_registration(validators, validator) validator_urls = self.vnm.urls() clients = [SawtoothClient(base_url=u) for u in validator_urls] integer_key_clients = [ IntegerKeyClient(baseurl=u, keystring=generate_private_key()) for u in validator_urls ] for int_key_client in integer_key_clients: int_key_client.set(key=str(1), value=20) self._verify_equality_of_block_lists(clients) self._verify_orderly_transactions(clients, node_identifiers) finally: self.vnm.shutdown() self.vnm.create_result_archive( 'TestOrderlyInitialConnectivity.tar.gz')
def test_adding_node_with_nodelist(self): try: validators = self.vnm.launch_network(5) validator_urls = self.vnm.urls() endpoint_client = EndpointClient(validator_urls[0]) nodes = [] for epl in endpoint_client.get_endpoint_list(): node = {} node['Host'] = epl['Host'] node['Port'] = epl['Port'] node['Identifier'] = epl['NodeIdentifier'] node['NodeName'] = epl['Name'] nodes.append(node) peers = [nodes[0]['NodeName'], nodes[2]['NodeName'], 'validator-x'] self.vnm.validator_config['Nodes'] = nodes self.vnm.validator_config['Peers'] = peers v = self.vnm.launch_node() validator_urls.append(v.url) self.vnm.wait_for_registration([v], validators[0]) clients = [SawtoothClient(base_url=u) for u in validator_urls] integer_key_clients = [ IntegerKeyClient(baseurl=u, keystring=generate_private_key()) for u in validator_urls ] for int_key_client in integer_key_clients: int_key_client.set(key=str(1), value=20) self._verify_equality_of_block_lists(clients) finally: self.vnm.shutdown() self.vnm.create_result_archive('TestNodeList.tar.gz')
def get_statuslist(urls): ret = None try: ret = [(SawtoothClient(base_url=u)).get_status() for u in urls] except Exception as e: print(e) raise return ret
def get_blocklists(urls): ret = None try: ret = [(SawtoothClient(base_url=u)).get_block_list() for u in urls] except Exception as e: print e.message raise for arr in ret: arr.reverse() return ret
def _get_quorum(gossiper, callback): """Attempts to connect gossiper to new available quorum nodes Args: gossiper (Node): The local node. callback (function): The function to call once the quorum topology update has completed. """ # find out how many we have and how many nodes we still need need count = max(0, TargetConnectivity - len(gossiper.VotingQuorum.keys())) # we have all the nodes we need; do next operation (the callback) if count <= 0: logger.debug('sufficiently connected via %s', [str(x.Name) for x in gossiper.VotingQuorum.itervalues()]) callback() return # add nodes we don't have already, in random order candidates = [x for x in gossiper.quorum_list() if gossiper.VotingQuorum.get(x.Identifier, None) is None] random.shuffle(candidates) logger.debug('trying to increase working quorum by %d from candidates %s', count, [str(x.Name) for x in candidates]) for nd in candidates: client = SawtoothClient('http://{0}:{1}'.format(nd.NetHost, nd.HttpPort)) try: status = client.get_status(timeout=2) except MessageException as e: logger.debug(e.message) continue status = status.get('Status', '') if status in ['started', "transferring ledger", "waiting for initial connections"]: # candidate node is live; add it logger.debug('adding %s to quorum', nd.Name) gossiper.add_quorum_node(nd) if nd.Identifier not in gossiper.peer_id_list(): send_connection_request(gossiper, nd) count -= 1 if count == 0: logger.debug('now sufficiently connected') break # try again (or possibly execute the piggybacked callback) reactor.callLater(TimeBetweenProbes, _get_quorum, gossiper, callback)
def test_join_after_delay_start(self): delayed_validator = None validator_urls = [] try: self.vnm.launch_network(5) validator_urls = self.vnm.urls() delayed_validator = self.vnm.launch_node(delay=True) time.sleep(5) command_url = delayed_validator.url + '/command' request = urllib2.Request( url=command_url, headers={'Content-Type': 'application/json'}) response = urllib2.urlopen(request, data='{"action": "start"}') response.close() self.assertEqual(response.code, 200, "Successful post to delayed validator") validator_urls.append(delayed_validator.url) clients = [SawtoothClient(base_url=u) for u in validator_urls] with Progress("Waiting for registration of 1 validator") as p: url = validator_urls[0] to = TimeOut(60) while not delayed_validator.is_registered(url): if to(): raise ExitError( "{} delayed validator failed to register " "within {}S.".format(1, to.WaitTime)) p.step() time.sleep(1) try: delayed_validator.check_error() except ValidatorManagerException as vme: delayed_validator.dump_log() delayed_validator.dump_stderr() raise ExitError(str(vme)) integer_key_clients = [ IntegerKeyClient(baseurl=u, keystring=generate_private_key()) for u in validator_urls ] for int_key_client in integer_key_clients: int_key_client.set(key=str(1), value=20) self._verify_equality_of_block_lists(clients) finally: self.vnm.shutdown() if delayed_validator is not None and \ validator_urls is not [] and \ delayed_validator.url not in validator_urls: delayed_validator.shutdown() self.vnm.create_result_archive("TestDelayedStart.tar.gz")
def LocalMain(config): """ Main processing loop for the synchronization process """ # To make this more robust we should probably pass in several # URLs and handle failures more cleanly by swapping to alternates client = SawtoothClient(config['LedgerURL'], store_name='MarketPlaceTransaction', name='LedgerSyncClient') global full_sync_interval full_sync_interval = config.get('FullSyncInterval', 50) blockcount = config.get('BlockCount', 10) refresh = config['Refresh'] # pull database and collection names from the configuration and set up the # connections that we need dbhost = config.get('DatabaseHost', 'localhost') dbport = int(config.get('DatabasePort', 28015)) dbname = config['DatabaseName'] InitializeDatabase(dbhost, dbport, dbname) lastblockid = None while True: try: logger.debug('begin synchronization') rconn = rethinkdb.connect(dbhost, dbport, dbname) rconn.repl() currentblocklist = GetCurrentBlockList(client, full_sync_interval) currentblockid = currentblocklist[0] UpdateTransactionState(client, currentblocklist) if currentblockid and currentblockid != lastblockid: ProcessBlockList(client, currentblocklist) logger.info( 'synchronization completed successfully, ' 'current block is %s', currentblockid) lastblockid = currentblockid except: logger.exception('synchronization failed') finally: logger.debug('close the database connection') rconn.close() logger.debug('sleep for %s seconds', float(refresh)) time.sleep(float(refresh))
def do_transaction(args): subcommands = ['list', 'show', 'status'] if args.subcommand not in subcommands: print 'Unknown sub-command, expecting one of {0}'.format( subcommands) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': if args.all: tsctids = web_client.get_transaction_list() else: tsctids = \ web_client.get_transaction_list( block_count=args.blockcount) print_trans_info(args, web_client, tsctids) elif args.subcommand == 'show': tsct_info = \ web_client.get_transaction( transaction_id=args.transactionID, field=args.key) print pretty_print_dict(tsct_info) return elif args.subcommand == 'status': tsct_status = web_client.get_transaction_status(args.transactionID) if tsct_status == transaction.Status.committed: print 'transaction committed' elif tsct_status == transaction.Status.pending: print 'transaction still uncommitted' elif tsct_status == transaction.Status.unknown: print 'unknown transaction' elif tsct_status == transaction.Status.failed: print 'transaction failed to validate.' else: print 'transaction returned unexpected status code {0}'\ .format(tsct_status) return except MessageException as e: raise CliException(e)
def test_basic_startup(self): try: self.vnm.launch_network(count=self.number_of_daemons, others_daemon=True) validator_urls = self.vnm.urls() # IntegerKeyClient is only needed to send one more transaction # so n-1=number of EndpointRegistryTransactions integer_key_clients = [ IntegerKeyClient(baseurl=u, keystring=generate_private_key()) for u in validator_urls ] clients = [SawtoothClient(base_url=u) for u in validator_urls] for int_key_client in integer_key_clients: int_key_client.set(key=str(1), value=20) self._verify_equality_of_block_lists(clients) finally: self.vnm.shutdown() self.vnm.create_result_archive('TestDaemonStartup.tar.gz')
def _get_blocklists(self, urls): ret = [(SawtoothClient(base_url=u)).get_block_list() for u in urls] for (i, arr) in enumerate(ret): arr.reverse() ret[i] = [hsh[:4] for hsh in arr] return ret
try: txn_content = json2dict(json_content) except ValueError, e: raise CliException("Decoding JSON: {}".format(str(e))) try: txnfamily = importlib.import_module(family_name) except ImportError: raise CliException( "transaction family not found: {}".format(family_name)) fake_journal = FakeJournal() txnfamily.register_transaction_types(fake_journal) client = SawtoothClient(base_url=url, keyfile=key_file, store_name=fake_journal.store_class.__name__) client.sendtxn(fake_journal.store_class, fake_journal.msg_class, txn_content) if args.wait: if not client.wait_for_commit(): raise CliException("transaction was not successfully committed") def _get_webclient(args): if args.url is not None: url = args.url else: url = 'http://localhost:8800'
class ClientController(cmd.Cmd): _TxnVerbMap = {'=': 'set', '+=': 'inc', '-=': 'dec'} pformat = 'client> ' def __init__(self, baseurl, keystring=None): cmd.Cmd.__init__(self) self.prompt = 'client> ' self._current_state = {} self._client = SawtoothClient(baseurl) signingkey = generate_signing_key( wifstr=keystring) if keystring else generate_signing_key() identifier = generate_identifier(signingkey) self._local_node = Node(identifier=identifier, signingkey=signingkey, name="txnclient") def postcmd(self, flag, line): return flag def sign_and_post(self, msg): msg.SenderID = self._local_node.Identifier msg.sign_from_node(self._local_node) try: result = self._client.forward_message(msg) if result: pretty_print_dict(result) except MessageException as me: print me # ================================================================= # COMMANDS # ================================================================= def do_set(self, args): """ set -- Command to set properties of the interpreter set url --url <url> set nodeid --name <name> --keyfile <file> """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand url|nodeid' return try: if pargs[0] == 'url': parser = argparse.ArgumentParser() parser.add_argument('--url', help='url used to connect to a validator', required=True) options = parser.parse_args(pargs) self.BaseURL = options.url print "server URL set to {0}".format(self.BaseURL) return elif pargs[0] == 'nodeid': pargs = args.split() parser = argparse.ArgumentParser() parser.add_argument('--name', help='name to use for the client', default='txnclient') parser.add_argument('--keyfile', help='name of the file that contains ' 'the wif format private key') options = parser.parse_args(pargs[1:]) addr = (socket.gethostbyname("localhost"), 0) name = options.name if options.keyfile: signingkey = generate_signing_key( wifstr=read_key_file(options.keyfile)) else: signingkey = generate_signing_key() identifier = generate_identifier(signingkey) self._local_node = Node(address=addr, identifier=identifier, signingkey=signingkey, name=name) print "local id set to {0}".format(self._local_node) return else: print "unknown subcommand; {0}".format(pargs[0]) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return def do_state(self, args): """ state -- Command to manipulate the current ledger state state fetch --store <store> state keys state value --path <path> """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: fetch|keys|value' return try: if pargs[0] == 'fetch': parser = argparse.ArgumentParser() parser.add_argument('--store', choices=TransactionTypes.keys(), default='endpoint') options = parser.parse_args(pargs[1:]) self._current_state = \ self._client.get_store_by_name( txn_type_or_name=TransactionTypes.get(options.store), key='*') elif pargs[0] == 'keys': try: print self._current_state.keys() except: print '[]' elif pargs[0] == 'value': parser = argparse.ArgumentParser() parser.add_argument('--path', required=True) options = parser.parse_args(pargs[1:]) pathargs = options.path.split('.') value = self._current_state while pathargs: value = value.get(pathargs.pop(0)) print value except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return def do_txn(self, args): """ txn -- Command to create IntegerKey transactions txn <expr> [ && <expr> ]* """ txn = integer_key.IntegerKeyTransaction() # pylint: disable=line-too-long pattern = re.compile( r"^\s*(?P<name>[a-zA-Z0-9]+)\s*(?P<verb>[+-]?=)\s*(?P<value>[0-9]+)\s*$" ) # noqa expressions = args.split('&&') for expression in expressions: match = pattern.match(expression) if not match: print 'unable to parse the transaction; {0}'.format(expression) return update = integer_key.Update() update.Verb = self._TxnVerbMap[match.group('verb')] update.Name = match.group('name') update.Value = long(match.group('value')) txn.Updates.append(update) txn.sign_from_node(self._local_node) msg = integer_key.IntegerKeyTransactionMessage() msg.Transaction = txn self.sign_and_post(msg) def do_nodestats(self, args): """ nodestats -- Command to send nodestats messages to validator pool nodestats reset --metrics [<metric>]+ nodestats dump --metrics [<metric>]+ --domains [<domain>]+ """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: reset|dump' return try: if pargs[0] == 'reset': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post( gossip_debug.ResetStatsMessage( {'MetricList': options.metrics})) return elif pargs[0] == 'dump': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') parser.add_argument('--domains', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post( gossip_debug.DumpNodeStatsMessage({ 'MetricList': options.metrics, 'DomainList': options.domains })) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return print 'unknown nodestats command {0}'.format(args) def do_peerstats(self, args): """ peerstats -- Command to send peerstats messages to validator pool peerstats reset --metrics [<metric>]+ peerstats dump --metrics [<metric>]+ --peers [<nodeid>]+ """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: reset|dump' return try: if pargs[0] == 'reset': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post( gossip_debug.ResetPeerStatsMessage( {'MetricList': options.metrics})) return elif pargs[0] == 'dump': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') parser.add_argument('--peers', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post( gossip_debug.DumpPeerStatsMessage({ 'MetricList': options.metrics, 'PeerIDList': options.peers })) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return print 'unknown peerstats command {0}'.format(args) def do_ping(self, args): """ ping -- Command to send a ping message to validator pool """ self.sign_and_post(gossip_debug.PingMessage({})) def do_sping(self, args): """ sping -- Command to send a special ping message to validator pool """ parser = argparse.ArgumentParser() parser.add_argument('--address', default=self._local_node.Identifier) parser.add_argument('--count', default=2, type=int) options = parser.parse_args(args.split()) msg = SpecialPingMessage() msg.Address = options.address msg.Count = options.count self.sign_and_post(msg) def do_dumpquorum(self, args): """ dumpquorum -- Command to request quorum consensus node to dump quorum list """ self.sign_and_post(quorum_debug.DumpQuorumMessage({})) def do_dumpcnxs(self, args): """ dumpcnxs -- Command to send to the validator pool a request to dump current connection information """ self.sign_and_post(gossip_debug.DumpConnectionsMessage({})) def do_dumpblks(self, args): """ dumpblks -- Command to send dump blocks request to the validator pool dumpblks --blocks <count> """ parser = argparse.ArgumentParser() parser.add_argument('--blocks', default=0, type=int) options = parser.parse_args(args.split()) self.sign_and_post( gossip_debug.DumpJournalBlocksMessage({'Count': options.blocks})) def do_val(self, args): """ val -- Command to send a dump value request to the validator pool val <name> [--type <transaction type>] """ pargs = args.split() parser = argparse.ArgumentParser() parser.add_argument('--type', help='Transaction family', default='/IntegerKeyTransaction') options = parser.parse_args(pargs[1:]) tinfo = {'Name': pargs[0], 'TransactionType': options.type} self.sign_and_post(journal_debug.DumpJournalValueMessage(tinfo)) def do_shutdown(self, args): """ shutdown -- Command to send a shutdown message to the validator pool """ self.sign_and_post(shutdown_message.ShutdownMessage({})) return True def do_exit(self, args): """exit Shutdown the simulator and exit the command loop """ return True def do_eof(self, args): return True
try: txn_content = json2dict(json_content) except ValueError, e: raise CliException("Decoding JSON: {}".format(str(e))) try: txnfamily = importlib.import_module(family_name) except ImportError: raise CliException( "transaction family not found: {}".format(family_name)) fake_journal = FakeJournal() txnfamily.register_transaction_types(fake_journal) client = SawtoothClient( base_url=url, keyfile=key_file, store_name=fake_journal.store_class.__name__) client.sendtxn( fake_journal.store_class, fake_journal.msg_class, txn_content) if args.wait: if not client.wait_for_commit(): raise CliException("transaction was not successfully committed") def _get_webclient(args): if args.url is not None: url = args.url
def do_transaction(args): subcommands = ['list', 'show', 'status'] if args.subcommand not in subcommands: print 'Unknown sub-command, expecting one of {0}'.format(subcommands) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': if args.all: tsctids = web_client.get_transaction_list() else: tsctids = \ web_client.get_transaction_list( block_count=args.blockcount) if args.format == 'default': print '{:20} {:20} {:6} {:30} {:12} {:18} {:40}'.format( 'TRANS', 'BLOCK', 'STATUS', 'TXNTYPE', 'NODENAME', 'HOST', 'DOMAIN') for txn_id in tsctids: trans_id, in_block, tran_status, txn_type, node_name,\ host, domain = get_trans_info(web_client, txn_id) print '{:20} {:20} {:6} {:30} {:12} {:18} {:40}'.format( trans_id, in_block, tran_status, txn_type, node_name, host, domain) return elif args.format == 'csv': try: writer = csv.writer(sys.stdout) writer.writerow(('TRANS', 'BLOCK', 'STATUS', 'TXNTYPE', 'NODENAME', 'HOST', 'DOMAIN')) for txn_id in tsctids: writer.writerow((get_trans_info(web_client, txn_id))) except csv.Error as e: raise CliException(e) elif args.format == 'json' or args.format == 'yaml': json_dict = [] for txn_id in tsctids: trans_id, in_block, tran_status, txn_type, node_name,\ host, domain = get_trans_info(web_client, txn_id) json_block = { 'TRANS': trans_id, 'BLOCK': in_block, 'STATUS': tran_status, 'TXNTYPE': txn_type, 'NODENAME': node_name, 'HOST': host, 'DOMAIN': domain } json_dict.append(json_block) if args.format == 'json': print json.dumps(json_dict) else: print yaml.dump(json_dict, default_flow_style=False) else: raise CliException("unknown format option: {}".format( args.format)) elif args.subcommand == 'show': tsct_info = \ web_client.get_transaction( transaction_id=args.transactionID, field=args.key) print pretty_print_dict(tsct_info) return elif args.subcommand == 'status': tsct_status = web_client.get_transaction_status(args.transactionID) if tsct_status == transaction.Status.committed: print 'transaction committed' elif tsct_status == transaction.Status.pending: print 'transaction still uncommitted' elif tsct_status == transaction.Status.unknown: print 'unknown transaction' elif tsct_status == transaction.Status.failed: print 'transaction failed to validate.' else: print 'transaction returned unexpected status code {0}'\ .format(tsct_status) return except MessageException as e: raise CliException(e)
def get_blocklists(urls): ret = None ret = [(SawtoothClient(base_url=u)).get_block_list() for u in urls] for arr in ret: arr.reverse() return ret
def do_block(args): subcommands = ['list', 'show'] if args.subcommand not in subcommands: print 'Unknown sub-command, expecting one of {0}'.format( subcommands) return if args.url is not None: url = args.url else: url = 'http://localhost:8800' web_client = SawtoothClient(url) try: if args.subcommand == 'list': if args.blockcount is None: blockids = web_client.get_block_list() else: blockids = web_client.get_block_list(count=args.blockcount) if args.format == 'default': print '{:6} {:20} {:4} {:10} {:10} {:50}'.format( 'NUM', 'BLOCK', 'TXNS', 'DURATION', 'LOCALMEAN', 'VALIDATOR') for block_id in blockids: block_num, blockid, txns, duration, local_mean,\ validator_dest = get_block_info(web_client, block_id) print '{:6} {:20} {:4} {:10} {:10} {:50}'.format( block_num, blockid, txns, duration, local_mean, validator_dest) elif args.format == 'csv': try: writer = csv.writer(sys.stdout) writer.writerow( ( 'NUM', 'BLOCK', 'TXNS', 'DURATION', 'LOCALMEAN', 'VALIDATOR')) for block_id in blockids: writer.writerow( (get_block_info(web_client, block_id))) except csv.Error: raise CliException('Error writing CSV.') elif args.format == 'json' or args.format == 'yaml': json_dict = [] for block_id in blockids: block_num, blockid, txns, duration, local_mean,\ validator_dest = get_block_info(web_client, block_id) json_block = { 'NUM': block_num, 'BLOCK': blockid, 'TXNS': txns, 'DURATION': duration, 'LOCALMEAN': local_mean, 'VALIDATOR': validator_dest} json_dict.append(json_block) if args.format == 'json': print json.dumps(json_dict) else: print yaml.dump(json_dict, default_flow_style=False) else: raise CliException( "unknown format option: {}".format(args.format)) elif args.subcommand == 'show': block_info = \ web_client.get_block( block_id=args.blockID, field=args.key) print pretty_print_dict(block_info) return except MessageException as e: raise CliException(e)
class ClientController(cmd.Cmd): _TxnVerbMap = {'=': 'set', '+=': 'inc', '-=': 'dec'} pformat = 'client> ' def __init__(self, baseurl, keystring=None): cmd.Cmd.__init__(self) self.prompt = 'client> ' self._current_state = {} self._client = SawtoothClient(baseurl) signingkey = generate_signing_key( wifstr=keystring) if keystring else generate_signing_key() identifier = generate_identifier(signingkey) self._local_node = Node(identifier=identifier, signingkey=signingkey, name="txnclient") def postcmd(self, flag, line): return flag def sign_and_post(self, msg): msg.SenderID = self._local_node.Identifier msg.sign_from_node(self._local_node) try: result = self._client.forward_message(msg) if result: pretty_print_dict(result) except MessageException as me: print me # ================================================================= # COMMANDS # ================================================================= def do_set(self, args): """ set -- Command to set properties of the interpreter set url --url <url> set nodeid --name <name> --keyfile <file> """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand url|nodeid' return try: if pargs[0] == 'url': parser = argparse.ArgumentParser() parser.add_argument('--url', help='url used to connect to a validator', required=True) options = parser.parse_args(pargs) self.BaseURL = options.url print "server URL set to {0}".format(self.BaseURL) return elif pargs[0] == 'nodeid': pargs = args.split() parser = argparse.ArgumentParser() parser.add_argument('--name', help='name to use for the client', default='txnclient') parser.add_argument('--keyfile', help='name of the file that contains ' 'the wif format private key') options = parser.parse_args(pargs[1:]) addr = (socket.gethostbyname("localhost"), 0) name = options.name if options.keyfile: signingkey = generate_signing_key( wifstr=read_key_file(options.keyfile)) else: signingkey = generate_signing_key() identifier = generate_identifier(signingkey) self._local_node = Node(address=addr, identifier=identifier, signingkey=signingkey, name=name) print "local id set to {0}".format(self._local_node) return else: print "unknown subcommand; {0}".format(pargs[0]) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return def do_state(self, args): """ state -- Command to manipulate the current ledger state state fetch --store <store> state keys state value --path <path> """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: fetch|keys|value' return try: if pargs[0] == 'fetch': parser = argparse.ArgumentParser() parser.add_argument('--store', choices=TransactionTypes.keys(), default='endpoint') options = parser.parse_args(pargs[1:]) self._current_state = \ self._client.get_store_by_name( txn_type_or_name=TransactionTypes.get(options.store), key='*') elif pargs[0] == 'keys': try: print self._current_state.keys() except: print '[]' elif pargs[0] == 'value': parser = argparse.ArgumentParser() parser.add_argument('--path', required=True) options = parser.parse_args(pargs[1:]) pathargs = options.path.split('.') value = self._current_state while pathargs: value = value.get(pathargs.pop(0)) print value except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return def do_txn(self, args): """ txn -- Command to create IntegerKey transactions txn <expr> [ && <expr> ]* """ txn = integer_key.IntegerKeyTransaction() # pylint: disable=line-too-long pattern = re.compile(r"^\s*(?P<name>[a-zA-Z0-9]+)\s*(?P<verb>[+-]?=)\s*(?P<value>[0-9]+)\s*$") # noqa expressions = args.split('&&') for expression in expressions: match = pattern.match(expression) if not match: print 'unable to parse the transaction; {0}'.format(expression) return update = integer_key.Update() update.Verb = self._TxnVerbMap[match.group('verb')] update.Name = match.group('name') update.Value = long(match.group('value')) txn.Updates.append(update) txn.sign_from_node(self._local_node) msg = integer_key.IntegerKeyTransactionMessage() msg.Transaction = txn self.sign_and_post(msg) def do_nodestats(self, args): """ nodestats -- Command to send nodestats messages to validator pool nodestats reset --metrics [<metric>]+ nodestats dump --metrics [<metric>]+ --domains [<domain>]+ """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: reset|dump' return try: if pargs[0] == 'reset': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post(gossip_debug.ResetStatsMessage( {'MetricList': options.metrics})) return elif pargs[0] == 'dump': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') parser.add_argument('--domains', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post(gossip_debug.DumpNodeStatsMessage( {'MetricList': options.metrics, 'DomainList': options.domains})) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return print 'unknown nodestats command {0}'.format(args) def do_peerstats(self, args): """ peerstats -- Command to send peerstats messages to validator pool peerstats reset --metrics [<metric>]+ peerstats dump --metrics [<metric>]+ --peers [<nodeid>]+ """ pargs = args.split() if len(pargs) == 0: print 'missing subcommand: reset|dump' return try: if pargs[0] == 'reset': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post(gossip_debug.ResetPeerStatsMessage( {'MetricList': options.metrics})) return elif pargs[0] == 'dump': parser = argparse.ArgumentParser() parser.add_argument('--metrics', default=[], nargs='+') parser.add_argument('--peers', default=[], nargs='+') options = parser.parse_args(pargs[1:]) self.sign_and_post(gossip_debug.DumpPeerStatsMessage( {'MetricList': options.metrics, 'PeerIDList': options.peers})) return except Exception as e: print 'an error occured processing {0}: {1}'.format(args, str(e)) return print 'unknown peerstats command {0}'.format(args) def do_ping(self, args): """ ping -- Command to send a ping message to validator pool """ self.sign_and_post(gossip_debug.PingMessage({})) def do_sping(self, args): """ sping -- Command to send a special ping message to validator pool """ parser = argparse.ArgumentParser() parser.add_argument( '--address', default=self._local_node.Identifier) parser.add_argument('--count', default=2, type=int) options = parser.parse_args(args.split()) msg = SpecialPingMessage() msg.Address = options.address msg.Count = options.count self.sign_and_post(msg) def do_dumpquorum(self, args): """ dumpquorum -- Command to request quorum consensus node to dump quorum list """ self.sign_and_post(quorum_debug.DumpQuorumMessage({})) def do_dumpcnxs(self, args): """ dumpcnxs -- Command to send to the validator pool a request to dump current connection information """ self.sign_and_post(gossip_debug.DumpConnectionsMessage({})) def do_dumpblks(self, args): """ dumpblks -- Command to send dump blocks request to the validator pool dumpblks --blocks <count> """ parser = argparse.ArgumentParser() parser.add_argument('--blocks', default=0, type=int) options = parser.parse_args(args.split()) self.sign_and_post(gossip_debug.DumpJournalBlocksMessage( {'Count': options.blocks})) def do_val(self, args): """ val -- Command to send a dump value request to the validator pool val <name> [--type <transaction type>] """ pargs = args.split() parser = argparse.ArgumentParser() parser.add_argument('--type', help='Transaction family', default='/IntegerKeyTransaction') options = parser.parse_args(pargs[1:]) tinfo = {'Name': pargs[0], 'TransactionType': options.type} self.sign_and_post(journal_debug.DumpJournalValueMessage(tinfo)) def do_shutdown(self, args): """ shutdown -- Command to send a shutdown message to the validator pool """ self.sign_and_post(shutdown_message.ShutdownMessage({})) return True def do_exit(self, args): """exit Shutdown the simulator and exit the command loop """ return True def do_eof(self, args): return True