Exemple #1
0
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)
Exemple #2
0
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
Exemple #4
0
    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)
Exemple #5
0
    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
Exemple #7
0
 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')
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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")
Exemple #15
0
    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")
Exemple #16
0
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))
Exemple #17
0
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')
Exemple #19
0
 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'
Exemple #21
0
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
Exemple #22
0
    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
Exemple #23
0
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)
Exemple #24
0
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
Exemple #25
0
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)
Exemple #26
0
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