def do_receipt_list(args, config): url = config.get("DEFAULT", 'url') client = BondClient(base_url=url, keyfile=None) state = client.get_all_store_objects() if args.org is not None: org_obj = try_get_then_lookup( state, 'organization', ['organization:ticker', 'organization:pricing-source'], args.org) if org_obj is not None: ListWriter(state, 'receipt', args.full, args.yaml).write('PayeeId', org_obj.get('object-id')) else: raise ClientException("{} does not match an organization".format( args.org)) elif args.bond is not None: bond_obj = try_get_then_lookup(state, 'bond', ['bond:isin', 'bond:cusip'], args.bond) if bond_obj is not None: ListWriter(state, 'receipt', args.full, args.yaml).write('BondId', bond_obj.get('object-id')) else: raise ClientException("{} does not match a bond".format(args.bond)) else: ListWriter(state, 'receipt', args.full, args.yaml).write()
def do_quote_list(args, config): url = config.get("DEFAULT", 'url') client = BondClient(base_url=url, keyfile=None) state = client.get_all_store_objects() if args.org is not None: org_obj = try_get_then_lookup( state, 'organization', ['organization:ticker', 'organization:pricing-source'], args.org) if org_obj is not None: ListWriter(state, 'quote', args.full, args.yaml).write('Firm', org_obj.get('pricing-source')) else: raise ClientException("{} does not match an organization".format( args.org)) elif args.user is not None: user_obj = try_get_then_lookup( state, 'participant', ['participant:username', 'participant:key-id'], args.user) if user_obj is not None: ListWriter(state, 'quote', args.full, args.yaml).write('CreatorId', user_obj.get('object-id')) else: raise ClientException("{} does not match a user".format(args.user)) else: ListWriter(state, 'quote', args.full, args.yaml).write()
def do_init(args, config): username = config.get('DEFAULT', 'username') if args.username is not None: if len(args.username) < 3 or len(args.username) > 16: raise ClientException( "username must be between 3 and 16 characters") username = args.username config.set('DEFAULT', 'username', username) print "set username: {}".format(username) else: print "Username: {}".format(username) http_url = config.get('DEFAULT', 'url') if args.url is not None: http_url = args.url config.set('DEFAULT', 'url', http_url) print "set url to {}".format(http_url) else: print "Validator url: {}".format(http_url) save_config(config) wif_filename = config.get('DEFAULT', 'key_file') if wif_filename.endswith(".wif"): addr_filename = wif_filename[0:-len(".wif")] + ".addr" else: addr_filename = wif_filename + ".addr" if not os.path.exists(wif_filename): try: if not os.path.exists(os.path.dirname(wif_filename)): os.makedirs(os.path.dirname(wif_filename)) privkey = pybitcointools.random_key() encoded = pybitcointools.encode_privkey(privkey, 'wif') addr = pybitcointools.privtoaddr(privkey) with open(wif_filename, "w") as wif_fd: print "writing file: {}".format(wif_filename) wif_fd.write(encoded) wif_fd.write("\n") with open(addr_filename, "w") as addr_fd: print "writing file: {}".format(addr_filename) addr_fd.write(addr) addr_fd.write("\n") except IOError, ioe: raise ClientException("IOError: {}".format(str(ioe)))
def state(self): if self._current_state is None: raise \ ClientException('Client must be configured with a store name ' 'to access its current state') return self._current_state.state
def main(prog_name=os.path.basename(sys.argv[0]), args=sys.argv[1:]): parser = create_parser(prog_name) args = parser.parse_args(args) if args.verbose is None: verbose_level = 0 else: verbose_level = args.verbose setup_loggers(verbose_level=verbose_level) config = load_config() if args.command == 'init': do_init(args, config) elif args.command == 'load': do_load(args, config) elif args.command == 'bond': do_bond(args, config) elif args.command == 'org': do_org(args, config) elif args.command == 'holding': do_holding(args, config) elif args.command == 'user': do_user(args, config) elif args.command == 'order': do_order(args, config) elif args.command == 'quote': do_quote(args, config) elif args.command == 'settlement': do_settlement(args, config) elif args.command == 'receipt': do_receipt(args, config) else: raise ClientException("invalid command: {}".format(args.command))
def do_submit(args): if args.key is not None: key_name = args.key else: key_name = getpass.getuser() if args.url is not None: url = args.url else: url = 'http://localhost:8800' filename = args.filename family_name = args.family # If we have a '/' in the key name, treat it as the full path to # a wif file, without modification. If it does not, then assume # it is in ~/.sawtooth/keys/. if '/' in key_name: key_file = key_name else: key_dir = os.path.join(os.path.expanduser('~'), '.sawtooth', 'keys') key_file = os.path.join(key_dir, key_name + '.wif') if not os.path.exists(key_file): raise ClientException('no such file: {}'.format(key_file)) try: if filename == '-': json_content = sys.stdin.read() else: with open(filename) as fd: json_content = fd.read() except IOError, e: raise CliException(str(e))
def do_load(args, config): url = config.get('DEFAULT', 'url') key_file = config.get('DEFAULT', 'key_file') client = BondClient(base_url=url, keyfile=key_file) for filename in args.filename: try: with open(filename) as fd: data = yaml.load(fd) except IOError, ioe: raise ClientException("IOError: {}".format(str(ioe))) print "Loading file: {}".format(filename) with UpdateBatch(client): for i in xrange(0, len(data['Transactions'])): for j in xrange(0, len(data['Transactions'][i]["Updates"])): update = data['Transactions'][i]["Updates"][j] if "ObjectId" not in update: update["ObjectId"] = \ hashlib.sha256(dict2cbor(update)).hexdigest() print "Sending transaction {}, {}...".format(i, j) print "Update ", update client.send_bond_update(update) if args.wait: client.wait_for_commit()
def sendtxn(self, txntype_name, msgtype_name, minfo): """ Build a transaction for the update, wrap it in a message with all of the appropriate signatures and post it to the validator. Will not work with UpdatesTransaction txn families but will work with txn families in Arcade. """ if self._signing_key is None: raise ClientException( 'can not send transactions as a read-only client') txn = {'TransactionType': txntype_name} txn = dict(txn, **minfo) if 'Dependencies' not in txn: txn['Dependencies'] = [] msg, txnid = _sign_message_with_transaction(txn, msgtype_name, self._signing_key) try: LOGGER.debug('Posting transaction: %s', txnid) result = self._communication.postmsg(msgtype_name, msg) except MessageException as e: LOGGER.warn('Posting transaction failed: %s', str(e)) return None # if there was no exception thrown then all transactions should return # a value which is a dictionary with the message that was sent assert result # if the message was successfully posted, then save the transaction # id for future dependencies self._last_transaction = txnid return txnid
def __init__(self, base_url, store_name=None, name='SawtoothClient', transaction_type=None, message_type=None, keystring=None, keyfile=None, disable_client_validation=False): self._base_url = base_url self._message_type = message_type self._transaction_type = transaction_type # An explicit store name takes precedence over a store name # implied by the transaction type. self._store_name = None if store_name is not None: self._store_name = store_name.strip('/') elif transaction_type is not None: self._store_name = transaction_type.TransactionTypeName.strip('/') self._communication = _Communication(base_url) self._last_transaction = None self._local_node = None self._update_batch = None self._disable_client_validation = disable_client_validation # We only keep current state if we have a store name self._current_state = None if self._store_name is not None: state_type = global_store_manager.KeyValueStore if transaction_type is not None: state_type = transaction_type.TransactionStoreType self._current_state = \ _ClientState(client=self, state_type=state_type) self.fetch_state() signing_key = None if keystring: LOGGER.debug("set signing key from string\n%s", keystring) signing_key = signed_object.generate_signing_key(wifstr=keystring) elif keyfile: LOGGER.debug("set signing key from file %s", keyfile) try: signing_key = signed_object.generate_signing_key( wifstr=open(keyfile, "r").read().strip()) except IOError as ex: raise ClientException("Failed to load key file: {}".format( str(ex))) if signing_key: identifier = signed_object.generate_identifier(signing_key) self._local_node = node.Node(identifier=identifier, signingkey=signing_key, name=name)
def do_keygen(args): if args.key_name is not None: key_name = args.key_name else: key_name = getpass.getuser() if args.key_dir is not None: key_dir = args.key_dir if not os.path.exists(key_dir): raise ClientException('no such directory: {}'.format(key_dir)) else: key_dir = os.path.join(os.path.expanduser('~'), '.sawtooth', 'keys') if not os.path.exists(key_dir): if not args.quiet: print('creating key directory: {}'.format(key_dir)) try: os.makedirs(key_dir) except IOError, e: raise ClientException('IOError: {}'.format(str(e)))
def start_batch(self): """ Start a batch of updates to be sent in a single transaction to the validator. Returns: None """ if self._update_batch is not None: raise ClientException("Update batch already in progress.") self._update_batch = {'Updates': [], 'Dependencies': []}
def fetch_state(self): """ Refresh the state for the client. Returns: Nothing """ if self._current_state is None: raise \ ClientException('Client must be configured with a store name ' 'to access its current state') self._current_state.fetch()
def do_permissioned_validator_registry(args): validator_url = 'http://localhost:8800' if args.url is not None: validator_url = args.url client =\ PermissionedValidatorRegistryClient(args.keyfile, base_url=validator_url) try: with open(args.whitelist) as whitelist_fd: permissioned_validators = json.load(whitelist_fd) except IOError, ex: raise ClientException('IOError: {}'.format(str(ex)))
def do_holding_list(args, config): url = config.get("DEFAULT", 'url') client = BondClient(base_url=url, keyfile=None) state = client.get_all_store_objects() if args.org is not None: org_obj = try_get_then_lookup( state, 'organization', ['organization:ticker', 'organization:pricing-source'], args.org) if org_obj is None: raise ClientException("--org did not specify an organization") ListWriter(state, 'holding', args.full, args.yaml).write('OwnerId', org_obj.get('object-id')) else: ListWriter(state, 'holding', args.full, args.yaml).write()
def send_batch(self): """ Sends the current batch of transactions to the Validator. Returns: transaction_id of the update transaction """ if len(self._update_batch) == 0: raise ClientException("No updates in batch.") msg_info = self._update_batch self._update_batch = None return self.sendtxn(minfo=msg_info, txntype_name=self._transaction_type, msgtype_name=self._message_type)
def sendtxn(self, txn_type, txn_msg_type, minfo): """ Build a transaction for the update, wrap it in a message with all of the appropriate signatures and post it to the validator """ if self._local_node is None: raise ClientException( 'can not send transactions as a read-only client') txn_type = txn_type or self._transaction_type txn_msg_type = txn_msg_type or self._message_type txn = txn_type(minfo=minfo) if len(minfo.get('Dependencies', [])) == 0: # add the last transaction submitted to ensure that the ordering # in the journal matches the order in which we generated them if self._last_transaction: txn.Dependencies = [self._last_transaction] txn.sign_from_node(self._local_node) txnid = txn.Identifier txn.check_valid(self._current_state.state) msg = txn_msg_type() msg.Transaction = txn msg.SenderID = self._local_node.Identifier msg.sign_from_node(self._local_node) try: LOGGER.debug('Posting transaction: %s', txnid) result = self._communication.postmsg(msg.MessageType, msg.dump()) except MessageException: return None # if there was no exception thrown then all transactions should return # a value which is a dictionary with the message that was sent assert result # if the message was successfully posted, then save the transaction # id for future dependencies this could be a problem if the transaction # fails during application self._last_transaction = txnid txn.apply(self._current_state.state) return txnid
def do_settlement_list(args, config): url = config.get("DEFAULT", 'url') client = BondClient(base_url=url, keyfile=None) state = client.get_all_store_objects() if args.creator is not None: user_obj = try_get_then_lookup( state, 'participant', ['participant:username', 'participant:key-id'], args.creator) if user_obj is not None: ListWriter(state, 'settlement', args.full, args.yaml).write('CreatorId', user_obj.get('object-id')) else: raise ClientException("{} does not match a user".format( args.creator)) else: ListWriter(state, 'settlement', args.full, args.yaml).write()
def __init__(self, base_url, store_name=None, name='SawtoothClient', txntype_name=None, msgtype_name=None, keystring=None, keyfile=None, disable_client_validation=False): self._base_url = base_url self._message_type = msgtype_name self._transaction_type = txntype_name # an explicit store name takes precedence over a store name # implied by the transaction type self._store_name = None if store_name is not None: self._store_name = store_name.strip('/') elif txntype_name is not None: self._store_name = txntype_name.strip('/') self._communication = _Communication(base_url) self._last_transaction = None self._signing_key = None self._identifier = None self._update_batch = None self._disable_client_validation = disable_client_validation if keystring: LOGGER.debug("set signing key from string\n%s", keystring) self._signing_key = signing.encode_privkey( signing.decode_privkey(keystring, 'wif'), 'hex') elif keyfile: LOGGER.debug("set signing key from file %s", keyfile) try: self._signing_key = signing.encode_privkey( signing.decode_privkey( open(keyfile, "r").read().strip(), 'wif'), 'hex') except IOError as ex: raise ClientException("Failed to load key file: {}".format( str(ex))) if self._signing_key is not None: self._identifier = signing.generate_identifier( signing.generate_pubkey(self._signing_key))
def get_store(self, key=None, block_id=None, delta=False): """ Generic store retrieval method. This allows complete flexibility in specifying the parameters to the HTTP request. This function should only be used when you need absolute control over the HTTP request being made to the store. Otherwise, the store convenience methods should be used instead. Args: key: (optional) The object to retrieve from the store. If None, will returns keys instead of objects. block_id: (optional) The block ID to use as ending or starting point of retrieval. delta: (optional) A flag to indicate of only a delta should be returned. If key is None, this is ignored. Returns: Either a list of keys, a dictionary of name/value pairs that represent one or more objects, or a delta representation of the store. Notes: Reference the Sawtooth Lake Web API documentation for the behavior for the key/block_id/delta combinations. Raises ClientException if the client object was not created with a store name or transaction type. """ if self._store_name is None: raise \ ClientException( 'The client must be configured with a store name or ' 'transaction type') return \ self.get_store_by_name( txn_type_or_name=self._store_name, key=key, block_id=block_id, delta=delta)
def __init__(self, base_url, store_name, name='SawtoothClient', transaction_type=None, message_type=None, keystring=None, keyfile=None): self._transaction_type = transaction_type self._message_type = message_type self._base_url = base_url self._communication = _Communication(base_url) self._last_transaction = None self._local_node = None state_communication = self._communication if base_url else None self._current_state = _ClientState( communication=state_communication, store_name=store_name, state_type=transaction_type.TransactionStoreType if transaction_type else global_store_manager.KeyValueStore) self._update_batch = None self.fetch_state() signing_key = None if keystring: LOGGER.debug("set signing key from string\n%s", keystring) signing_key = signed_object.generate_signing_key(wifstr=keystring) elif keyfile: LOGGER.debug("set signing key from file %s", keyfile) try: signing_key = signed_object.generate_signing_key( wifstr=open(keyfile, "r").read().strip()) except IOError as ex: raise ClientException("Failed to load key file: {}".format( str(ex))) if signing_key: identifier = signed_object.generate_identifier(signing_key) self._local_node = node.Node(identifier=identifier, signingkey=signing_key, name=name)
def send_update(self, updates, dependencies=None): """ Send an update or list of updates to the validator or add them to an existing batch. Args: updates: single update or list of updates to be sent. dependencies: ids of transactions dependencies. Returns: transaction_id if update is sent, None if it is added to a batch. """ if self._update_batch is not None: # if we are in batching mode. if isinstance(updates, dict): # accept single update self._update_batch['Updates'].append(updates) elif isinstance(updates, (list, tuple)): # or a list self._update_batch['Updates'] += updates else: raise ClientException( "Unexpected updates type {}.".format(type(updates))) if dependencies: self._update_batch['Dependencies'] += dependencies return None # there is no transaction id yet. else: if isinstance(updates, dict): # accept single update updates = [updates] dependencies = dependencies or [] return self.sendtxn( minfo={ 'Updates': updates, 'Dependencies': dependencies, }, txntype_name=self._transaction_type, msgtype_name=self._message_type)
try: os.makedirs(key_dir) except IOError, e: raise ClientException('IOError: {}'.format(str(e))) wif_filename = os.path.join(key_dir, key_name + '.wif') addr_filename = os.path.join(key_dir, key_name + '.addr') if not args.force: file_exists = False for filename in [wif_filename, addr_filename]: if os.path.exists(filename): file_exists = True print('file exists: {}'.format(filename), file=sys.stderr) if file_exists: raise ClientException( 'files exist, rerun with --force to overwrite existing files') privkey = signing.generate_privkey() encoded = signing.encode_privkey(privkey) pubkey = signing.generate_pubkey(privkey) addr = signing.generate_identifier(pubkey) try: wif_exists = os.path.exists(wif_filename) with open(wif_filename, 'w') as wif_fd: if not args.quiet: if wif_exists: print('overwriting file: {}'.format(wif_filename)) else: print('writing file: {}'.format(wif_filename)) wif_fd.write(encoded)
PermissionedValidatorRegistryClient(args.keyfile, base_url=validator_url) try: with open(args.whitelist) as whitelist_fd: permissioned_validators = json.load(whitelist_fd) except IOError, ex: raise ClientException('IOError: {}'.format(str(ex))) result = {} whitelist = permissioned_validators["WhitelistOfPermissionedValidators"] if 'WhitelistName' in whitelist: whitelist_name = whitelist['WhitelistName'] else: raise ClientException('No WhitelistName') if 'PermissionedValidatorPublicKeys' in whitelist: permissioned_public_keys =\ whitelist['PermissionedValidatorPublicKeys'] if 'PermissionedValidatorAddrs' in whitelist: permissioned_addrs = whitelist['PermissionedValidatorAddrs'] update = { 'whitelist_name': whitelist_name, 'verb': 'reg', 'permissioned_public_keys': permissioned_public_keys, 'permissioned_addrs': permissioned_addrs } result['Update'] = update