def test_encrypt_decrypt_wallet(self): wallet = self.enc_wallet wallet._cmd_runner = Commands(wallet.config, wallet.wallet, wallet.network, None, self.enc_wallet_password) wallet.encrypt_wallet("secret2", False) wallet.decrypt_wallet()
def run_offline_command(config, config_options): cmdname = config.get('cmd') cmd = known_commands[cmdname] storage = WalletStorage(config.get_wallet_path()) wallet = Wallet(storage) if cmd.requires_wallet else None # check password if cmd.requires_password and storage.get('use_encryption'): password = config_options.get('password') try: seed = wallet.check_password(password) except InvalidPassword: print "Error: This password does not decode this wallet." sys.exit(1) if cmd.requires_network: print "Warning: running command offline" # arguments passed to function args = map(lambda x: config.get(x), cmd.params) # decode json arguments args = map(json_decode, args) # options args += map(lambda x: config.get(x), cmd.options) cmd_runner = Commands(config, wallet, None, password=config_options.get('password'), new_password=config_options.get('new_password')) func = getattr(cmd_runner, cmd.name) result = func(*args) # save wallet if wallet: wallet.storage.write() return result
def test_encrypt_decrypt_wallet(self): self.wallet._cmd_runner = Commands(self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password") self.wallet.encrypt_wallet("secret2", False) self.wallet.decrypt_wallet()
def _get_value_for_name(self, name): block_header = self.network.blockchain.read_header( self.network.get_local_height() - RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS + 1) block_hash = self.network.blockchain.hash_header(block_header) d = self._run_cmd_as_defer_to_thread('requestvalueforname', name, block_hash) d.addCallback(lambda response: Commands._verify_proof(name, block_header['claim_trie_root'], response)) return d
def test_unlock_wallet(self): self.wallet._cmd_runner = Commands(self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password") cmd_runner = self.wallet.get_cmd_runner() cmd_runner.unlock_wallet("password") self.assertIsNone(cmd_runner.new_password) self.assertEqual(cmd_runner._password, "password")
def test_unlock_wallet(self): wallet = self.enc_wallet wallet._cmd_runner = Commands(wallet.config, wallet.wallet, wallet.network, None, self.enc_wallet_password) cmd_runner = wallet.get_cmd_runner() cmd_runner.unlock_wallet(self.enc_wallet_password) self.assertIsNone(cmd_runner.new_password) self.assertEqual(cmd_runner._password, self.enc_wallet_password)
def _get_value_for_name(self, name): block_header = self.network.blockchain.read_header( self.network.get_local_height() - RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS + 1) block_hash = self.network.blockchain.hash_header(block_header) d = self._run_cmd_as_defer_to_thread('requestvalueforname', name, block_hash) d.addCallback(lambda response: Commands._verify_proof( name, block_header['claim_trie_root'], response)) return d
def test_update_password_keyring_off(self): self.wallet.config.use_keyring = False self.wallet._cmd_runner = Commands(self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password") # no keyring available, so ValueError is expected with self.assertRaises(ValueError): self.wallet.encrypt_wallet("secret2", True)
def _get_value_for_name(self, name): height_to_check = self.network.get_local_height() - RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS + 1 if height_to_check < 0: msg = "Height to check is less than 0, blockchain headers are likely not initialized" raise Exception(msg) block_header = self.network.blockchain.read_header(height_to_check) block_hash = self.network.blockchain.hash_header(block_header) d = self._run_cmd_as_defer_to_thread('requestvalueforname', name, block_hash) d.addCallback(lambda response: Commands._verify_proof(name, block_header['claim_trie_root'], response)) return d
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 __init__(self, config, network): DaemonThread.__init__(self) self.config = config self.network = network self.wallets = {} self.wallet = self.load_wallet(config.get_wallet_path()) self.cmd_runner = Commands(self.config, self.wallet, self.network) host = config.get('rpchost', 'localhost') port = config.get('rpcport', 0) self.server = SimpleJSONRPCServer((host, port), logRequests=False) with open(lockfile(config), 'w') as f: f.write(repr(self.server.socket.getsockname())) self.server.timeout = 0.1 for cmdname in Commands.known_commands: self.server.register_function(getattr(self.cmd_runner, cmdname), cmdname) self.server.register_function(self.run_cmdline, 'run_cmdline') self.server.register_function(self.ping, 'ping') self.server.register_function(self.run_daemon, 'daemon')
def run_cmdline(self, config_options): config = SimpleConfig(config_options) cmdname = config.get('cmd') cmd = Commands.known_commands[cmdname] path = config.get_wallet_path() wallet = self.load_wallet(path) if cmd.requires_wallet else None # arguments passed to function args = map(lambda x: config.get(x), cmd.params) # decode json arguments args = map(json_decode, args) # options args += map(lambda x: config.get(x), cmd.options) cmd_runner = Commands(config, wallet, self.network, password=config_options.get('password'), new_password=config_options.get('new_password')) func = getattr(cmd_runner, cmd.name) result = func(*args) return result
def _get_cmd_runner(self): return Commands(self.config, self.wallet, self.network)
def command(self, command_name, *args, **kwargs): cmd_runner = Commands(self.config, self.wallet, None) cmd = known_commands[command_name] func = getattr(cmd_runner, cmd.name) return func(*args, **kwargs)
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
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