示例#1
0
def do_genesis(args, data_dir=None):
    """Given the command args, take an series of input files containing
    GenesisData, combine all the batches into one GenesisData, and output the
    result into a new file.
    """

    if data_dir is None:
        data_dir = get_data_dir()

    if not os.path.exists(data_dir):
        raise CliException(
            "Data directory does not exist: {}".format(data_dir))

    genesis_batches = []
    for input_file in args.input_file:
        print('Processing {}...'.format(input_file))
        input_data = BatchList()
        try:
            with open(input_file, 'rb') as in_file:
                input_data.ParseFromString(in_file.read())
        except:
            raise CliException('Unable to read {}'.format(input_file))

        genesis_batches += input_data.batches

    _validate_depedencies(genesis_batches)
    if args.output:
        genesis_file = args.output
    else:
        genesis_file = os.path.join(data_dir, 'genesis.batch')

    print('Generating {}'.format(genesis_file))
    output_data = GenesisData(batches=genesis_batches)
    with open(genesis_file, 'wb') as out_file:
        out_file.write(output_data.SerializeToString())
示例#2
0
def _read_signer(key_filename):
    """Reads the given file as a hex key.

    Args:
        key_filename: The filename where the key is stored. If None,
            defaults to the default key for the current user.

    Returns:
        Signer: the signer

    Raises:
        CliException: If unable to read the file.
    """
    filename = key_filename
    if filename is None:
        filename = os.path.join(os.path.expanduser('~'), '.dgt', 'keys',
                                getpass.getuser() + '.priv')

    try:
        with open(filename, 'r') as key_file:
            signing_key = key_file.read().strip()
    except IOError as e:
        raise CliException('Unable to read key file: {}'.format(str(e)))

    try:
        private_key = Secp256k1PrivateKey.from_hex(signing_key)
    except ParseError as e:
        raise CliException('Unable to read key in file: {}'.format(str(e)))

    context = create_context('secp256k1')
    crypto_factory = CryptoFactory(context)
    return crypto_factory.new_signer(private_key)
示例#3
0
def _do_config_proposal_vote(args):
    """Executes the 'proposal vote' subcommand.  Given a key file, a proposal
    id and a vote value, it generates a batch of bgx_settings transactions
    in a BatchList instance.  The BatchList is file or submitted to a
    validator.
    """
    signer = _read_signer(args.key)
    rest_client = RestClient(args.url)

    proposals = _get_proposals(rest_client)

    proposal = None
    for candidate in proposals.candidates:
        if candidate.proposal_id == args.proposal_id:
            proposal = candidate
            break

    if proposal is None:
        raise CliException('No proposal exists with the given id')

    for vote_record in proposal.votes:
        if vote_record.public_key == signer.get_public_key().as_hex():
            raise CliException(
                'A vote has already been recorded with this signing key')

    txn = _create_vote_txn(
        signer,
        args.proposal_id,
        proposal.proposal.setting,
        args.vote_value)
    batch = _create_batch(signer, [txn])

    batch_list = BatchList(batches=[batch])

    rest_client.send_batches(batch_list)
示例#4
0
    def _submit_request(self,
                        url,
                        params=None,
                        data=None,
                        headers=None,
                        method="GET"):
        """Submits the given request, and handles the errors appropriately.

        Args:
            url (str): the request to send.
            params (dict): params to be passed along to get/post
            data (bytes): the data to include in the request.
            headers (dict): the headers to include in the request.
            method (str): the method to use for the request, "POST" or "GET".

        Returns:
            tuple of (int, str): The response status code and the json parsed
                body, or the error message.

        Raises:
            `CliException`: If any issues occur with the URL.
        """
        if headers is None:
            headers = {}

        if self._auth_header is not None:
            headers['Authorization'] = self._auth_header

        try:
            if method == 'POST':
                result = requests.post(url,
                                       params=params,
                                       data=data,
                                       headers=headers)
            elif method == 'GET':
                result = requests.get(url,
                                      params=params,
                                      data=data,
                                      headers=headers)
            result.raise_for_status()
            return (result.status_code, result.json())
        except requests.exceptions.HTTPError as e:
            return (e.response.status_code, e.response.reason)
        except RemoteDisconnected as e:
            raise CliException(e)
        except (requests.exceptions.MissingSchema,
                requests.exceptions.InvalidURL) as e:
            raise CliException(e)
        except requests.exceptions.ConnectionError as e:
            raise CliException(
                ('Unable to connect to "{}": '
                 'make sure URL is correct').format(self._base_url))
示例#5
0
def _do_config_proposal_create(args):
    """Executes the 'proposal create' subcommand.  Given a key file, and a
    series of key/value pairs, it generates batches of sawtooth_settings
    transactions in a BatchList instance.  The BatchList is either stored to a
    file or submitted to a validator, depending on the supplied CLI arguments.
    """
    settings = [s.split('=', 1) for s in args.setting]

    signer = _read_signer(args.key)

    txns = [_create_propose_txn(signer, setting)
            for setting in settings]

    batch = _create_batch(signer, txns)

    batch_list = BatchList(batches=[batch])

    if args.output is not None:
        try:
            with open(args.output, 'wb') as batch_file:
                batch_file.write(batch_list.SerializeToString())
        except IOError as e:
            raise CliException(
                'Unable to write to batch file: {}'.format(str(e)))
    elif args.url is not None:
        rest_client = RestClient(args.url)
        rest_client.send_batches(batch_list)
    else:
        raise AssertionError('No target for create set.')
示例#6
0
def do_peers(args):
    if args.peers_command == 'list':
        _do_peers_list(args)
    elif args.peers_command == 'graph':
        _do_peers_graph(args)
    else:
        raise CliException('Invalid command: {}'.format(args.subcommand))
示例#7
0
def _do_identity_policy_list(args):
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _POLICY_PREFIX)

    head = state['head']
    state_values = state['data']
    printable_policies = []
    for state_value in state_values:
        policies_list = PolicyList()
        decoded = b64decode(state_value['data'])
        policies_list.ParseFromString(decoded)

        for policy in policies_list.policies:
            printable_policies.append(policy)

    printable_policies.sort(key=lambda p: p.name)

    if args.format == 'default':
        tty_width = tty.width()
        for policy in printable_policies:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(policy.name) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = "Entries:\n"
            for entry in policy.entries:
                entry_string = (" " * 4) + Policy.EntryType.Name(entry.type) \
                    + " " + entry.key
                value += (entry_string[:width] + '...' if
                          len(entry_string) > width else entry_string) + "\n"
            print('{}: \n  {}'.format(policy.name, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['POLICY NAME', 'ENTRIES'])
            for policy in printable_policies:
                output = [policy.name]
                for entry in policy.entries:
                    output.append(
                        Policy.EntryType.Name(entry.type) + " " + entry.key)
                writer.writerow(output)
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        output = {}
        for policy in printable_policies:
            value = "Entries: "
            for entry in policy.entries:
                entry_string = Policy.EntryType.Name(entry.type) + " " \
                    + entry.key
                value += entry_string + " "
            output[policy.name] = value

        policies_snapshot = {'head': head, 'policies': output}
        if args.format == 'json':
            print(json.dumps(policies_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(policies_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))
示例#8
0
def _do_settings_list(args):
    """Lists the current on-chain configuration values.
    """
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=SETTINGS_NAMESPACE)

    prefix = args.filter

    head = state['head']
    state_values = state['data']
    printable_settings = []
    proposals_address = _key_to_address('sawtooth.settings.vote.proposals')
    for state_value in state_values:
        if state_value['address'] == proposals_address:
            # This is completely internal setting and we won't list it here
            continue

        decoded = b64decode(state_value['data'])
        setting = Setting()
        setting.ParseFromString(decoded)

        for entry in setting.entries:
            if entry.key.startswith(prefix):
                printable_settings.append(entry)

    printable_settings.sort(key=lambda s: s.key)

    if args.format == 'default':
        tty_width = tty.width()
        for setting in printable_settings:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(setting.key) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = (setting.value[:width] +
                     '...' if len(setting.value) > width else setting.value)
            print('{}: {}'.format(setting.key, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['KEY', 'VALUE'])
            for setting in printable_settings:
                writer.writerow([setting.key, setting.value])
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        settings_snapshot = {
            'head': head,
            'settings':
            {setting.key: setting.value
             for setting in printable_settings}
        }
        if args.format == 'json':
            print(json.dumps(settings_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(settings_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))
示例#9
0
def do_state(args):
    """Runs the batch list or batch show command, printing output to the
    console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        response = rest_client.list_state(args.subtree, args.head)
        leaves = response['data']
        head = response['head']
        keys = ('address', 'size', 'data')
        headers = tuple(k.upper() for k in keys)

        def parse_leaf_row(leaf, decode=True):
            decoded = b64decode(leaf['data'])
            return (leaf['address'], len(decoded),
                    str(decoded) if decode else leaf['data'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, leaves, parse_leaf_row)
            print('HEAD BLOCK: "{}"'.format(head))

        elif args.format == 'csv':
            fmt.print_csv(headers, leaves, parse_leaf_row)
            print('(data for head block: "{}")'.format(head))

        elif args.format == 'json' or args.format == 'yaml':
            state_data = {
                'head':
                head,
                'data':
                [{k: d
                  for k, d in zip(keys, parse_leaf_row(l, False))}
                 for l in leaves]
            }

            if args.format == 'yaml':
                fmt.print_yaml(state_data)
            elif args.format == 'json':
                fmt.print_json(state_data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_leaf(args.address, args.head)
        if output is not None:
            print('DATA: "{}"'.format(b64decode(output['data'])))
            print('HEAD: "{}"'.format(output['head']))
        else:
            raise CliException('No data available at {}'.format(args.address))
示例#10
0
def print_csv(headers, data_list, parse_row_fn):
    """Takes headers, data, and a row parsing function, and prints data
    to the console in a csv format.
    """
    try:
        writer = csv.writer(sys.stdout)
        writer.writerow(headers)
        for data in data_list:
            writer.writerow(parse_row_fn(data))
    except csv.Error as e:
        raise CliException('Error writing CSV: {}'.format(e))
示例#11
0
def _do_config_genesis(args):
    signer = _read_signer(args.key)
    public_key = signer.get_public_key().as_hex()

    authorized_keys = args.authorized_key if args.authorized_key else \
        [public_key]
    if public_key not in authorized_keys:
        authorized_keys.append(public_key)

    txns = []

    txns.append(_create_propose_txn(
        signer,
        ('sawtooth.settings.vote.authorized_keys',
         ','.join(authorized_keys))))

    if args.approval_threshold is not None:
        if args.approval_threshold < 1:
            raise CliException('approval threshold must not be less than 1')

        if args.approval_threshold > len(authorized_keys):
            raise CliException(
                'approval threshold must not be greater than the number of '
                'authorized keys')

        txns.append(_create_propose_txn(
            signer,
            ('sawtooth.settings.vote.approval_threshold',
             str(args.approval_threshold))))

    batch = _create_batch(signer, txns)
    batch_list = BatchList(batches=[batch])

    try:
        with open(args.output, 'wb') as batch_file:
            batch_file.write(batch_list.SerializeToString())
        print('Generated {}'.format(args.output))
    except IOError as e:
        raise CliException(
            'Unable to write to batch file: {}'.format(str(e)))
示例#12
0
    def _get(self, path, **queries):
        code, json_result = self._submit_request(
            self._base_url + path,
            params=self._format_queries(queries),
        )

        # concat any additional pages of data
        while code == 200 and 'next' in json_result.get('paging', {}):
            previous_data = json_result.get('data', [])
            code, json_result = self._submit_request(
                json_result['paging']['next'])
            json_result['data'] = previous_data + json_result.get('data', [])

        if code == 200:
            return json_result
        if code == 404:
            raise CliException(
                '{}: There is no resource with the identifier "{}"'.format(
                    self._base_url,
                    path.split('/')[-1]))

        raise CliException("{}: {} {}".format(self._base_url, code,
                                              json_result))
示例#13
0
    def _get_data(self, path, **queries):
        url = self._base_url + path
        params = self._format_queries(queries)

        while url:
            code, json_result = self._submit_request(
                url,
                params=params,
            )

            if code == 404:
                raise CliException(
                    '{}: There is no resource with the identifier "{}"'.format(
                        self._base_url,
                        path.split('/')[-1]))
            elif code != 200:
                raise CliException("{}: {} {}".format(self._base_url, code,
                                                      json_result))

            for item in json_result.get('data', []):
                yield item

            url = json_result['paging'].get('next', None)
示例#14
0
def main(prog_name=os.path.basename(sys.argv[0]), args=None,
         with_loggers=True):
    parser = create_parser(prog_name)
    if args is None:
        args = sys.argv[1:]
    args = parser.parse_args(args)

    if with_loggers is True:
        if args.verbose is None:
            verbose_level = 0
        else:
            verbose_level = args.verbose
        setup_loggers(verbose_level=verbose_level)

    if args.subcommand == 'proposal' and args.proposal_cmd == 'create':
        _do_config_proposal_create(args)
    elif args.subcommand == 'proposal' and args.proposal_cmd == 'list':
        _do_config_proposal_list(args)
    elif args.subcommand == 'proposal' and args.proposal_cmd == 'vote':
        _do_config_proposal_vote(args)
    elif args.subcommand == 'genesis':
        _do_config_genesis(args)
    elif args.subcommand == 'topology':
        if args.topology_cmd == 'list':
            _do_list_topology(args)
        elif args.topology_cmd == 'set':
            _do_set_topology(args)
        elif args.topology_cmd == 'param':
            _do_param_topology(args)
        else:
            raise CliException('"{}" is not a valid subcommand of "topology"'.format(args.subcommand))
    #elif args.subcommand == 'fbft':

    else:
        raise CliException(
            '"{}" is not a valid subcommand of "config"'.format(
                args.subcommand))
示例#15
0
def _do_identity_role_list(args):
    """Lists the current on-chain configuration values.
    """
    rest_client = RestClient(args.url)
    state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _ROLE_PREFIX)

    head = state['head']
    state_values = state['data']
    printable_roles = []
    for state_value in state_values:
        role_list = RoleList()
        decoded = b64decode(state_value['data'])
        role_list.ParseFromString(decoded)

        for role in role_list.roles:
            printable_roles.append(role)

    printable_roles.sort(key=lambda r: r.name)

    if args.format == 'default':
        tty_width = tty.width()
        for role in printable_roles:
            # Set value width to the available terminal space, or the min width
            width = tty_width - len(role.name) - 3
            width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH
            value = (role.policy_name[:width] + '...'
                     if len(role.policy_name) > width else role.policy_name)
            print('{}: {}'.format(role.name, value))
    elif args.format == 'csv':
        try:
            writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            writer.writerow(['KEY', 'VALUE'])
            for role in printable_roles:
                writer.writerow([role.name, role.policy_name])
        except csv.Error:
            raise CliException('Error writing CSV')
    elif args.format == 'json' or args.format == 'yaml':
        roles_snapshot = {
            'head': head,
            'roles': {role.name: role.policy_name
                      for role in printable_roles}
        }
        if args.format == 'json':
            print(json.dumps(roles_snapshot, indent=2, sort_keys=True))
        else:
            print(yaml.dump(roles_snapshot, default_flow_style=False)[0:-1])
    else:
        raise AssertionError('Unknown format {}'.format(args.format))
示例#16
0
def _do_identity_role_create(args):
    """Executes the 'role create' subcommand.  Given a key file, a role name,
    and a policy name it generates a batch of sawtooth_identity
    transactions in a BatchList instance. The BatchList is either stored to a
    file or submitted to a validator, depending on the supplied CLI arguments.
    """
    signer = _read_signer(args.key)
    txns = [_create_role_txn(signer, args.name, args.policy)]

    batch = _create_batch(signer, txns)

    batch_list = BatchList(batches=[batch])

    if args.output is not None:
        try:
            with open(args.output, 'wb') as batch_file:
                batch_file.write(batch_list.SerializeToString())
        except IOError as e:
            raise CliException('Unable to write to batch file: {}'.format(
                str(e)))
    elif args.url is not None:
        rest_client = RestClient(args.url)
        rest_client.send_batches(batch_list)
        if args.wait and args.wait > 0:
            batch_id = batch.header_signature
            wait_time = 0
            start_time = time.time()

            while wait_time < args.wait:
                statuses = rest_client.get_statuses([batch_id],
                                                    args.wait - int(wait_time))
                wait_time = time.time() - start_time

                if statuses[0]['status'] == 'COMMITTED':
                    print('Role committed in {:.6} sec'.format(wait_time))
                    return

                # Wait a moment so as not to hammer the Rest Api
                time.sleep(0.2)

            print('Wait timed out! Role was not committed...')
            print('{:128.128}  {}'.format(batch_id, statuses[0]['status']))
            exit(1)
    else:
        raise AssertionError('No target for create set.')
示例#17
0
def do_batch_show(args):
    rest_client = RestClient(args.url, args.user)
    output = rest_client.get_batch(args.batch_id)

    if args.key:
        if args.key in output:
            output = output[args.key]
        elif args.key in output['header']:
            output = output['header'][args.key]
        else:
            raise CliException('key "{}" not found in batch or header'.format(
                args.key))

    if args.format == 'yaml':
        fmt.print_yaml(output)
    elif args.format == 'json':
        fmt.print_json(output)
    else:
        raise AssertionError('Missing handler: {}'.format(args.format))
示例#18
0
def do_batch_submit(args):

    try:
        with open(args.filename, mode='rb') as fd:
            batches = batch_pb2.BatchList()
            batches.ParseFromString(fd.read())
    except IOError as e:
        raise CliException(e)

    rest_client = RestClient(args.url, args.user)

    start = time.time()

    for batch_list in _split_batch_list(args, batches):
        rest_client.send_batches(batch_list)

    stop = time.time()

    print('batches: {},  batch/sec: {}'.format(
        str(len(batches.batches)),
        len(batches.batches) / (stop - start)))

    if args.wait and args.wait > 0:
        batch_ids = [b.header_signature for b in batches.batches]
        wait_time = 0
        start_time = time.time()

        while wait_time < args.wait:
            statuses = rest_client.get_statuses(batch_ids,
                                                args.wait - int(wait_time))
            wait_time = time.time() - start_time

            if all(s['status'] == 'COMMITTED' for s in statuses):
                print('All batches committed in {:.6} sec'.format(wait_time))
                return

            # Wait a moment so as not to send another request immediately
            time.sleep(0.2)

        print('Wait timed out! Some batches have not yet been committed...')
        for batch_id, status in statuses[0].items():
            print('{}  {}'.format(batch_id, status))
        exit(1)
示例#19
0
    def _post(self, path, data, **queries):
        if isinstance(data, bytes):
            headers = {'Content-Type': 'application/octet-stream'}
        else:
            data = json.dumps(data).encode()
            headers = {'Content-Type': 'application/json'}
        headers['Content-Length'] = '%d' % len(data)

        code, json_result = self._submit_request(
            self._base_url + path,
            params=self._format_queries(queries),
            data=data,
            headers=headers,
            method='POST')

        if code in (200, 201, 202):
            return json_result

        raise CliException("({}): {}".format(code, json_result))
示例#20
0
def _do_list_topology(args):
    """
     Executes the 'topology list' subcommand.  
    """
    #signer = _read_signer(args.key)
    rest_client = RestClient(args.url)

    topology = _get_topology(rest_client,args)

    if topology is None:
        raise CliException('No topology exists ')
    """
    for vote_record in proposal.votes:
        if vote_record.public_key == signer.get_public_key().as_hex():
            raise CliException(
                'A vote has already been recorded with this signing key')
    """
    
    print('topology ',args.cls,args.peer,'>>>',topology)
    """
示例#21
0
def _do_peers_graph(args):
    urls = split_comma_append_args(args.urls)
    users = split_comma_append_args(args.users)
    clients = make_rest_apis(urls, users)

    status_dict = _get_peer_endpoints(clients)

    path = args.output if args.output else DOT_FILE

    if not args.force and os.path.isfile(path):
        raise CliException('{} already exists; '
                           'rerun with `--force` to overwrite'.format(path))

    with open(path, 'w') as dot:
        print('strict graph peers {', file=dot)

        for node, peers in status_dict.items():
            for peer in peers:
                print('    "{}" -- "{}"'.format(node, peer), file=dot)

        print('}', file=dot)
示例#22
0
def main(prog_name=os.path.basename(sys.argv[0]), args=None,
         with_loggers=True):
    parser = create_parser(prog_name)
    if args is None:
        args = sys.argv[1:]
    args = parser.parse_args(args)

    if with_loggers is True:
        if args.verbose is None:
            verbose_level = 0
        else:
            verbose_level = args.verbose
        setup_loggers(verbose_level=verbose_level)

    if args.subcommand == 'compare-chains':
        do_compare_chains(args)
    elif args.subcommand == 'list-blocks':
        do_list_blocks(args)
    elif args.subcommand == 'peers':
        do_peers(args)
    else:
        raise CliException('Invalid command: {}'.format(args.subcommand))
示例#23
0
def do_dag(args):
    """Runs the head list or block show command, printing output to the
    console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        heads = sorted(rest_client.list_dag())
        if args.format == 'csv' or args.format == 'default':
            print(','.join(heads))

        elif args.format == 'json':
            fmt.print_json(heads)

        elif args.format == 'yaml':
            fmt.print_yaml(heads)

    if args.subcommand == 'show':
        output = rest_client.get_dag(args.head_id)

        if args.key:
            if args.key in output:
                output = output[args.key]
            elif args.key in output['header']:
                output = output['header'][args.key]
            else:
                raise CliException(
                    'key "{}" not found in block or header'.format(args.key))

        if args.format == 'yaml':
            fmt.print_yaml(output)
        elif args.format == 'json':
            fmt.print_json(output)
        else:
            raise AssertionError('Missing handler: {}'.format(args.format))
示例#24
0
def main(prog_name=os.path.basename(sys.argv[0]), args=None,
         with_loggers=True):
    parser = create_parser(prog_name)
    if args is None:
        args = sys.argv[1:]
    args = parser.parse_args(args)

    load_cli_config(args)

    if with_loggers is True:
        if args.verbose is None:
            verbose_level = 0
        else:
            verbose_level = args.verbose
        setup_loggers(verbose_level=verbose_level)

    if args.command == 'keygen':
        do_keygen(args)
    elif args.command == 'block':
        do_block(args)
    elif args.command == 'batch':
        do_batch(args)
    elif args.command == 'transaction':
        do_transaction(args)
    elif args.command == 'state':
        do_state(args)
    elif args.command == 'identity':
        do_identity(args)
    elif args.command == 'settings':
        do_settings(args)
    elif args.command == 'peer':
        do_peer(args)
    elif args.command == 'status':
        do_status(args)
    elif args.command == 'dag':
        do_dag(args)
    else:
        raise CliException("invalid command: {}".format(args.command))
示例#25
0
def _validate_depedencies(batches):
    """Validates the transaction dependencies for the transactions contained
    within the sequence of batches. Given that all the batches are expected to
    to be executed for the genesis blocks, it is assumed that any dependent
    transaction will proceed the depending transaction.
    """
    transaction_ids = set()
    for batch in batches:
        for txn in batch.transactions:
            txn_header = TransactionHeader()
            txn_header.ParseFromString(txn.header)

            if txn_header.dependencies:
                unsatisfied_deps = [
                    id for id in txn_header.dependencies
                    if id not in transaction_ids
                ]
                if unsatisfied_deps:
                    raise CliException(
                        'Unsatisfied dependency in given transactions:'
                        ' {}'.format(unsatisfied_deps))

            transaction_ids.add(txn.header_signature)
示例#26
0
def do_keygen(args):
    """Executes the key generation operation, given the parsed arguments.

    Args:
        args (:obj:`Namespace`): The parsed args.
    """
    if args.key_name is not None:
        key_name = args.key_name
    else:
        key_name = 'validator'

    key_dir = get_key_dir()

    if not os.path.exists(key_dir):
        raise CliException("Key directory does not exist: {}".format(key_dir))

    priv_filename = os.path.join(key_dir, key_name + '.priv')
    pub_filename = os.path.join(key_dir, key_name + '.pub')

    if not args.force:
        file_exists = False
        for filename in [priv_filename, pub_filename]:
            if os.path.exists(filename):
                file_exists = True
                print('file exists: {}'.format(filename), file=sys.stderr)
        if file_exists:
            raise CliException(
                'files exist, rerun with --force to overwrite existing files')

    context = create_context('secp256k1')

    private_key = context.new_random_private_key()
    public_key = context.get_public_key(private_key)

    try:
        priv_exists = os.path.exists(priv_filename)
        with open(priv_filename, 'w') as priv_fd:
            if not args.quiet:
                if priv_exists:
                    print('overwriting file: {}'.format(priv_filename))
                else:
                    print('writing file: {}'.format(priv_filename))
            priv_fd.write(private_key.as_hex())
            priv_fd.write('\n')
            # Get the uid and gid of the key directory
            keydir_info = os.stat(key_dir)
            keydir_gid = keydir_info.st_gid
            keydir_uid = keydir_info.st_uid
            # Set user and group on keys to the user/group of the key directory
            os.chown(priv_filename, keydir_uid, keydir_gid)
            # Set the private key u+rw g+r
            os.chmod(priv_filename, 0o640)

        pub_exists = os.path.exists(pub_filename)
        with open(pub_filename, 'w') as pub_fd:
            if not args.quiet:
                if pub_exists:
                    print('overwriting file: {}'.format(pub_filename))
                else:
                    print('writing file: {}'.format(pub_filename))
            pub_fd.write(public_key.as_hex())
            pub_fd.write('\n')
            # Set user and group on keys to the user/group of the key directory
            os.chown(pub_filename, keydir_uid, keydir_gid)
            # Set the public key u+rw g+r o+r
            os.chmod(pub_filename, 0o644)

    except IOError as ioe:
        raise CliException('IOError: {}'.format(str(ioe)))
示例#27
0
def do_block(args):
    """Runs the block list or block show command, printing output to the
    console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        block_generator = rest_client.list_blocks()
        blocks = []
        left = args.count
        for block in block_generator:
            blocks.append(block)
            left -= 1
            if left <= 0:
                break

        keys = ('num', 'block_id', 'batches', 'txns', 'signer')
        headers = tuple(k.upper() if k != 'batches' else 'BATS' for k in keys)

        def parse_block_row(block):
            batches = block.get('batches', [])
            txns = [t for b in batches for t in b['transactions']]
            return (
                block['header'].get('block_num', 0),
                block['header_signature'],
                len(batches),
                len(txns),
                block['header']['signer_public_key'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, blocks, parse_block_row)

        elif args.format == 'csv':
            fmt.print_csv(headers, blocks, parse_block_row)

        elif args.format == 'json' or args.format == 'yaml':
            data = [{k: d for k, d in zip(keys, parse_block_row(b))}
                    for b in blocks]

            if args.format == 'yaml':
                fmt.print_yaml(data)
            elif args.format == 'json':
                fmt.print_json(data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_block(args.block_id)

        if args.key:
            if args.key in output:
                output = output[args.key]
            elif args.key in output['header']:
                output = output['header'][args.key]
            else:
                raise CliException(
                    'key "{}" not found in block or header'.format(args.key))

        if args.format == 'yaml':
            fmt.print_yaml(output)
        elif args.format == 'json':
            fmt.print_json(output)
        else:
            raise AssertionError('Missing handler: {}'.format(args.format))
示例#28
0
def do_node(args):
    """Executes the dirs generation operation

    Args:
        args (:obj:`Namespace`): The parsed args.
    """
    def make_dir(dname):

        if os.path.exists(dname):
            print('Dir exists: {}'.format(dname), file=sys.stderr)
            if args.force:
                print('Recreate : {}'.format(dname), file=sys.stderr)
                os.rmdir(dname)
            else:
                return
        print('Create Dir : {}'.format(dname), file=sys.stderr)
        os.mkdir(dname, mode=0o777)

    def copy_file(src, dst):
        try:
            if not os.path.isfile(dst) or args.force:
                shutil.copyfile(src, dst)
                shutil.copymode(src, dst)
                print('Copy file: {}'.format(dst), file=sys.stdout)
        except Exception as ex:
            print('Cant copy file: {} ({})'.format(dst, ex), file=sys.stdout)

    if args.cluster_name is not None:
        cluster_name = args.cluster_name
    else:
        cluster_name = 'dyn'
    if args.peer_name is not None:
        peer_name = args.peer_name
    else:
        peer_name = 'bgx1'

    node_dir = '/project/peer'
    etc_dyn_dir = '/project/bgx/bgx/etc'
    if cluster_name == 'dyn':
        etc_dir = '/project/bgx/bgx/etc'  # config sources
    else:
        etc_dir = os.path.join("/project/bgx/clusters", cluster_name,
                               peer_name, "etc")
        keys_dir = os.path.join("/project/bgx/clusters", cluster_name,
                                peer_name, "keys")

    if not os.path.exists(node_dir):
        raise CliException(
            "Peer directory does not exist: {}".format(node_dir))

    try:

        for filename in ["data", "etc", "keys", "logs", "policy"]:
            dname = os.path.join(node_dir, filename)
            make_dir(dname)

            if filename == 'etc':
                # add config
                for fnm in ["validator.toml", "log_config.toml", "dgt.conf"]:
                    dst = os.path.join(dname, fnm)
                    if fnm == "log_config.toml":
                        src = os.path.join(etc_dyn_dir, fnm + ".dyn")
                    elif fnm == "dgt.conf":
                        src = os.path.join(
                            etc_dyn_dir, fnm +
                            (".dyn" if cluster_name == 'dyn' else '.static'))
                    else:
                        src = os.path.join(
                            etc_dir,
                            fnm + (".dyn" if cluster_name == 'dyn' else ''))
                    copy_file(src, dst)

            elif filename == 'keys' and cluster_name != 'dyn':
                for fnm in ["validator.priv", "validator.pub"]:
                    dst = os.path.join(dname, fnm)
                    src = os.path.join(keys_dir, fnm)
                    copy_file(src, dst)

    except IOError as ioe:
        raise CliException('IOError: {}'.format(str(ioe)))
    except Exception as ex:
        raise CliException('Exception: {}'.format(str(ex)))
示例#29
0
def do_transaction(args):
    """Runs the transaction list or show command, printing to the console

        Args:
            args: The parsed arguments sent to the command at runtime
    """
    rest_client = RestClient(args.url, args.user)

    if args.subcommand == 'list':
        transactions = rest_client.list_transactions()
        keys = ('transaction_id', 'family', 'version', 'size', 'payload')
        headers = tuple(k.upper() if k != 'version' else 'VERS' for k in keys)

        def parse_txn_row(transaction, decode=True):
            decoded = b64decode(transaction['payload'])
            return (
                transaction['header_signature'],
                transaction['header']['family_name'],
                transaction['header']['family_version'],
                len(decoded),
                str(decoded) if decode else transaction['payload'])

        if args.format == 'default':
            fmt.print_terminal_table(headers, transactions, parse_txn_row)

        elif args.format == 'csv':
            fmt.print_csv(headers, transactions, parse_txn_row)

        elif args.format == 'json' or args.format == 'yaml':
            data = [{k: d for k, d in zip(keys, parse_txn_row(b, False))}
                    for b in transactions]

            if args.format == 'yaml':
                fmt.print_yaml(data)
            elif args.format == 'json':
                fmt.print_json(data)
            else:
                raise AssertionError('Missing handler: {}'.format(args.format))

        else:
            raise AssertionError('Missing handler: {}'.format(args.format))

    if args.subcommand == 'show':
        output = rest_client.get_transaction(args.transaction_id)

        if args.key:
            if args.key == 'payload':
                output = b64decode(output['payload'])
            elif args.key in output:
                output = output[args.key]
            elif args.key in output['header']:
                output = output['header'][args.key]
            else:
                raise CliException(
                    'Key "{}" not found in transaction or header'.format(
                        args.key))

        if args.format == 'yaml':
            fmt.print_yaml(output)
        elif args.format == 'json':
            fmt.print_json(output)
        else:
            raise AssertionError('Missing handler: {}'.format(args.format))
示例#30
0
def do_status(args):
    if args.subcommand == 'show':
        do_status_show(args)
    else:
        raise CliException('Invalid command: {}'.format(args.subcommand))