def __init__(self, lbryum_path): self.config = SimpleConfig() self.config.set_key('chain', 'lbrycrd_main') self.storage = WalletStorage(lbryum_path) self.wallet = Wallet(self.storage) self.cmd_runner = Commands(self.config, self.wallet, None) if not self.wallet.has_seed(): seed = self.wallet.make_seed() self.wallet.add_seed(seed, "derp") self.wallet.create_master_keys("derp") self.wallet.create_main_account() self.wallet.update_password("derp", "") self.network = Network(self.config) self.blockchain = get_blockchain(self.config, self.network) print self.config.get('chain'), self.blockchain self.wallet.storage.write()
def run_non_RPC(config): cmdname = config.get('cmd') storage = WalletStorage(config.get_wallet_path()) if storage.file_exists: sys.exit("Error: Remove the existing wallet first!") def password_dialog(): return prompt_password( "Password (hit return if you do not wish to encrypt your wallet):") if cmdname == 'restore': text = config.get('text') password = password_dialog() if Wallet.is_seed(text) or Wallet.is_xprv( text) or Wallet.is_private_key(text) else None try: wallet = Wallet.from_text(text, password, storage) except BaseException as e: sys.exit(str(e)) if not config.get('offline'): network = Network(config) network.start() wallet.start_threads(network) log.info("Recovering wallet...") wallet.synchronize() wallet.wait_until_synchronized() msg = "Recovery successful" if wallet.is_found( ) else "Found no history for this wallet" else: msg = "This wallet was restored offline. It may contain more addresses than displayed." log.info(msg) elif cmdname == 'create': password = password_dialog() wallet = Wallet(storage) seed = wallet.make_seed() wallet.add_seed(seed, password) wallet.create_master_keys(password) wallet.create_main_account() wallet.synchronize() print "Your wallet generation seed is:\n\"%s\"" % seed print "Please keep it in a safe place; if you lose it, you will not be able to restore " \ "your wallet." elif cmdname == 'deseed': wallet = Wallet(storage) if not wallet.seed: log.info("Error: This wallet has no seed") else: ns = wallet.storage.path + '.seedless' print "Warning: you are going to create a seedless wallet'\n" \ "It will be saved in '%s'" % ns if raw_input("Are you sure you want to continue? (y/n) ") in [ 'y', 'Y', 'yes' ]: wallet.storage.path = ns wallet.seed = '' wallet.storage.put('seed', '') wallet.use_encryption = False wallet.storage.put('use_encryption', wallet.use_encryption) for k in wallet.imported_keys.keys(): wallet.imported_keys[k] = '' wallet.storage.put('imported_keys', wallet.imported_keys) print "Done." else: print "Action canceled." wallet.storage.write() else: raise Exception("Unknown command %s" % cmdname) wallet.storage.write() log.info("Wallet saved in '%s'", wallet.storage.path)
def main(): # make sure that certificates are here assert os.path.exists(requests.utils.DEFAULT_CA_BUNDLE_PATH) # on osx, delete Process Serial Number arg generated for apps launched in Finder sys.argv = filter(lambda x: not x.startswith('-psn'), sys.argv) # old 'help' syntax if len(sys.argv) > 1 and sys.argv[1] == 'help': sys.argv.remove('help') sys.argv.append('-h') # read arguments from stdin pipe and prompt for i, arg in enumerate(sys.argv): if arg == '-': if not sys.stdin.isatty(): sys.argv[i] = sys.stdin.read() break else: raise BaseException('Cannot get argument from stdin') elif arg == '?': sys.argv[i] = raw_input("Enter argument:") elif arg == ':': sys.argv[i] = prompt_password('Enter argument (will not echo):', False) # parse command line parser = get_parser() args = parser.parse_args() if args.verbose: logging.getLogger("lbryum").setLevel(logging.INFO) else: logging.getLogger("lbryum").setLevel(logging.ERROR) # config is an object passed to the various constructors (wallet, interface, gui) config_options = args.__dict__ for k, v in config_options.items(): if v is None or (k in config_variables.get(args.cmd, {}).keys()): config_options.pop(k) if config_options.get('server'): config_options['auto_connect'] = False config = SimpleConfig(config_options) cmdname = config.get('cmd') # run non-RPC commands separately if cmdname in ['create', 'restore', 'deseed']: run_non_RPC(config) sys.exit(0) # check if a daemon is running server = get_daemon(config) if cmdname == 'daemon': if server is not None: result = server.daemon(config_options) else: subcommand = config.get('subcommand') if subcommand in ['status', 'stop']: print "Daemon not running" sys.exit(1) elif subcommand == 'start': if hasattr(os, "fork"): p = os.fork() else: log.warning( "Cannot start lbryum daemon as a background process") log.warning( "To use lbryum commands, run them from a different window" ) p = 0 if p == 0: network = Network(config) network.start() daemon = Daemon(config, network) daemon.start() daemon.join() sys.exit(0) else: print "starting daemon (PID %d)" % p sys.exit(0) else: print "syntax: lbryum daemon <start|status|stop>" sys.exit(1) else: # command line init_cmdline(config_options) if server is not None: result = server.run_cmdline(config_options) else: cmd = known_commands[cmdname] if cmd.requires_network: print "Network daemon is not running. Try 'lbryum daemon start'" sys.exit(1) else: result = run_offline_command(config, config_options) print json.dumps(result, indent=2) sys.exit(0)
def main(): # make sure that certificates are here assert os.path.exists(requests.utils.DEFAULT_CA_BUNDLE_PATH) # parse command line parser = get_parser() args = parser.parse_args() if args.verbose: logging.getLogger("lbryum").setLevel(logging.INFO) else: logging.getLogger("lbryum").setLevel(logging.ERROR) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)-8s " "%(name)s:%(lineno)d: %(message)s")) logging.getLogger("lbryum").addHandler(handler) # config is an object passed to the various constructors (wallet, interface) config_options = args.__dict__ for k, v in config_options.items(): if v is None or (k in config_variables.get(args.cmd, {}).keys()): config_options.pop(k) if config_options.get('server'): config_options['auto_connect'] = False config = SimpleConfig(config_options) cmdname = config.get('cmd') # run non-RPC commands separately if cmdname in ['create', 'restore', 'deseed']: run_non_RPC(config) sys.exit(0) # check if a daemon is running server = get_daemon(config) if cmdname == 'daemon': if server is not None: result = server.daemon(config_options) else: subcommand = config.get('subcommand') if subcommand in ['status', 'stop']: print "Daemon not running" sys.exit(1) elif subcommand == 'start': if hasattr(os, "fork"): p = os.fork() else: log.warning("Cannot start lbryum daemon as a background process") log.warning("To use lbryum commands, run them from a different window") p = 0 if p == 0: network = Network(config) network.start() daemon = Daemon(config, network) daemon.start() daemon.join() sys.exit(0) else: print "starting daemon (PID %d)" % p sys.exit(0) else: print "syntax: lbryum daemon <start|status|stop>" sys.exit(1) else: # command line init_cmdline(config_options) if server is not None: result = server.run_cmdline(config_options) else: cmd = Commands.known_commands[cmdname] if cmd.requires_network: print "Network daemon is not running. Try 'lbryum daemon start'" sys.exit(1) else: result = run_offline_command(config, config_options) print json.dumps(result, indent=2) sys.exit(0)
def run_non_RPC(config): _ = get_blockchain(config, None) cmdname = config.get('cmd') storage = WalletStorage(config.get_wallet_path()) if storage.file_exists: sys.exit("Error: Remove the existing wallet first!") def password_dialog(): return prompt_password("Password (hit return if you do not wish to encrypt your wallet):") if cmdname == 'restore': text = config.get('text') no_password = config.get('no_password') password = None if not no_password and (Wallet.is_seed(text) or Wallet.is_xprv(text) or Wallet.is_private_key(text)): password = password_dialog() try: wallet = Wallet.from_text(text, password, storage) wallet.create_main_account() except BaseException as e: sys.exit(str(e)) if not config.get('offline'): network = Network(config) network.start() wallet.start_threads(network) log.info("Recovering wallet...") wallet.synchronize() wallet.wait_until_synchronized() print "Recovery successful" if wallet.is_found() else "Found no history for this wallet" else: print "This wallet was restored offline. It may contain more addresses than displayed." elif cmdname == 'create': password = password_dialog() wallet = Wallet(storage) seed = wallet.make_seed() wallet.add_seed(seed, password) wallet.create_master_keys(password) wallet.create_main_account() wallet.synchronize() print "Your wallet generation seed is:\n\"%s\"" % seed print "Please keep it in a safe place; if you lose it, you will not be able to restore " \ "your wallet." elif cmdname == 'deseed': wallet = Wallet(storage) if not wallet.seed: log.info("Error: This wallet has no seed") else: ns = wallet.storage.path + '.seedless' print "Warning: you are going to create a seedless wallet'\n" \ "It will be saved in '%s'" % ns if raw_input("Are you sure you want to continue? (y/n) ") in ['y', 'Y', 'yes']: wallet.storage.path = ns wallet.seed = '' wallet.storage.put('seed', '') wallet.use_encryption = False wallet.storage.put('use_encryption', wallet.use_encryption) for k in wallet.imported_keys.keys(): wallet.imported_keys[k] = '' wallet.storage.put('imported_keys', wallet.imported_keys) print "Done." else: print "Action canceled." wallet.storage.write() else: raise Exception("Unknown command %s" % cmdname) wallet.storage.write() log.info("Wallet saved in '%s'", wallet.storage.path)
def main(args=None): # make sure that certificates are here assert os.path.exists(requests.utils.DEFAULT_CA_BUNDLE_PATH) # parse command line parser = get_parser() args = parser.parse_args(args) if args.verbose: logging.getLogger("lbryum").setLevel(logging.INFO) else: logging.getLogger("lbryum").setLevel(logging.ERROR) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)-8s " "%(name)s:%(lineno)d: %(message)s")) logging.getLogger("lbryum").addHandler(handler) # config is an object passed to the various constructors (wallet, interface) config_options = args.__dict__ for k, v in config_options.items(): if v is None or (k in config_variables.get(args.cmd, {}).keys()): config_options.pop(k) if config_options.get('server'): config_options['auto_connect'] = False config = SimpleConfig(config_options) cmdname = config.get('cmd') # run non-RPC commands separately if cmdname in ['create', 'restore', 'deseed']: run_non_RPC(config) sys.exit(0) # check if a daemon is running server = get_daemon(config) if cmdname == 'daemon': if server is not None: result = server.daemon(config_options) else: subcommand = config.get('subcommand') if subcommand in ['status', 'stop']: print "Daemon not running" sys.exit(1) elif subcommand == 'start': if hasattr(os, "fork"): p = os.fork() else: log.warning("Cannot start lbryum daemon as a background process") log.warning("To use lbryum commands, run them from a different window") p = 0 if p == 0: network = Network(config) network.start() daemon = Daemon(config, network) daemon.start() daemon.join() sys.exit(0) else: print "starting daemon (PID %d)" % p sys.exit(0) else: print "syntax: lbryum daemon <start|status|stop>" sys.exit(1) else: # command line init_cmdline(config_options) if server is not None: result = server.run_cmdline(config_options) else: cmd = Commands.known_commands[cmdname] if cmd.requires_network: print "Network daemon is not running. Try 'lbryum daemon start'" sys.exit(1) else: result = run_offline_command(config, config_options) print json.dumps(result, indent=2) sys.exit(0)
def setup_network(): self.network = Network(self.config) log.info("Loading the wallet") return defer.succeed(self.network.start())
class LBRYumWallet(Wallet): def __init__(self, storage, config=None): Wallet.__init__(self, storage) self._config = config self.config = make_config(self._config) self.network = None self.wallet = None self._cmd_runner = None self.wallet_unlocked_d = defer.Deferred() self.is_first_run = False self.printed_retrieving_headers = False self._start_check = None self._catch_up_check = None self._caught_up_counter = 0 self._lag_counter = 0 self.blocks_behind = 0 self.catchup_progress = 0 # fired when the wallet actually unlocks (wallet_unlocked_d can be called multiple times) self.wallet_unlock_success = defer.Deferred() def _is_first_run(self): return (not self.printed_retrieving_headers and self.network.blockchain.retrieving_headers) def get_cmd_runner(self): if self._cmd_runner is None: self._cmd_runner = Commands(self.config, self.wallet, self.network) return self._cmd_runner def check_locked(self): if not self.wallet.use_encryption: log.info("Wallet is not encrypted") self.wallet_unlock_success.callback(True) elif not self._cmd_runner: raise Exception("Command runner hasn't been initialized yet") elif self._cmd_runner.locked: log.info("Waiting for wallet password") self.wallet_unlocked_d.addCallback(self.unlock) return self.wallet_unlock_success def unlock(self, password): if self._cmd_runner and self._cmd_runner.locked: try: self._cmd_runner.unlock_wallet(password) self.wallet_unlock_success.callback(True) log.info("Unlocked the wallet!") except InvalidPassword: log.warning("Incorrect password, try again") self.wallet_unlocked_d = defer.Deferred() self.wallet_unlocked_d.addCallback(self.unlock) return defer.succeed(False) return defer.succeed(True) def _start(self): network_start_d = defer.Deferred() def setup_network(): self.network = Network(self.config) log.info("Loading the wallet") return defer.succeed(self.network.start()) def check_started(): if self.network.is_connecting(): if self._is_first_run(): log.info("Running the wallet for the first time. This may take a moment.") self.printed_retrieving_headers = True return False self._start_check.stop() self._start_check = None if self.network.is_connected(): network_start_d.callback(True) else: network_start_d.errback(ValueError("Failed to connect to network.")) self._start_check = task.LoopingCall(check_started) d = setup_network() d.addCallback(lambda _: self._load_wallet()) d.addCallback(lambda _: self._start_check.start(.1)) d.addCallback(lambda _: network_start_d) d.addCallback(lambda _: self._load_blockchain()) d.addCallback(lambda _: log.info("Subscribing to addresses")) d.addCallback(lambda _: self.wallet.wait_until_synchronized(lambda _: None)) d.addCallback(lambda _: log.info("Synchronized wallet")) d.addCallback(lambda _: self.get_cmd_runner()) d.addCallbacks(lambda _: log.info("Set up lbryum command runner")) return d def _stop(self): if self._start_check is not None: self._start_check.stop() self._start_check = None if self._catch_up_check is not None: if self._catch_up_check.running: self._catch_up_check.stop() self._catch_up_check = None d = defer.Deferred() def check_stopped(): if self.network: if self.network.is_connected(): return False stop_check.stop() self.network = None d.callback(True) if self.wallet: self.wallet.stop_threads() log.info("Stopped wallet") if self.network: self.network.stop() log.info("Stopped connection to lbryum server") stop_check = task.LoopingCall(check_stopped) stop_check.start(.1) return d def _load_wallet(self): path = self.config.get_wallet_path() storage = lbryum_wallet.WalletStorage(path) wallet = lbryum_wallet.Wallet(storage) if not storage.file_exists: self.is_first_run = True seed = wallet.make_seed() wallet.add_seed(seed, None) wallet.create_master_keys(None) wallet.create_main_account() wallet.synchronize() self.wallet = wallet self._check_large_wallet() return defer.succeed(True) def _check_large_wallet(self): addr_count = len(self.wallet.addresses(include_change=False)) if addr_count > 1000: log.warning("Your wallet is excessively large (%i addresses), " "please follow instructions here: " "https://github.com/lbryio/lbry/issues/437 to reduce your wallet size", addr_count) else: log.info("Wallet has %i addresses", addr_count) def _load_blockchain(self): blockchain_caught_d = defer.Deferred() def on_update_callback(event, *args): # This callback is called by lbryum when something chain # related has happened local_height = self.network.get_local_height() remote_height = self.network.get_server_height() updated_blocks_behind = self.network.get_blocks_behind() log.info( 'Local Height: %s, remote height: %s, behind: %s', local_height, remote_height, updated_blocks_behind) self.blocks_behind = updated_blocks_behind if local_height != remote_height: return assert self.blocks_behind == 0 self.network.unregister_callback(on_update_callback) log.info("Wallet Loaded") reactor.callFromThread(blockchain_caught_d.callback, True) self.network.register_callback(on_update_callback, ['updated']) d = defer.succeed(self.wallet.start_threads(self.network)) d.addCallback(lambda _: blockchain_caught_d) return d # run commands as a defer.succeed, # lbryum commands should be run this way , unless if the command # only makes a lbrum server query, use _run_cmd_as_defer_to_thread() def _run_cmd_as_defer_succeed(self, command_name, *args, **kwargs): cmd_runner = self.get_cmd_runner() cmd = Commands.known_commands[command_name] func = getattr(cmd_runner, cmd.name) return defer.succeed(func(*args, **kwargs)) # run commands as a deferToThread, lbryum commands that only make # queries to lbryum server should be run this way # TODO: keep track of running threads and cancel them on `stop` # otherwise the application will hang, waiting for threads to complete def _run_cmd_as_defer_to_thread(self, command_name, *args, **kwargs): cmd_runner = self.get_cmd_runner() cmd = Commands.known_commands[command_name] func = getattr(cmd_runner, cmd.name) return threads.deferToThread(func, *args, **kwargs) def _update_balance(self): accounts = None exclude_claimtrietx = True d = self._run_cmd_as_defer_succeed('getbalance', accounts, exclude_claimtrietx) d.addCallback( lambda result: Decimal(result['confirmed']) + Decimal(result.get('unconfirmed', 0.0))) return d # Always create and return a brand new address def get_new_address(self, for_change=False, account=None): return defer.succeed(self.wallet.create_new_address(account=account, for_change=for_change)) # Get the balance of a given address. def get_address_balance(self, address, include_balance=False): c, u, x = self.wallet.get_addr_balance(address) if include_balance is False: return Decimal(float(c) / COIN) else: return Decimal((float(c) + float(u) + float(x)) / COIN) @defer.inlineCallbacks def create_addresses_with_balance(self, num_addresses, amount, broadcast=True): addresses = self.wallet.get_unused_addresses(account=None) if len(addresses) > num_addresses: addresses = addresses[:num_addresses] elif len(addresses) < num_addresses: for i in range(len(addresses), num_addresses): address = self.wallet.create_new_address(account=None) addresses.append(address) outputs = [[address, amount] for address in addresses] tx = yield self._run_cmd_as_defer_succeed('payto', outputs, broadcast=broadcast) defer.returnValue(tx) # Return an address with no balance in it, if # there is none, create a brand new address @defer.inlineCallbacks def get_unused_address(self): addr = self.wallet.get_unused_address(account=None) if addr is None: addr = yield self.get_new_address() defer.returnValue(addr) def get_least_used_address(self, account=None, for_change=False, max_count=100): return defer.succeed(self.wallet.get_least_used_address(account, for_change, max_count)) def get_block(self, blockhash): return self._run_cmd_as_defer_to_thread('getblock', blockhash) def get_most_recent_blocktime(self): height = self.network.get_local_height() if height < 0: return defer.succeed(None) header = self.network.get_header(self.network.get_local_height()) return defer.succeed(header['timestamp']) def get_best_blockhash(self): height = self.network.get_local_height() if height < 0: return defer.succeed(None) header = self.network.blockchain.read_header(height) return defer.succeed(self.network.blockchain.hash_header(header)) def _get_blockhash(self, height): header = self.network.blockchain.read_header(height) return defer.succeed(self.network.blockchain.hash_header(header)) def _get_transaction(self, txid): return self._run_cmd_as_defer_to_thread("gettransaction", txid) def get_name_claims(self): return self._run_cmd_as_defer_succeed('getnameclaims') def _get_claims_for_name(self, name): return self._run_cmd_as_defer_to_thread('getclaimsforname', name) @defer.inlineCallbacks def _send_name_claim(self, name, value, amount, certificate_id=None, claim_address=None, change_address=None): log.info("Send claim: %s for %s: %s ", name, amount, value) claim_out = yield self._run_cmd_as_defer_succeed('claim', name, value, amount, certificate_id=certificate_id, claim_addr=claim_address, change_addr=change_address) defer.returnValue(claim_out) @defer.inlineCallbacks def _abandon_claim(self, claim_id, txid, nout): log.debug("Abandon %s" % claim_id) tx_out = yield self._run_cmd_as_defer_succeed('abandon', claim_id, txid, nout) defer.returnValue(tx_out) @defer.inlineCallbacks def _support_claim(self, name, claim_id, amount): log.debug("Support %s %s %f" % (name, claim_id, amount)) claim_out = yield self._run_cmd_as_defer_succeed('support', name, claim_id, amount) defer.returnValue(claim_out) @defer.inlineCallbacks def _tip_claim(self, claim_id, amount): log.debug("Tip %s %f", claim_id, amount) claim_out = yield self._run_cmd_as_defer_succeed('sendwithsupport', claim_id, amount) defer.returnValue(claim_out) def _do_send_many(self, payments_to_send): def handle_payto_out(payto_out): if not payto_out['success']: raise Exception("Failed payto, reason:{}".format(payto_out['reason'])) return payto_out['txid'] log.debug("Doing send many. payments to send: %s", str(payments_to_send)) d = self._run_cmd_as_defer_succeed('payto', payments_to_send.iteritems()) d.addCallback(lambda out: handle_payto_out(out)) return d def _get_value_for_name(self, name): if not name: raise Exception("No name given") return self._run_cmd_as_defer_to_thread('getvalueforname', name) def _get_value_for_uri(self, uri): if not uri: raise Exception("No uri given") return self._run_cmd_as_defer_to_thread('getvalueforuri', uri) def _get_values_for_uris(self, page, page_size, *uris): return self._run_cmd_as_defer_to_thread('getvaluesforuris', False, page, page_size, *uris) def _claim_certificate(self, name, amount): return self._run_cmd_as_defer_succeed('claimcertificate', name, amount) def _get_certificate_claims(self): return self._run_cmd_as_defer_succeed('getcertificateclaims') def get_claims_from_tx(self, txid): return self._run_cmd_as_defer_to_thread('getclaimsfromtx', txid) def _get_claim_by_outpoint(self, txid, nout): return self._run_cmd_as_defer_to_thread('getclaimbyoutpoint', txid, nout) def _get_claim_by_claimid(self, claim_id): return self._run_cmd_as_defer_to_thread('getclaimbyid', claim_id) def _get_claims_by_claimids(self, *claim_ids): return self._run_cmd_as_defer_to_thread('getclaimsbyids', claim_ids) def _get_balance_for_address(self, address): return defer.succeed(Decimal(self.wallet.get_addr_received(address)) / COIN) def get_nametrie(self): return self._run_cmd_as_defer_to_thread('getclaimtrie') def _get_history(self): return self._run_cmd_as_defer_succeed('claimhistory') def _address_is_mine(self, address): return self._run_cmd_as_defer_succeed('ismine', address) # returns a list of public keys associated with address # (could be multiple public keys if a multisig address) def get_pub_keys(self, address): return self._run_cmd_as_defer_succeed('getpubkeys', address) def list_addresses(self): return self._run_cmd_as_defer_succeed('listaddresses') def list_unspent(self): return self._run_cmd_as_defer_succeed('listunspent') def send_claim_to_address(self, claim_id, destination, amount): return self._run_cmd_as_defer_succeed('sendclaimtoaddress', claim_id, destination, amount) def import_certificate_info(self, serialized_certificate_info): return self._run_cmd_as_defer_succeed('importcertificateinfo', serialized_certificate_info) def export_certificate_info(self, certificate_claim_id): return self._run_cmd_as_defer_succeed('exportcertificateinfo', certificate_claim_id) def get_certificates_for_signing(self): return self._run_cmd_as_defer_succeed('getcertificatesforsigning') def claim_renew_all_before_expiration(self, height): return self._run_cmd_as_defer_succeed('renewclaimsbeforeexpiration', height) def claim_renew(self, txid, nout): return self._run_cmd_as_defer_succeed('renewclaim', txid, nout) def decrypt_wallet(self): if not self.wallet.use_encryption: return False if not self._cmd_runner: return False if self._cmd_runner.locked: return False self._cmd_runner.decrypt_wallet() return not self.wallet.use_encryption def encrypt_wallet(self, new_password, update_keyring=False): if not self._cmd_runner: return False if self._cmd_runner.locked: return False self._cmd_runner.update_password(new_password, update_keyring) return not self.wallet.use_encryption