From 1675cc45800cf7264e0cecc3df3e6fddeea9bc0e Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sat, 25 Aug 2018 23:20:43 -0400 Subject: [PATCH] renamed a bunch of wallet commands and split up the big account command --- CHANGELOG.md | 76 +- lbrynet/daemon/Components.py | 26 +- lbrynet/daemon/Daemon.py | 1059 +++++++++++---------- tests/integration/wallet/test_commands.py | 4 +- tests/unit/lbrynet_daemon/test_Daemon.py | 14 +- 5 files changed, 614 insertions(+), 565 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4da19bda4..a5e870a3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,33 +8,63 @@ can and probably will change functionality and break backwards compatibility at anytime. ## [Unreleased] +Python 3 upgrade of the entire code base and switching to a brand new wallet +implementation are the major changes in this release. + ### Security - * Upgraded `cryptography` package. - * + * upgraded `cryptography` package. -### Fixed - * - * +### API + * unified all command line executables into a single `lbrynet` executable. + * deprecated `daemon_stop` command, use `stop` instead. + * deprecated `wallet_balance` command, use `account_balance` instead. + * deprecated `wallet_unlock` command, use `account_unlock` instead. + * deprecated `wallet_decrypt` command, use `account_decrypt` instead. + * deprecated `wallet_encrypt` command, use `account_encrypt` instead. + * deprecated `wallet_prefill_addresses` command, use `account_fund` instead. + * deprecated `wallet_list` command, use `address_list` instead. + * deprecated `wallet_is_address_mine` command, use `address_is_mine` instead. + * deprecated `wallet_public_key` command, use `address_public_key` instead. + * deprecated `wallet_new_address` command, use `address_generate` instead. + * deprecated `wallet_unused_address` command, use `address_unused` instead. + * added `account_list` command to list accounts including their balance. + * added `account_add` command to add a previously created account from seed or private key. + * added `account_create` command to generate a new account. + * added `account_remove` command to remove an account from wallet. + * added `account_set` command to change a setting on an account. + * added `account_balance` command to get just the account balance. + * added `account_unlock` command to unlock an account. + * added `account_encrypt` command to encrypt an account. + * added `account_decrypt` command to decrypt an account. + * added `account_fund` command to move funds between or within an account in various ways. + * added `account_max_address_gap` command to find large gaps of unused addresses. + * added `address_list` command to list addresses. + * added `address_is_mine` command to check if an address is one of your addresses. + * added `address_public_key` command to get public key of an address. + * added `address_generate` command to generate a new address. + * added `address_unused` command to get existing or generate a new unused address. + * removed `send_amount_to_address` command previously marked as deprecated + * removed `channel_list_mine` command previously marked as deprecated + * removed `get_availability` command previously marked as deprecated -### Deprecated +### Wallet + * changed to a new wallet implementation: torba. + * changed wallet file format to support multiple accounts in one wallet. + * moved transaction data from wallet file into an sqlite database. + * changed channel certificates to be keyed by txid:nout instead of claim_id which + makes it possible to recover old certificates. + +### DHT + * Extensive internal changes as a result of porting to Python 3. + +### P2P & File Manager + * Extensive internal changes as a result of porting to Python 3. + +### Database + * + +### Reflector * - * - -### Changed - * Ported to Python 3 without backwards compatibility with Python 2. - * Switched to a brand new wallet implementation: torba. - * Format of wallet has changed to support multiple accounts in one wallet. - -### Added - * `fund` command, used to move funds between or within an account in various ways. - * `max_address_gap` command, for finding large gaps of unused addresses - * `balance` command, a more detailed version `wallet_balace` which includes all accounts. - * `account` command, adding/deleting/modifying accounts including setting the default account. - -### Removed - * `send_amount_to_address` command, which was previously marked as deprecated - * - ## [0.21.2] - 2018-08-23 ### Fixed diff --git a/lbrynet/daemon/Components.py b/lbrynet/daemon/Components.py index 6faf697e2..d3de4e528 100644 --- a/lbrynet/daemon/Components.py +++ b/lbrynet/daemon/Components.py @@ -314,24 +314,24 @@ class WalletComponent(Component): def __init__(self, component_manager): super().__init__(component_manager) - self.wallet = None + self.wallet_manager = None @property def component(self): - return self.wallet + return self.wallet_manager @defer.inlineCallbacks def get_status(self): - if self.wallet: - local_height = self.wallet.network.get_local_height() - remote_height = self.wallet.network.get_server_height() - best_hash = yield self.wallet.get_best_blockhash() + if self.wallet_manager: + local_height = self.wallet_manager.network.get_local_height() + remote_height = self.wallet_manager.network.get_server_height() + best_hash = yield self.wallet_manager.get_best_blockhash() defer.returnValue({ 'blocks': max(local_height, 0), 'blocks_behind': max(remote_height - local_height, 0), 'best_blockhash': best_hash, - 'is_encrypted': self.wallet.wallet.use_encryption, - 'is_locked': not self.wallet.is_wallet_unlocked, + 'is_encrypted': self.wallet_manager.wallet.use_encryption, + 'is_locked': not self.wallet_manager.is_wallet_unlocked, }) @defer.inlineCallbacks @@ -339,14 +339,14 @@ class WalletComponent(Component): log.info("Starting torba wallet") storage = self.component_manager.get_component(DATABASE_COMPONENT) lbryschema.BLOCKCHAIN_NAME = conf.settings['blockchain_name'] - self.wallet = LbryWalletManager.from_lbrynet_config(conf.settings, storage) - self.wallet.old_db = storage - yield self.wallet.start() + self.wallet_manager = LbryWalletManager.from_lbrynet_config(conf.settings, storage) + self.wallet_manager.old_db = storage + yield self.wallet_manager.start() @defer.inlineCallbacks def stop(self): - yield self.wallet.stop() - self.wallet = None + yield self.wallet_manager.stop() + self.wallet_manager = None class BlobComponent(Component): diff --git a/lbrynet/daemon/Daemon.py b/lbrynet/daemon/Daemon.py index c65f3912e..059716edd 100644 --- a/lbrynet/daemon/Daemon.py +++ b/lbrynet/daemon/Daemon.py @@ -194,7 +194,7 @@ class Daemon(AuthJSONRPCServer): component_attributes = { DATABASE_COMPONENT: "storage", DHT_COMPONENT: "dht_node", - WALLET_COMPONENT: "wallet", + WALLET_COMPONENT: "wallet_manager", STREAM_IDENTIFIER_COMPONENT: "sd_identifier", FILE_MANAGER_COMPONENT: "file_manager", EXCHANGE_RATE_MANAGER_COMPONENT: "exchange_rate_manager", @@ -225,7 +225,7 @@ class Daemon(AuthJSONRPCServer): # TODO: delete these, get the components where needed self.storage = None self.dht_node = None - self.wallet = None + self.wallet_manager = None self.sd_identifier = None self.file_manager = None self.exchange_rate_manager = None @@ -237,10 +237,24 @@ class Daemon(AuthJSONRPCServer): # TODO: delete this self.streams = {} + @property + def wallet(self): + try: + return self.wallet_manager.default_wallet + except AttributeError: + return None + + @property + def account(self): + try: + return self.wallet_manager.default_account + except AttributeError: + return None + @property def ledger(self): try: - return self.wallet.default_account.ledger + return self.wallet_manager.default_account.ledger except AttributeError: return None @@ -277,7 +291,7 @@ class Daemon(AuthJSONRPCServer): timeout = timeout or 30 downloader = StandaloneBlobDownloader( blob_hash, self.blob_manager, self.dht_node.peer_finder, self.rate_limiter, - rate_manager, self.wallet, timeout + rate_manager, self.wallet_manager, timeout ) return downloader.download() @@ -340,7 +354,7 @@ class Daemon(AuthJSONRPCServer): download_id = utils.random_string() self.analytics_manager.send_download_started(download_id, name, claim_dict) self.streams[sd_hash] = GetStream( - self.sd_identifier, self.wallet, self.exchange_rate_manager, self.blob_manager, + self.sd_identifier, self.wallet_manager, self.exchange_rate_manager, self.blob_manager, self.dht_node.peer_finder, self.rate_limiter, self.payment_rate_manager, self.storage, conf.settings['max_key_fee'], conf.settings['disable_max_key_fee'], conf.settings['data_rate'], timeout @@ -371,7 +385,7 @@ class Daemon(AuthJSONRPCServer): def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate=None, claim_address=None, change_address=None): publisher = Publisher( - self.blob_manager, self.payment_rate_manager, self.storage, self.file_manager, self.wallet, certificate + self.blob_manager, self.payment_rate_manager, self.storage, self.file_manager, self.wallet_manager, certificate ) parse_lbry_uri(name) if not file_path: @@ -401,7 +415,7 @@ class Daemon(AuthJSONRPCServer): return self.blob_manager.get_blob(blob[0]) return download_sd_blob( sd_hash, self.blob_manager, self.dht_node.peer_finder, self.rate_limiter, self.payment_rate_manager, - self.wallet, timeout=conf.settings['search_timeout'], download_mirrors=conf.settings['download_mirrors'] + self.wallet_manager, timeout=conf.settings['search_timeout'], download_mirrors=conf.settings['download_mirrors'] ) def get_or_download_sd_blob(self, sd_hash): @@ -439,7 +453,7 @@ class Daemon(AuthJSONRPCServer): cost = self._get_est_cost_from_stream_size(size) - resolved = yield self.wallet.resolve(uri) + resolved = yield self.wallet_manager.resolve(uri) if uri in resolved and 'claim' in resolved[uri]: claim = ClaimDict.load_dict(resolved[uri]['claim']['value']) @@ -614,7 +628,7 @@ class Daemon(AuthJSONRPCServer): def _get_single_peer_downloader(self): downloader = SinglePeerDownloader() - downloader.setup(self.wallet) + downloader.setup(self.wallet_manager) return downloader @defer.inlineCallbacks @@ -664,6 +678,27 @@ class Daemon(AuthJSONRPCServer): # # ############################################################################ + @AuthJSONRPCServer.deprecated("stop") + def jsonrpc_daemon_stop(self): + pass + + def jsonrpc_stop(self): + """ + Stop lbrynet + + Usage: + stop + + Options: + None + + Returns: + (string) Shutdown message + """ + log.info("Shutting down lbrynet daemon") + reactor.callLater(0.1, reactor.fireSystemEvent, "shutdown") + defer.returnValue("Shutting down") + @defer.inlineCallbacks def jsonrpc_status(self): """ @@ -950,14 +985,186 @@ class Daemon(AuthJSONRPCServer): """ return self._render_response(sorted([command for command in self.callable_methods.keys()])) - @requires(WALLET_COMPONENT) - @defer.inlineCallbacks + @AuthJSONRPCServer.deprecated("account_balance") def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False): + pass + + @AuthJSONRPCServer.deprecated("account_unlock") + def jsonrpc_wallet_unlock(self, password): + pass + + @AuthJSONRPCServer.deprecated("account_decrypt") + def jsonrpc_wallet_decrypt(self): + pass + + @AuthJSONRPCServer.deprecated("account_encrypt") + def jsonrpc_wallet_encrypt(self, new_password): + pass + + @AuthJSONRPCServer.deprecated("address_is_mine") + def jsonrpc_wallet_is_address_mine(self, address): + pass + + @AuthJSONRPCServer.deprecated("address_public_key") + def jsonrpc_wallet_public_key(self, address): + pass + + @AuthJSONRPCServer.deprecated("address_list") + def jsonrpc_wallet_list(self): + pass + + @AuthJSONRPCServer.deprecated("address_generate") + def jsonrpc_wallet_new_address(self): + pass + + @AuthJSONRPCServer.deprecated("address_unused") + def jsonrpc_wallet_unused_address(self): + pass + + @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) + @defer.inlineCallbacks + def jsonrpc_wallet_send(self, amount, address=None, claim_id=None): """ - Return the balance of the wallet + Send credits. If given an address, send credits to it. If given a claim id, send a tip + to the owner of a claim specified by uri. A tip is a claim support where the recipient + of the support is the claim address for the claim being supported. Usage: - wallet_balance [
| --address=
] [--include_unconfirmed] + wallet_send ( | --amount=) + ((
| --address=
) | ( | --claim_id=)) + + Options: + --amount= : (Decimal) amount of credit to send + --address=
: (str) address to send credits to + --claim_id= : (str) claim_id of the claim to send to tip to + + Returns: + If sending to an address: + (dict) true if payment successfully scheduled + { + "hex": (str) raw transaction, + "inputs": (list) inputs(dict) used for the transaction, + "outputs": (list) outputs(dict) for the transaction, + "total_fee": (int) fee in dewies, + "total_input": (int) total of inputs in dewies, + "total_output": (int) total of outputs in dewies(input - fees), + "txid": (str) txid of the transaction, + } + + If sending a claim tip: + (dict) Dictionary containing the result of the support + { + txid : (str) txid of resulting support claim + nout : (int) nout of the resulting support claim + fee : (float) fee paid for the transaction + } + """ + + amount = self.get_dewies_or_error("amount", amount) + if not amount: + raise NullFundsError + elif amount < 0: + raise NegativeFundsError() + + if address and claim_id: + raise Exception("Given both an address and a claim id") + elif not address and not claim_id: + raise Exception("Not given an address or a claim id") + + if address: + # raises an error if the address is invalid + decode_address(address) + + reserved_points = self.wallet_manager.reserve_points(address, amount) + if reserved_points is None: + raise InsufficientFundsError() + result = yield self.wallet_manager.send_points_to_address(reserved_points, amount) + self.analytics_manager.send_credits_sent() + else: + validate_claim_id(claim_id) + result = yield self.wallet_manager.tip_claim(claim_id, amount) + self.analytics_manager.send_claim_action('new_support') + defer.returnValue(result) + + @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) + # @AuthJSONRPCServer.deprecated("account_fund"), API has changed as well, so we forward for now + # marked as deprecated in changelog and will be removed after subsequent release + def jsonrpc_wallet_prefill_addresses(self, num_addresses, amount, no_broadcast=False): + """ + Create new UTXOs, each containing `amount` credits + + Usage: + wallet_prefill_addresses [--no_broadcast] + ( | --num_addresses=) + ( | --amount=) + + Options: + --no_broadcast : (bool) whether to broadcast or not + --num_addresses= : (int) num of addresses to create + --amount= : (float) initial amount in each address + + Returns: + (dict) the resulting transaction + """ + broadcast = not no_broadcast + return self.jsonrpc_account_fund( + self.wallet_manager.default_account.name, + self.wallet_manager.default_account.name, + amount=amount, + outputs=num_addresses, + broadcast=broadcast + ) + + @requires("wallet") + def jsonrpc_account_list(self, account_name=None, confirmations=6, include_reserved=False, + include_claims=False): + """ + Return details of an individual account or all of the accounts. + + Usage: + account_list [] [--confirmations=] + [--include_reserved] [--include_claims] + + Options: + --account= : (str) If provided only the balance for this + account will be given + --confirmations= : (int) required confirmations (default: 6) + --include_reserved : (bool) include reserved UTXOs (default: false) + --include_claims : (bool) include claims, requires than a + LBC account is specified (default: false) + + Returns: + (map) balance of account(s) + """ + if account_name: + for account in self.wallet_manager.accounts: + if account.name == account_name: + if include_claims and not isinstance(account, LBCAccount): + raise Exception( + "'--include-claims' requires specifying an LBC ledger account. " + "Found '{}', but it's an {} ledger account." + .format(account_name, account.ledger.symbol) + ) + args = { + 'confirmations': confirmations, + 'include_reserved': include_reserved + } + if include_claims: + args['include_claims'] = True + return account.get_balance(**args) + raise Exception("Couldn't find an account named: '{}'.".format(account_name)) + else: + if include_claims: + raise Exception("'--include-claims' requires specifying an LBC account.") + return self.wallet_manager.get_balances(confirmations) + + @requires("wallet") + def jsonrpc_account_balance(self, address=None, include_unconfirmed=False): + """ + Return the balance of an account + + Usage: + account_balance [
| --address=
] [--include_unconfirmed] Options: --address=
: (str) If provided only the balance for this @@ -969,31 +1176,185 @@ class Daemon(AuthJSONRPCServer): """ if address is not None: raise NotImplementedError("Limiting by address needs to be re-implemented in new wallet.") - dewies = yield self.wallet.default_account.get_balance( + dewies = yield self.wallet_manager.default_account.get_balance( 0 if include_unconfirmed else 6 ) defer.returnValue(round(dewies / COIN, 3)) - @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_wallet_unlock(self, password): + @requires("wallet") + def jsonrpc_account_add( + self, account_name, single_key=False, seed=None, private_key=None, public_key=None): """ - Unlock an encrypted wallet + Add a previously created account from a seed, private key or public key (read-only). + Specify --single_key for single address or vanity address accounts. Usage: - wallet_unlock ( | --password=) + account_add ( | --account_name=) + (--seed= | --private_key= | --public_key=) + [--single_key] + + Options: + --account_name= : (str) name of the account to add + --seed= : (str) seed to generate new account from + --private_key= : (str) private key for new account + --public_key= : (str) public key for new account + --single_key : (bool) create single key account, default is multi-key + + Returns: + (map) added account details + + """ + self.error_if_account_exists(account_name) + account = LBCAccount.from_dict( + self.wallet_manager.get_or_create_ledger('lbc_mainnet'), + self.wallet_manager, { + 'name': account_name, + 'seed': seed, + 'private_key': private_key, + 'public_key': public_key, + 'address_generator': { + 'name': SingleKey.name if single_key else HierarchicalDeterministic.name + } + } + ) + self.wallet_manager.save() + + result = account.to_dict() + result['status'] = 'added' + result.pop('certificates', None) + result['is_default'] = self.wallet_manager.accounts[0] == account + return result + + @requires("wallet") + def jsonrpc_account_create(self, account_name, single_key=False): + """ + Create a new account. Specify --single_key if you want to use + the same address for all transactions (not recommended). + + Usage: + account_create ( | --account_name=) [--single_key] + + Options: + --account_name= : (str) name of the account to create + --single_key : (bool) create single key account, default is multi-key + + Returns: + (map) new account details + + """ + self.error_if_account_exists(account_name) + account = LBCAccount.generate( + self.wallet_manager.get_or_create_ledger('lbc_mainnet'), + self.wallet_manager, account_name, { + 'name': SingleKey.name if single_key else HierarchicalDeterministic.name + } + ) + self.wallet_manager.save() + + result = account.to_dict() + result['status'] = 'created' + result.pop('certificates', None) + result['is_default'] = self.wallet_manager.accounts[0] == account + return result + + @requires("wallet") + def jsonrpc_account_remove(self, account_name): + """ + Remove an existing account. + + Usage: + account ( | --account_name=) + + Options: + --account_name= : (str) name of the account to remove + + Returns: + (map) removed account details + + """ + wallet = self.wallet_manager.default_wallet + account = self.get_account_or_error('account_name', account_name) + wallet.accounts.remove(account) + wallet.save() + result = account.to_dict() + result['status'] = 'removed' + result.pop('certificates', None) + return result + + @requires("wallet") + def jsonrpc_account_set( + self, account_name, default=False, + change_gap=None, change_max_uses=None, receiving_gap=None, receiving_max_uses=None): + """ + Change various settings on an account. + + Usage: + account ( | --account_name=) [--default] + [--change_gap=] [--change_max_uses=] + [--receiving_gap=] [--receiving_max_uses=] + + Options: + --account_name= : (str) name of the account to change + --default : (bool) make this account the default + --receiving_gap= : (int) set the gap for receiving addresses + --receiving_max_uses= : (int) set the maximum number of times to + use a receiving address + --change_gap= : (int) set the gap for change addresses + --change_max_uses= : (int) set the maximum number of times to + use a change address + + Returns: + (map) updated account details + + """ + account = self.get_account_or_error('account_name', account_name) + change_made = False + + if account.receiving.name == HierarchicalDeterministic.name: + address_changes = { + 'change': {'gap': change_gap, 'maximum_uses_per_address': change_max_uses}, + 'receiving': {'gap': receiving_gap, 'maximum_uses_per_address': receiving_max_uses}, + } + for chain_name in address_changes: + chain = getattr(account, chain_name) + for attr, value in address_changes[chain_name].items(): + if value is not None: + setattr(chain, attr, value) + change_made = True + + if default: + self.wallet_manager.accounts.remove(account) + self.wallet_manager.accounts.insert(0, account) + change_made = True + + if change_made: + self.wallet_manager.save() + + result = account.to_dict() + result.pop('certificates', None) + result['is_default'] = self.wallet_manager.accounts[0] == account + return result + + @requires(WALLET_COMPONENT) + @defer.inlineCallbacks + def jsonrpc_account_unlock(self, password): + """ + Unlock an encrypted account + + Usage: + account_unlock ( | --password=) Options: --password= : (str) password for unlocking wallet Returns: - (bool) true if wallet is unlocked, otherwise false + (bool) true if account is unlocked, otherwise false """ # the check_locked() in the if statement is needed because that is what sets # the wallet_unlocked_d deferred ¯\_(ツ)_/¯ - if not self.wallet.check_locked(): - d = self.wallet.wallet_unlocked_d + if not self.wallet_manager.check_locked(): + d = self.wallet_manager.wallet_unlocked_d d.callback(password) result = yield d else: @@ -1002,12 +1363,12 @@ class Daemon(AuthJSONRPCServer): defer.returnValue(response) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - def jsonrpc_wallet_decrypt(self): + def jsonrpc_account_decrypt(self): """ - Decrypt an encrypted wallet, this will remove the wallet password + Decrypt an encrypted account, this will remove the wallet password Usage: - wallet_decrypt + account_decrypt Options: None @@ -1015,10 +1376,10 @@ class Daemon(AuthJSONRPCServer): Returns: (bool) true if wallet is decrypted, otherwise false """ - return defer.succeed(self.wallet.decrypt_wallet()) + return self.wallet_manager.decrypt_wallet() @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - def jsonrpc_wallet_encrypt(self, new_password): + def jsonrpc_account_encrypt(self, new_password): """ Encrypt a wallet with a password, if the wallet is already encrypted this will update the password @@ -1032,41 +1393,148 @@ class Daemon(AuthJSONRPCServer): Returns: (bool) true if wallet is decrypted, otherwise false """ - return defer.succeed(self.wallet.encrypt_wallet(new_password)) + return self.wallet_manager.encrypt_wallet(new_password) - @defer.inlineCallbacks - @AuthJSONRPCServer.deprecated("stop") - def jsonrpc_daemon_stop(self): + @requires("wallet") + def jsonrpc_account_max_address_gap(self, account_name): """ - Stop lbrynet-daemon + Finds ranges of consecutive addresses that are unused and returns the length + of the longest such range: for change and receiving address chains. This is + useful to figure out ideal values to set for 'receiving_gap' and 'change_gap' + account settings. Usage: - daemon_stop + account_max_address_gap ( | --account=) + + Options: + --account= : (str) account for which to get max gaps + + Returns: + (map) maximum gap for change and receiving addresses + """ + return self.get_account_or_error('account', account_name).get_max_gap() + + @requires("wallet") + def jsonrpc_account_fund(self, to_account, from_account, amount=0, + everything=False, outputs=1, broadcast=False): + """ + Transfer some amount (or --everything) to an account from another + account (can be the same account). Amounts are interpreted as LBC. + You can also spread the transfer across a number of --outputs (cannot + be used together with --everything). + + Usage: + account_fund ( | --to_account=) + ( | --from_account=) + ( | --amount= | --everything) + [ | --outputs=] + [--broadcast] + + Options: + --to_account= : (str) send to this account + --from_account= : (str) spend from this account + --amount= : (str) the amount to transfer lbc + --everything : (bool) transfer everything (excluding claims), default: false. + --outputs= : (int) split payment across many outputs, default: 1. + --broadcast : (bool) actually broadcast the transaction, default: false. + + Returns: + (map) transaction performing requested action + + """ + to_account = self.get_account_or_error('to_account', to_account) + from_account = self.get_account_or_error('from_account', from_account) + amount = self.get_dewies_or_error('amount', amount) if amount else None + if not isinstance(outputs, int): + raise ValueError("--outputs must be an integer.") + if everything and outputs > 1: + raise ValueError("Using --everything along with --outputs is not supported.") + return from_account.fund( + to_account=to_account, amount=amount, everything=everything, + outputs=outputs, broadcast=broadcast + ) + + @requires(WALLET_COMPONENT) + def jsonrpc_address_is_mine(self, address): + """ + Checks if an address is associated with the current wallet. + + Usage: + wallet_is_address_mine (
| --address=
) + + Options: + --address=
: (str) address to check + + Returns: + (bool) true, if address is associated with current wallet + """ + return self.wallet_manager.address_is_mine(address) + + @requires(WALLET_COMPONENT) + def jsonrpc_address_public_key(self, address): + """ + Get public key from wallet address + + Usage: + wallet_public_key (
| --address=
) + + Options: + --address=
: (str) address for which to get the public key + + Returns: + (list) list of public keys associated with address. + Could contain more than one public key if multisig. + """ + return self.wallet_manager.get_pub_keys(address) + + @requires(WALLET_COMPONENT) + def jsonrpc_address_list(self): + """ + List wallet addresses + + Usage: + wallet_list Options: None Returns: - (string) Shutdown message + List of wallet addresses """ - return self.jsonrpc_stop() + return self.wallet_manager.list_addresses() - def jsonrpc_stop(self): + @requires(WALLET_COMPONENT) + def jsonrpc_address_generate(self): """ - Stop lbrynet + Generate a new wallet address Usage: - stop + wallet_new_address Options: None Returns: - (string) Shutdown message + (str) New wallet address in base58 """ - log.info("Shutting down lbrynet daemon") - reactor.callLater(0.1, reactor.fireSystemEvent, "shutdown") - defer.returnValue("Shutting down") + return self.wallet_manager.get_new_address() + + @requires(WALLET_COMPONENT) + def jsonrpc_address_unused(self): + """ + Return an address containing no balance, will create + a new address if there is none. + + Usage: + wallet_unused_address + + Options: + None + + Returns: + (str) Unused wallet address in base58 + """ + return self.wallet_manager.get_unused_address() @requires(FILE_MANAGER_COMPONENT) @defer.inlineCallbacks @@ -1160,7 +1628,7 @@ class Daemon(AuthJSONRPCServer): try: name = parse_lbry_uri(name).name - metadata = yield self.wallet.resolve(name, check_cache=not force) + metadata = yield self.wallet_manager.resolve(name, check_cache=not force) if name in metadata: metadata = metadata[name] except UnknownNameError: @@ -1207,9 +1675,9 @@ class Daemon(AuthJSONRPCServer): """ if claim_id is not None and txid is None and nout is None: - claim_results = yield self.wallet.get_claim_by_claim_id(claim_id) + claim_results = yield self.wallet_manager.get_claim_by_claim_id(claim_id) elif txid is not None and nout is not None and claim_id is None: - claim_results = yield self.wallet.get_claim_by_outpoint(txid, int(nout)) + claim_results = yield self.wallet_manager.get_claim_by_outpoint(txid, int(nout)) else: raise Exception("Must specify either txid/nout, or claim_id") response = yield self._render_response(claim_results) @@ -1299,7 +1767,7 @@ class Daemon(AuthJSONRPCServer): except URIParseError: results[u] = {"error": "%s is not a valid uri" % u} - resolved = yield self.wallet.resolve(*valid_uris, check_cache=not force) + resolved = yield self.wallet_manager.resolve(*valid_uris, check_cache=not force) for resolved_uri in resolved: results[resolved_uri] = resolved[resolved_uri] @@ -1360,7 +1828,7 @@ class Daemon(AuthJSONRPCServer): if parsed_uri.is_channel and not parsed_uri.path: raise Exception("cannot download a channel claim, specify a /path") - resolved_result = yield self.wallet.resolve(uri) + resolved_result = yield self.wallet_manager.resolve(uri) if resolved_result and uri in resolved_result: resolved = resolved_result[uri] else: @@ -1559,8 +2027,8 @@ class Daemon(AuthJSONRPCServer): if amount <= 0: raise Exception("Invalid amount") - tx = yield self.wallet.claim_new_channel(channel_name, amount) - self.wallet.save() + tx = yield self.wallet_manager.claim_new_channel(channel_name, amount) + self.wallet_manager.save() self.analytics_manager.send_new_channel() nout = 0 txo = tx.outputs[nout] @@ -1590,28 +2058,10 @@ class Daemon(AuthJSONRPCServer): is in the wallet. """ - result = yield self.wallet.channel_list() + result = yield self.wallet_manager.channel_list() response = yield self._render_response(result) defer.returnValue(response) - @requires(WALLET_COMPONENT) - @AuthJSONRPCServer.deprecated("channel_list") - def jsonrpc_channel_list_mine(self): - """ - Get certificate claim infos for channels that can be published to (deprecated) - - Usage: - channel_list_mine - - Options: - None - - Returns: - (list) ClaimDict - """ - - return self.jsonrpc_channel_list() - @requires(WALLET_COMPONENT) @defer.inlineCallbacks def jsonrpc_channel_export(self, claim_id): @@ -1628,7 +2078,7 @@ class Daemon(AuthJSONRPCServer): (str) Serialized certificate information """ - result = yield self.wallet.export_certificate_info(claim_id) + result = yield self.wallet_manager.export_certificate_info(claim_id) defer.returnValue(result) @requires(WALLET_COMPONENT) @@ -1647,7 +2097,7 @@ class Daemon(AuthJSONRPCServer): (dict) Result dictionary """ - result = yield self.wallet.import_certificate_info(serialized_certificate_info) + result = yield self.wallet_manager.import_certificate_info(serialized_certificate_info) defer.returnValue(result) @requires(WALLET_COMPONENT, FILE_MANAGER_COMPONENT, BLOB_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT, @@ -1750,7 +2200,7 @@ class Daemon(AuthJSONRPCServer): # raises an error if the address is invalid decode_address(address) - available = yield self.wallet.default_account.get_balance() + available = yield self.wallet_manager.default_account.get_balance() if bid >= available: # TODO: add check for existing claim balance #balance = yield self.wallet.get_max_usable_balance_for_claim(name) @@ -1802,7 +2252,7 @@ class Daemon(AuthJSONRPCServer): log.warning("Stripping empty fee from published metadata") del metadata['fee'] elif 'address' not in metadata['fee']: - address = yield self.wallet.default_account.receiving.get_or_create_usable_address() + address = yield self.wallet_manager.default_account.receiving.get_or_create_usable_address() metadata['fee']['address'] = address if 'fee' in metadata and 'version' not in metadata['fee']: metadata['fee']['version'] = '_0_0_1' @@ -1856,7 +2306,7 @@ class Daemon(AuthJSONRPCServer): certificate = None if channel_name: - certificates = yield self.wallet.get_certificates(channel_name) + certificates = yield self.wallet_manager.get_certificates(channel_name) for cert in certificates: if cert.claim_id == channel_id: certificate = cert @@ -1897,7 +2347,7 @@ class Daemon(AuthJSONRPCServer): if nout is None and txid is not None: raise Exception('Must specify nout') - tx = yield self.wallet.abandon_claim(claim_id, txid, nout) + tx = yield self.wallet_manager.abandon_claim(claim_id, txid, nout) self.analytics_manager.send_claim_action('abandon') defer.returnValue({ "success": True, @@ -1929,7 +2379,7 @@ class Daemon(AuthJSONRPCServer): } """ - result = yield self.wallet.support_claim(name, claim_id, amount) + result = yield self.wallet_manager.support_claim(name, claim_id, amount) self.analytics_manager.send_claim_action('new_support') defer.returnValue(result) @@ -1969,11 +2419,11 @@ class Daemon(AuthJSONRPCServer): nout = int(nout) else: raise Exception("invalid outpoint") - result = yield self.wallet.claim_renew(txid, nout) + result = yield self.wallet_manager.claim_renew(txid, nout) result = {outpoint: result} else: height = int(height) - result = yield self.wallet.claim_renew_all_before_expiration(height) + result = yield self.wallet_manager.claim_renew_all_before_expiration(height) defer.returnValue(result) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @@ -2004,7 +2454,7 @@ class Daemon(AuthJSONRPCServer): } """ - result = yield self.wallet.send_claim_to_address(claim_id, address, amount) + result = yield self.wallet_manager.send_claim_to_address(claim_id, address, amount) response = yield self._render_response(result) defer.returnValue(response) @@ -2043,7 +2493,7 @@ class Daemon(AuthJSONRPCServer): ] """ - d = self.wallet.get_name_claims() + d = self.wallet_manager.get_name_claims() d.addCallback(lambda claims: self._render_response(claims)) return d @@ -2082,7 +2532,7 @@ class Daemon(AuthJSONRPCServer): } """ - claims = yield self.wallet.get_claims_for_name(name) # type: dict + claims = yield self.wallet_manager.get_claims_for_name(name) # type: dict sort_claim_results(claims['claims']) defer.returnValue(claims) @@ -2160,7 +2610,7 @@ class Daemon(AuthJSONRPCServer): except URIParseError: results[chan_uri] = {"error": "%s is not a valid uri" % chan_uri} - resolved = yield self.wallet.resolve(*valid_uris, page=page, page_size=page_size) + resolved = yield self.wallet_manager.resolve(*valid_uris, page=page, page_size=page_size) for u in resolved: if 'error' in resolved[u]: results[u] = resolved[u] @@ -2233,7 +2683,7 @@ class Daemon(AuthJSONRPCServer): """ - d = self.wallet.get_history() + d = self.wallet_manager.get_history() d.addCallback(lambda r: self._render_response(r)) return d @@ -2252,209 +2702,10 @@ class Daemon(AuthJSONRPCServer): (dict) JSON formatted transaction """ - d = self.wallet.get_transaction(txid) + d = self.wallet_manager.get_transaction(txid) d.addCallback(lambda r: self._render_response(r)) return d - @requires(WALLET_COMPONENT) - def jsonrpc_wallet_is_address_mine(self, address): - """ - Checks if an address is associated with the current wallet. - - Usage: - wallet_is_address_mine (
| --address=
) - - Options: - --address=
: (str) address to check - - Returns: - (bool) true, if address is associated with current wallet - """ - - d = self.wallet.address_is_mine(address) - d.addCallback(lambda is_mine: self._render_response(is_mine)) - return d - - @requires(WALLET_COMPONENT) - def jsonrpc_wallet_public_key(self, address): - """ - Get public key from wallet address - - Usage: - wallet_public_key (
| --address=
) - - Options: - --address=
: (str) address for which to get the public key - - Returns: - (list) list of public keys associated with address. - Could contain more than one public key if multisig. - """ - - d = self.wallet.get_pub_keys(address) - d.addCallback(lambda r: self._render_response(r)) - return d - - @requires(WALLET_COMPONENT) - @defer.inlineCallbacks - def jsonrpc_wallet_list(self): - """ - List wallet addresses - - Usage: - wallet_list - - Options: - None - - Returns: - List of wallet addresses - """ - - addresses = yield self.wallet.list_addresses() - response = yield self._render_response(addresses) - defer.returnValue(response) - - @requires(WALLET_COMPONENT) - def jsonrpc_wallet_new_address(self): - """ - Generate a new wallet address - - Usage: - wallet_new_address - - Options: - None - - Returns: - (str) New wallet address in base58 - """ - - def _disp(address): - log.info("Got new wallet address: " + address) - return defer.succeed(address) - - d = self.wallet.get_new_address() - d.addCallback(_disp) - d.addCallback(lambda address: self._render_response(address)) - return d - - @requires(WALLET_COMPONENT) - def jsonrpc_wallet_unused_address(self): - """ - Return an address containing no balance, will create - a new address if there is none. - - Usage: - wallet_unused_address - - Options: - None - - Returns: - (str) Unused wallet address in base58 - """ - - def _disp(address): - address = str(address) - log.info("Got unused wallet address: " + address) - return defer.succeed(address) - - d = self.wallet.get_unused_address() - d.addCallback(_disp) - d.addCallback(lambda address: self._render_response(address)) - return d - - @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - @defer.inlineCallbacks - def jsonrpc_wallet_send(self, amount, address=None, claim_id=None): - """ - Send credits. If given an address, send credits to it. If given a claim id, send a tip - to the owner of a claim specified by uri. A tip is a claim support where the recipient - of the support is the claim address for the claim being supported. - - Usage: - wallet_send ( | --amount=) - ((
| --address=
) | ( | --claim_id=)) - - Options: - --amount= : (Decimal) amount of credit to send - --address=
: (str) address to send credits to - --claim_id= : (str) claim_id of the claim to send to tip to - - Returns: - If sending to an address: - (dict) true if payment successfully scheduled - { - "hex": (str) raw transaction, - "inputs": (list) inputs(dict) used for the transaction, - "outputs": (list) outputs(dict) for the transaction, - "total_fee": (int) fee in dewies, - "total_input": (int) total of inputs in dewies, - "total_output": (int) total of outputs in dewies(input - fees), - "txid": (str) txid of the transaction, - } - - If sending a claim tip: - (dict) Dictionary containing the result of the support - { - txid : (str) txid of resulting support claim - nout : (int) nout of the resulting support claim - fee : (float) fee paid for the transaction - } - """ - - amount = self.get_dewies_or_error("amount", amount) - if not amount: - raise NullFundsError - elif amount < 0: - raise NegativeFundsError() - - if address and claim_id: - raise Exception("Given both an address and a claim id") - elif not address and not claim_id: - raise Exception("Not given an address or a claim id") - - if address: - # raises an error if the address is invalid - decode_address(address) - - reserved_points = self.wallet.reserve_points(address, amount) - if reserved_points is None: - raise InsufficientFundsError() - result = yield self.wallet.send_points_to_address(reserved_points, amount) - self.analytics_manager.send_credits_sent() - else: - validate_claim_id(claim_id) - result = yield self.wallet.tip_claim(claim_id, amount) - self.analytics_manager.send_claim_action('new_support') - defer.returnValue(result) - - @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - def jsonrpc_wallet_prefill_addresses(self, num_addresses, amount, no_broadcast=False): - """ - Create new UTXOs, each containing `amount` credits - - Usage: - wallet_prefill_addresses [--no_broadcast] - ( | --num_addresses=) - ( | --amount=) - - Options: - --no_broadcast : (bool) whether to broadcast or not - --num_addresses= : (int) num of addresses to create - --amount= : (float) initial amount in each address - - Returns: - (dict) the resulting transaction - """ - broadcast = not no_broadcast - return self.jsonrpc_fund(self.wallet.default_account.name, - self.wallet.default_account.name, - amount=amount * num_addresses, - outputs=num_addresses, - broadcast=broadcast) - @requires(WALLET_COMPONENT) @defer.inlineCallbacks def jsonrpc_utxo_list(self): @@ -2485,7 +2736,7 @@ class Daemon(AuthJSONRPCServer): ] """ - unspent = yield self.wallet.list_unspent() + unspent = yield self.wallet_manager.list_unspent() for i, utxo in enumerate(unspent): utxo['txid'] = utxo.pop('prevout_hash') utxo['nout'] = utxo.pop('prevout_n') @@ -2723,7 +2974,7 @@ class Daemon(AuthJSONRPCServer): """ if uri or stream_hash or sd_hash: if uri: - metadata = (yield self.wallet.resolve(uri))[uri] + metadata = (yield self.wallet_manager.resolve(uri))[uri] sd_hash = utils.get_sd_hash(metadata) stream_hash = yield self.storage.get_stream_hash_for_sd_hash(sd_hash) elif stream_hash: @@ -2923,27 +3174,6 @@ class Daemon(AuthJSONRPCServer): return self._blob_availability(blob_hash, search_timeout, blob_timeout) - @requires(UPNP_COMPONENT, WALLET_COMPONENT, DHT_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - @AuthJSONRPCServer.deprecated("stream_availability") - def jsonrpc_get_availability(self, uri, sd_timeout=None, peer_timeout=None): - """ - Get stream availability for lbry uri - - Usage: - get_availability ( | --uri=) [ | --sd_timeout=] - [ | --peer_timeout=] - - Options: - --uri= : (str) check availability for this uri - --sd_timeout= : (int) sd blob download timeout - --peer_timeout= : (int) how long to look for peers - - Returns: - (float) Peers per blob / total blobs - """ - - return self.jsonrpc_stream_availability(uri, peer_timeout, sd_timeout) - @requires(UPNP_COMPONENT, WALLET_COMPONENT, DHT_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @defer.inlineCallbacks def jsonrpc_stream_availability(self, uri, search_timeout=None, blob_timeout=None): @@ -2997,7 +3227,7 @@ class Daemon(AuthJSONRPCServer): } try: - resolved_result = (yield self.wallet.resolve(uri))[uri] + resolved_result = (yield self.wallet_manager.resolve(uri))[uri] response['did_resolve'] = True except UnknownNameError: response['error'] = "Failed to resolve name" @@ -3047,220 +3277,9 @@ class Daemon(AuthJSONRPCServer): response['head_blob_availability'].get('is_available') defer.returnValue(response) - ####################### - # New Wallet Commands # - ####################### - # TODO: - # Delete this after all commands have been migrated - # and refactored. - @requires("wallet") - def jsonrpc_account(self, account_name, create=False, delete=False, single_key=False, - seed=None, private_key=None, public_key=None, - change_gap=None, change_max_uses=None, - receiving_gap=None, receiving_max_uses=None, - rename=None, default=False): - """ - Create new account or update some settings on an existing account. If no - creation or modification options are provided but the account exists then - it will just displayed the unmodified settings for the account. - - Usage: - account [--create | --delete] ( | --account_name=) [--single_key] - [--seed= | --private_key= | --public_key=] - [--change_gap=] [--change_max_uses=] - [--receiving_gap=] [--receiving_max_uses=] - [--rename=] [--default] - - Options: - --account_name= : (str) name of the account to create or update - --create : (bool) create the account - --delete : (bool) delete the account - --single_key : (bool) create single key account, default is multi-key - --seed= : (str) seed to generate new account from - --private_key= : (str) private key for new account - --public_key= : (str) public key for new account - --receiving_gap= : (int) set the gap for receiving addresses - --receiving_max_uses= : (int) set the maximum number of times to - use a receiving address - --change_gap= : (int) set the gap for change addresses - --change_max_uses= : (int) set the maximum number of times to - use a change address - --rename= : (str) change name of existing account - --default : (bool) make this account the default - - Returns: - (map) new or updated account details - - """ - wallet = self.wallet.default_wallet - if create: - self.error_if_account_exists(account_name) - if single_key: - address_generator = {'name': SingleKey.name} - else: - address_generator = { - 'name': HierarchicalDeterministic.name, - 'receiving': { - 'gap': receiving_gap or 20, - 'maximum_uses_per_address': receiving_max_uses or 1}, - 'change': { - 'gap': change_gap or 6, - 'maximum_uses_per_address': change_max_uses or 1} - } - ledger = self.wallet.get_or_create_ledger('lbc_mainnet') - if seed or private_key or public_key: - account = LBCAccount.from_dict(ledger, wallet, { - 'name': account_name, - 'seed': seed, - 'private_key': private_key, - 'public_key': public_key, - 'address_generator': address_generator - }) - else: - account = LBCAccount.generate( - ledger, wallet, account_name, address_generator) - wallet.save() - elif delete: - account = self.get_account_or_error('account_name', account_name) - wallet.accounts.remove(account) - wallet.save() - return "Account '{}' deleted.".format(account_name) - else: - change_made = False - account = self.get_account_or_error('account_name', account_name) - if rename is not None: - self.error_if_account_exists(rename) - account.name = rename - change_made = True - if account.receiving.name == HierarchicalDeterministic.name: - address_changes = { - 'change': {'gap': change_gap, 'maximum_uses_per_address': change_max_uses}, - 'receiving': {'gap': receiving_gap, 'maximum_uses_per_address': receiving_max_uses}, - } - for chain_name in address_changes: - chain = getattr(account, chain_name) - for attr, value in address_changes[chain_name].items(): - if value is not None: - setattr(chain, attr, value) - change_made = True - if change_made: - wallet.save() - - if default: - wallet.accounts.remove(account) - wallet.accounts.insert(0, account) - wallet.save() - - result = account.to_dict() - result.pop('certificates', None) - result['is_default'] = wallet.accounts[0] == account - return result - - @requires("wallet") - def jsonrpc_balance(self, account_name=None, confirmations=6, include_reserved=False, - include_claims=False): - """ - Return the balance of an individual account or all of the accounts. - - Usage: - balance [] [--confirmations=] - [--include_reserved] [--include_claims] - - Options: - --account= : (str) If provided only the balance for this - account will be given - --confirmations= : (int) required confirmations (default: 6) - --include_reserved : (bool) include reserved UTXOs (default: false) - --include_claims : (bool) include claims, requires than a - LBC account is specified (default: false) - - Returns: - (map) balance of account(s) - """ - if account_name: - for account in self.wallet.accounts: - if account.name == account_name: - if include_claims and not isinstance(account, LBCAccount): - raise Exception( - "'--include-claims' requires specifying an LBC ledger account. " - "Found '{}', but it's an {} ledger account." - .format(account_name, account.ledger.symbol) - ) - args = { - 'confirmations': confirmations, - 'include_reserved': include_reserved - } - if include_claims: - args['include_claims'] = True - return account.get_balance(**args) - raise Exception("Couldn't find an account named: '{}'.".format(account_name)) - else: - if include_claims: - raise Exception("'--include-claims' requires specifying an LBC account.") - return self.wallet.get_balances(confirmations) - - @requires("wallet") - def jsonrpc_max_address_gap(self, account_name): - """ - Finds ranges of consecutive addresses that are unused and returns the length - of the longest such range: for change and receiving address chains. This is - useful to figure out ideal values to set for 'receiving_gap' and 'change_gap' - account settings. - - Usage: - max_address_gap ( | --account=) - - Options: - --account= : (str) account for which to get max gaps - - Returns: - (map) maximum gap for change and receiving addresses - """ - return self.get_account_or_error('account', account_name).get_max_gap() - - @requires("wallet") - def jsonrpc_fund(self, to_account, from_account, amount=0, - everything=False, outputs=1, broadcast=False): - """ - Transfer some amount (or --everything) to an account from another - account (can be the same account). Amounts are interpreted as LBC. - You can also spread the transfer across a number of --outputs (cannot - be used together with --everything). - - Usage: - fund ( | --to_account=) - ( | --from_account=) - ( | --amount= | --everything) - [ | --outputs=] - [--broadcast] - - Options: - --to_account= : (str) send to this account - --from_account= : (str) spend from this account - --amount= : (str) the amount to transfer lbc - --everything : (bool) transfer everything (excluding claims), default: false. - --outputs= : (int) split payment across many outputs, default: 1. - --broadcast : (bool) actually broadcast the transaction, default: false. - - Returns: - (map) maximum gap for change and receiving addresses - - """ - to_account = self.get_account_or_error('to_account', to_account) - from_account = self.get_account_or_error('from_account', from_account) - amount = self.get_dewies_or_error('amount', amount) if amount else None - if not isinstance(outputs, int): - raise ValueError("--outputs must be an integer.") - if everything and outputs > 1: - raise ValueError("Using --everything along with --outputs is not supported.") - return from_account.fund( - to_account=to_account, amount=amount, everything=everything, - outputs=outputs, broadcast=broadcast - ) - - def get_account_or_error(self, argument: str, account_name: str, lbc_only=False): - for account in self.wallet.default_wallet.accounts: + def get_account_or_error(self, argument: str, account_name: str, lbc_only=True): + for account in self.wallet_manager.default_wallet.accounts: if account.name == account_name: if lbc_only and not isinstance(account, LBCAccount): raise ValueError( @@ -3272,7 +3291,7 @@ class Daemon(AuthJSONRPCServer): raise ValueError("Couldn't find an account named: '{}'.".format(account_name)) def error_if_account_exists(self, account_name: str): - for account in self.wallet.default_wallet.accounts: + for account in self.wallet_manager.default_wallet.accounts: if account.name == account_name: raise ValueError("Account with name '{}' already exists.".format(account_name)) diff --git a/tests/integration/wallet/test_commands.py b/tests/integration/wallet/test_commands.py index 426604b8b..b5e43c74f 100644 --- a/tests/integration/wallet/test_commands.py +++ b/tests/integration/wallet/test_commands.py @@ -111,7 +111,7 @@ class CommandTestCase(IntegrationTestCase): def wallet_maker(component_manager): self.wallet_component = WalletComponent(component_manager) - self.wallet_component.wallet = self.manager + self.wallet_component.wallet_manager = self.manager self.wallet_component._running = True return self.wallet_component @@ -131,7 +131,7 @@ class CommandTestCase(IntegrationTestCase): #for component in skip: # self.daemon.component_attributes.pop(component, None) await d2f(self.daemon.setup()) - self.daemon.wallet = self.wallet_component.wallet + self.daemon.wallet_manager = self.wallet_component.wallet self.manager.old_db = self.daemon.storage async def tearDown(self): diff --git a/tests/unit/lbrynet_daemon/test_Daemon.py b/tests/unit/lbrynet_daemon/test_Daemon.py index ed8fb2d8b..64e1ce83c 100644 --- a/tests/unit/lbrynet_daemon/test_Daemon.py +++ b/tests/unit/lbrynet_daemon/test_Daemon.py @@ -50,10 +50,10 @@ def get_test_daemon(data_rate=None, generous=True, with_fee=False): ) daemon = LBRYDaemon(component_manager=component_manager) daemon.payment_rate_manager = OnlyFreePaymentsManager() - daemon.wallet = mock.Mock(spec=LbryWalletManager) - daemon.wallet.wallet = mock.Mock(spec=Wallet) - daemon.wallet.wallet.use_encryption = False - daemon.wallet.network = FakeNetwork() + daemon.wallet_manager = mock.Mock(spec=LbryWalletManager) + daemon.wallet_manager.wallet = mock.Mock(spec=Wallet) + daemon.wallet_manager.wallet.use_encryption = False + daemon.wallet_manager.network = FakeNetwork() daemon.storage = mock.Mock(spec=SQLiteStorage) market_feeds = [BTCLBCFeed(), USDBTCFeed()] daemon.exchange_rate_manager = DummyExchangeRateManager(market_feeds, rates) @@ -79,7 +79,7 @@ def get_test_daemon(data_rate=None, generous=True, with_fee=False): metadata.update( {"fee": {"USD": {"address": "bQ6BGboPV2SpTMEP7wLNiAcnsZiH8ye6eA", "amount": 0.75}}}) migrated = smart_decode(json.dumps(metadata)) - daemon._resolve = daemon.wallet.resolve = lambda *_: defer.succeed( + daemon._resolve = daemon.wallet_manager.resolve = lambda *_: defer.succeed( {"test": {'claim': {'value': migrated.claim_dict}}}) return daemon @@ -135,8 +135,8 @@ class TestJsonRpc(unittest.TestCase): mock_conf_settings(self) util.resetTime(self) self.test_daemon = get_test_daemon() - self.test_daemon.wallet.is_first_run = False - self.test_daemon.wallet.get_best_blockhash = noop + self.test_daemon.wallet_manager.is_first_run = False + self.test_daemon.wallet_manager.get_best_blockhash = noop def test_status(self): d = defer.maybeDeferred(self.test_daemon.jsonrpc_status)