From c9c88055c3ae57100e7807e19ada574c00c27dad Mon Sep 17 00:00:00 2001 From: Mathew WAller Date: Sun, 23 Apr 2017 18:33:06 +0100 Subject: [PATCH] Requested changes --- CHANGELOG.md | 10 +-- build/requirements_base.txt | 29 +++++++ lbrynet/core/Wallet.py | 140 ++++++++++++------------------- lbrynet/lbrynet_daemon/Daemon.py | 19 ++++- 4 files changed, 101 insertions(+), 97 deletions(-) create mode 100644 build/requirements_base.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 807c150cc..5fca2eb1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,18 +10,16 @@ at anytime. ## [Unreleased] ### Added * Add `lbryschema_version` to response from `version` - * Added functionality to check the balance of a given address. - * + * Added call to `get_address_balance` when `address` conditional returns true + * Added `address` conditional to `jsonrpc_wallet_balance` + * Added `get_address_balance` method to the `Wallet` class ### Changed - * - * - * + * Added optional `address` and `include_unconfirmed` params to `jsonrpc_wallet_balance` method ### Fixed * fix stream_cost_estimate throwing exception on non decodeable claims * - * ## [0.10.0rc2] - 2017-04-17 ### Changed diff --git a/build/requirements_base.txt b/build/requirements_base.txt new file mode 100644 index 000000000..b020601af --- /dev/null +++ b/build/requirements_base.txt @@ -0,0 +1,29 @@ +Twisted==16.6.0 +appdirs==1.4.3 +argparse==1.2.1 +base58==0.2.2 +colorama==0.3.7 +dnspython==1.12.0 +ecdsa==0.13 +envparse==0.2.0 +gmpy==1.17 +jsonrpc==1.2 +jsonrpclib==0.1.7 +jsonschema==2.5.1 +git+https://github.com/lbryio/lbryschema.git@v0.0.3#egg=lbryschema +git+https://github.com/lbryio/lbryum.git@v2.7.20#egg=lbryum +miniupnpc==1.9 +pbkdf2==1.3 +protobuf==3.0.0 +pycrypto==2.6.1 +pyyaml==3.12 +qrcode==5.2.2 +requests==2.9.1 +txrequests==0.9.5 +seccure==0.3.1.3 +service_identity==16.0.0 +six>=1.9.0 +slowaes==0.1a1 +txJSON-RPC==0.5 +wsgiref==0.1.2 +zope.interface==4.3.3 diff --git a/lbrynet/core/Wallet.py b/lbrynet/core/Wallet.py index 6758d42dc..2a3808900 100644 --- a/lbrynet/core/Wallet.py +++ b/lbrynet/core/Wallet.py @@ -29,14 +29,12 @@ log = logging.getLogger(__name__) class ReservedPoints(object): - def __init__(self, identifier, amount): self.identifier = identifier self.amount = amount class ClaimOutpoint(dict): - def __init__(self, txid, nout): if len(txid) != 64: raise TypeError('{} is not a txid'.format(txid)) @@ -63,7 +61,6 @@ class ClaimOutpoint(dict): class MetaDataStorage(object): - def load(self): return defer.succeed(True) @@ -84,7 +81,6 @@ class MetaDataStorage(object): class InMemoryStorage(MetaDataStorage): - def __init__(self): self.metadata = {} self.claimids = {} @@ -102,8 +98,7 @@ class InMemoryStorage(MetaDataStorage): return defer.succeed(None) def update_claimid(self, claim_id, name, claim_outpoint): - self.claimids[ - (name, claim_outpoint['txid'], claim_outpoint['nout'])] = claim_id + self.claimids[(name, claim_outpoint['txid'], claim_outpoint['nout'])] = claim_id return defer.succeed(True) def get_claimid_for_tx(self, name, claim_outpoint): @@ -115,15 +110,13 @@ class InMemoryStorage(MetaDataStorage): class SqliteStorage(MetaDataStorage): - def __init__(self, db_dir): self.db_dir = db_dir self.db = None MetaDataStorage.__init__(self) def load(self): - self.db = adbapi.ConnectionPool( - 'sqlite3', os.path.join(self.db_dir, "blockchainname.db"), + self.db = adbapi.ConnectionPool('sqlite3', os.path.join(self.db_dir, "blockchainname.db"), check_same_thread=False) def create_tables(transaction): @@ -141,8 +134,7 @@ class SqliteStorage(MetaDataStorage): return self.db.runInteraction(create_tables) def clean_bad_records(self): - d = self.db.runQuery( - "delete from name_metadata where length(txid) > 64 or txid is null") + d = self.db.runQuery("delete from name_metadata where length(txid) > 64 or txid is null") return d def save_name_metadata(self, name, claim_outpoint, sd_hash): @@ -161,8 +153,7 @@ class SqliteStorage(MetaDataStorage): @rerun_if_locked def get_claim_metadata_for_sd_hash(self, sd_hash): - d = self.db.runQuery( - "select name, txid, n from name_metadata where sd_hash=?", (sd_hash,)) + d = self.db.runQuery("select name, txid, n from name_metadata where sd_hash=?", (sd_hash,)) d.addCallback(lambda r: r[0] if r else None) return d @@ -190,7 +181,6 @@ class SqliteStorage(MetaDataStorage): class Wallet(object): - """This class implements the Wallet interface for the LBRYcrd payment system""" implements(IWallet) @@ -202,10 +192,8 @@ class Wallet(object): self.wallet_balance = Decimal(0.0) self.total_reserved_points = Decimal(0.0) self.peer_addresses = {} # {Peer: string} - self.queued_payments = defaultdict( - Decimal) # {address(string): amount(Decimal)} - self.expected_balances = defaultdict( - Decimal) # {address(string): amount(Decimal)} + self.queued_payments = defaultdict(Decimal) # {address(string): amount(Decimal)} + self.expected_balances = defaultdict(Decimal) # {address(string): amount(Decimal)} self.current_address_given_to_peer = {} # {Peer: address(string)} # (Peer, address(string), amount(Decimal), time(datetime), count(int), # incremental_amount(float)) @@ -247,8 +235,7 @@ class Wallet(object): @staticmethod def log_stop_error(err): - log.error( - "An error occurred stopping the wallet: %s", err.getTraceback()) + log.error("An error occurred stopping the wallet: %s", err.getTraceback()) def stop(self): log.info("Stopping %s", self) @@ -302,8 +289,7 @@ class Wallet(object): def log_error(err): if isinstance(err, AttributeError): log.warning("Failed to get an updated balance") - log.warning( - "Last balance update: %s", str(self.wallet_balance)) + log.warning("Last balance update: %s", str(self.wallet_balance)) d.addCallbacks(lambda _: self.update_balance(), log_error) return d @@ -312,8 +298,7 @@ class Wallet(object): def set_next_manage_call(): if not self.stopped: - self.next_manage_call = reactor.callLater( - self._balance_refresh_time, self.manage) + self.next_manage_call = reactor.callLater(self._balance_refresh_time, self.manage) d.addCallback(lambda _: set_next_manage_call()) @@ -426,8 +411,7 @@ class Wallet(object): str(address), str(rounded_amount)) self.expected_balances[address] += rounded_amount expected_balance = self.expected_balances[address] - expected_time = datetime.datetime.now( - ) + self.max_expected_payment_time + expected_time = datetime.datetime.now() + self.max_expected_payment_time self.expected_balance_at_time.append( (peer, address, expected_balance, expected_time, 0, amount)) peer.update_stats('expected_points', amount) @@ -448,8 +432,7 @@ class Wallet(object): payments_to_send = {} for address, points in self.queued_payments.items(): if points > 0: - log.debug( - "Should be sending %s points to %s", str(points), str(address)) + log.debug("Should be sending %s points to %s", str(points), str(address)) payments_to_send[address] = points self.total_reserved_points -= points else: @@ -458,8 +441,7 @@ class Wallet(object): del self.queued_payments[address] if payments_to_send: - log.debug( - "Creating a transaction with outputs %s", str(payments_to_send)) + log.debug("Creating a transaction with outputs %s", str(payments_to_send)) d = self._do_send_many(payments_to_send) d.addCallback(lambda txid: log.debug("Sent transaction %s", txid)) return d @@ -467,7 +449,7 @@ class Wallet(object): log.debug("There were no payments to send") return defer.succeed(True) - # + ###### @defer.inlineCallbacks def get_claim(self, claim_id): @@ -483,8 +465,7 @@ class Wallet(object): claim['hex'] = claim['value'] claim['value'] = None claim['error'] = "Failed to decode" - log.warning( - "Failed to decode claim value for lbry://%s#%s", claim['name'], + log.warning("Failed to decode claim value for lbry://%s#%s", claim['name'], claim['claim_id']) defer.returnValue(claim) @@ -595,8 +576,7 @@ class Wallet(object): results['hex'] = claim_hex results['value'] = claim_dict - log.info("get claim info lbry://%s#%s", - results['name'], results['claim_id']) + log.info("get claim info lbry://%s#%s", results['name'], results['claim_id']) defer.returnValue(results) @defer.inlineCallbacks @@ -646,9 +626,7 @@ class Wallet(object): claim['hex'] = claim['value'] claim['value'] = None claim['error'] = "Failed to decode" - log.warning( - "Failed to decode claim value for lbry://%s#%s", claim[ - 'name'], + log.warning("Failed to decode claim value for lbry://%s#%s", claim['name'], claim['claim_id']) claims_for_return.append(claim) @@ -666,8 +644,7 @@ class Wallet(object): raise Exception("Invalid channel name") elif (parsed_channel_name.path or parsed_channel_name.claim_id or parsed_channel_name.bid_position or parsed_channel_name.claim_sequence): - raise Exception( - "New channel claim should have no fields other than name") + raise Exception("New channel claim should have no fields other than name") log.info("Preparing to make certificate claim for %s", channel_name) return self._claim_certificate(parsed_channel_name.name, amount) @@ -711,8 +688,7 @@ class Wallet(object): claim = self._process_claim_out(claim) claim_outpoint = ClaimOutpoint(claim['txid'], claim['nout']) - log.info("Saving metadata for claim %s %d", - claim['txid'], claim['nout']) + log.info("Saving metadata for claim %s %d", claim['txid'], claim['nout']) yield self._update_claimid(claim['claim_id'], name, claim_outpoint) yield self._save_name_metadata(name, claim_outpoint, decoded.source_hash) defer.returnValue(claim) @@ -722,8 +698,7 @@ class Wallet(object): claim_out = yield self._abandon_claim(claim_id) if not claim_out['success']: - msg = 'Abandon of {} failed: {}'.format( - claim_id, claim_out['reason']) + msg = 'Abandon of {} failed: {}'.format(claim_id, claim_out['reason']) raise Exception(msg) claim_out = self._process_claim_out(claim_out) @@ -732,8 +707,7 @@ class Wallet(object): def support_claim(self, name, claim_id, amount): def _parse_support_claim_out(claim_out): if not claim_out['success']: - msg = 'Support of {}:{} failed: {}'.format( - name, claim_id, claim_out['reason']) + msg = 'Support of {}:{} failed: {}'.format(name, claim_id, claim_out['reason']) raise Exception(msg) claim_out = self._process_claim_out(claim_out) return defer.succeed(claim_out) @@ -764,26 +738,20 @@ class Wallet(object): def get_claim_metadata_for_sd_hash(self, sd_hash): return self._get_claim_metadata_for_sd_hash(sd_hash) - def get_balance(self, address=None): - if address is None: - return self.wallet_balance-self.total_reserved_points-sum(self.queued_payments.values()) - else: - c, u, x = self.wallet.get_addr_balance(address) - return Decimal(float(c) / COIN) + def get_balance(self): + return self.wallet_balance - self.total_reserved_points - sum(self.queued_payments.values()) def _check_expected_balances(self): now = datetime.datetime.now() balances_to_check = [] try: while self.expected_balance_at_time[0][3] < now: - balances_to_check.append( - self.expected_balance_at_time.popleft()) + balances_to_check.append(self.expected_balance_at_time.popleft()) except IndexError: pass ds = [] for balance_to_check in balances_to_check: - log.debug( - "Checking balance of address %s", str(balance_to_check[1])) + log.debug("Checking balance of address %s", str(balance_to_check[1])) d = self._get_balance_for_address(balance_to_check[1]) d.addCallback(lambda bal: bal >= balance_to_check[2]) ds.append(d) @@ -800,13 +768,11 @@ class Wallet(object): balance[0], balance[1], balance[2], - datetime.datetime.now() + - self.max_expected_payment_time, + datetime.datetime.now() + self.max_expected_payment_time, balance[4] + 1, balance[5] ) - self.expected_balance_at_time.append( - new_expected_balance) + self.expected_balance_at_time.append(new_expected_balance) peer.update_score(-5.0) else: peer.update_score(-50.0) @@ -817,8 +783,7 @@ class Wallet(object): else: log.warning("Something went wrong checking a balance. Peer: %s, account: %s," "expected balance: %s, expected time: %s, count: %s, error: %s", - str(balance[0]), str(balance[1]), str( - balance[2]), str(balance[3]), + str(balance[0]), str(balance[1]), str(balance[2]), str(balance[3]), str(balance[4]), str(result.getErrorMessage())) dl.addCallback(handle_checks) @@ -832,6 +797,9 @@ class Wallet(object): def get_new_address(self): return defer.fail(NotImplementedError()) + def get_address_balance(self, address): + return defer.fail(NotImplementedError()) + def get_block(self, blockhash): return defer.fail(NotImplementedError()) @@ -897,7 +865,6 @@ class Wallet(object): class LBRYumWallet(Wallet): - def __init__(self, storage, config=None): Wallet.__init__(self, storage) self._config = config @@ -928,8 +895,7 @@ class LBRYumWallet(Wallet): 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.") + 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() @@ -937,8 +903,7 @@ class LBRYumWallet(Wallet): if self.network.is_connected(): network_start_d.callback(True) else: - network_start_d.errback( - ValueError("Failed to connect to network.")) + network_start_d.errback(ValueError("Failed to connect to network.")) self._start_check = task.LoopingCall(check_started) @@ -994,9 +959,8 @@ class LBRYumWallet(Wallet): def _check_large_wallet(self): if len(self.wallet.addresses(include_change=False)) > 1000: - log.warning( - ("Your wallet is excessively large, please follow instructions here: ", - "https://github.com/lbryio/lbry/issues/437 to reduce your wallet size")) + log.warning(("Your wallet is excessively large, please follow instructions here: ", + "https://github.com/lbryio/lbry/issues/437 to reduce your wallet size")) def _load_blockchain(self): blockchain_caught_d = defer.Deferred() @@ -1041,7 +1005,7 @@ class LBRYumWallet(Wallet): # 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 + # 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 = known_commands[command_name] @@ -1051,8 +1015,7 @@ class LBRYumWallet(Wallet): def _update_balance(self): accounts = None exclude_claimtrietx = True - d = self._run_cmd_as_defer_succeed( - 'getbalance', accounts, exclude_claimtrietx) + 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 @@ -1064,6 +1027,16 @@ class LBRYumWallet(Wallet): yield self._save_wallet() defer.returnValue(addr) + # 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) + + # Return an address with no balance in it, if # there is none, create a brand new address @defer.inlineCallbacks @@ -1107,8 +1080,7 @@ class LBRYumWallet(Wallet): @defer.inlineCallbacks def _send_name_claim(self, name, value, amount, certificate_id=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, + claim_out = yield self._run_cmd_as_defer_succeed('claim', name, value, amount, certificate_id=certificate_id) defer.returnValue(claim_out) @@ -1129,8 +1101,7 @@ class LBRYumWallet(Wallet): @defer.inlineCallbacks def _broadcast_claim_transaction(self, claim_out): if 'success' not in claim_out: - raise Exception( - 'Unexpected claim command output: {}'.format(claim_out)) + raise Exception('Unexpected claim command output: {}'.format(claim_out)) if claim_out['success']: yield self._broadcast_transaction(claim_out['tx']) defer.returnValue(claim_out) @@ -1146,14 +1117,11 @@ class LBRYumWallet(Wallet): def _do_send_many(self, payments_to_send): def broadcast_send_many(paytomany_out): if 'hex' not in paytomany_out: - raise Exception( - 'Unepxected paytomany output:{}'.format(paytomany_out)) + raise Exception('Unepxected paytomany output:{}'.format(paytomany_out)) return self._broadcast_transaction(paytomany_out['hex']) - log.debug( - "Doing send many. payments to send: %s", str(payments_to_send)) - d = self._run_cmd_as_defer_succeed( - 'paytomany', payments_to_send.iteritems()) + log.debug("Doing send many. payments to send: %s", str(payments_to_send)) + d = self._run_cmd_as_defer_succeed('paytomany', payments_to_send.iteritems()) d.addCallback(lambda out: broadcast_send_many(out)) return d @@ -1240,8 +1208,7 @@ class LBRYcrdAddressRequester(object): def _request_failed(self, err, peer): if not err.check(RequestCanceledError): - log.warning( - "A peer failed to send a valid public key response. Error: %s, peer: %s", + log.warning("A peer failed to send a valid public key response. Error: %s, peer: %s", err.getErrorMessage(), str(peer)) return err @@ -1292,8 +1259,7 @@ class LBRYcrdAddressQueryHandler(object): d.addCallback(create_response) return d if self.address is None: - log.warning( - "Expected a request for an address, but did not receive one") + log.warning("Expected a request for an address, but did not receive one") return defer.fail( Failure(ValueError("Expected but did not receive an address request"))) else: diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index 8f2549901..6e8553a83 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -740,6 +740,7 @@ class Daemon(AuthJSONRPCServer): @defer.inlineCallbacks def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate_id=None): + publisher = Publisher(self.session, self.lbry_file_manager, self.session.wallet, certificate_id) verify_name_characters(name) @@ -1310,20 +1311,30 @@ class Daemon(AuthJSONRPCServer): if 'DEPRECATED' not in getattr(self, "jsonrpc_" + command).__doc__] )) - def jsonrpc_get_balance(self): + def jsonrpc_get_balance(self, address=None, include_unconfirmed=False): """ DEPRECATED. Use `wallet_balance` instead. """ - return self.jsonrpc_wallet_balance() + return self.jsonrpc_wallet_balance(address, include_unconfirmed) - def jsonrpc_wallet_balance(self): + def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False): """ Return the balance of the wallet + Args: + 'address' (optional): If address is provided only that balance will be given + 'include_unconfirmed' (optional): If set unconfirmed balance will be included in + the only takes effect when address is also provided. + Returns: (float) amount of lbry credits in wallet """ - return self._render_response(float(self.session.wallet.get_balance())) + if address is None: + return self._render_response(float(self.session.wallet.get_balance())) + else: + return self._render_response(float( + self.session.wallet.get_address_balance(address, include_unconfirmed))) + def jsonrpc_stop(self): """