From 9749da46aeb887acaa8762c9ebde603488dbbded Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sat, 21 Mar 2020 23:44:57 -0400 Subject: [PATCH 1/5] added flags to resolve: --include_purchase_receipt, --include_is_my_output, --include_my_supports, --include_my_tips --- lbry/extras/daemon/daemon.py | 24 ++++++++--- lbry/extras/daemon/json_response_encoder.py | 4 ++ lbry/testcase.py | 13 ++++-- lbry/wallet/database.py | 10 ++--- lbry/wallet/ledger.py | 41 +++++++++++++++--- lbry/wallet/transaction.py | 5 ++- .../blockchain/test_resolve_command.py | 43 +++++++++++++++++++ 7 files changed, 119 insertions(+), 21 deletions(-) diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index cb3fbf2d9..1220092d7 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -920,16 +920,28 @@ class Daemon(metaclass=JSONRPCServerType): return self.platform_info @requires(WALLET_COMPONENT) - async def jsonrpc_resolve(self, urls: typing.Union[str, list], wallet_id=None): + async def jsonrpc_resolve(self, urls: typing.Union[str, list], wallet_id=None, **kwargs): """ Get the claim that a URL refers to. Usage: resolve ... [--wallet_id=] + [--include_purchase_receipt] + [--include_is_my_output] + [--include_my_supports] + [--include_my_tips] Options: - --urls= : (str, list) one or more urls to resolve - --wallet_id= : (str) wallet to check for claim purchase reciepts + --urls= : (str, list) one or more urls to resolve + --wallet_id= : (str) wallet to check for claim purchase reciepts + --include_purchase_receipt : (bool) lookup and include a receipt if this wallet + has purchased the claim being resolved + --include_is_my_output : (bool) lookup and include a boolean indicating + if claim being resolved is yours + --include_my_supports : (bool) lookup and sum the total amount + of supports you've made to this claim + --include_my_tips : (bool) lookup and sum the total amount + of tips you've made to this claim Returns: Dictionary of results, keyed by url @@ -1002,7 +1014,7 @@ class Daemon(metaclass=JSONRPCServerType): except ValueError: results[url] = {"error": f"{url} is not a valid url"} - resolved = await self.resolve(wallet.accounts, list(valid_urls)) + resolved = await self.resolve(wallet.accounts, list(valid_urls), **kwargs) for resolved_uri in resolved: results[resolved_uri] = resolved[resolved_uri] if resolved[resolved_uri] is not None else \ @@ -5100,8 +5112,8 @@ class Daemon(metaclass=JSONRPCServerType): except ValueError as e: raise ValueError(f"Invalid value for '{argument}': {e.args[0]}") - async def resolve(self, accounts, urls): - results = await self.ledger.resolve(accounts, urls) + async def resolve(self, accounts, urls, **kwargs): + results = await self.ledger.resolve(accounts, urls, **kwargs) if self.conf.save_resolved_claims and results: try: claims = self.stream_manager._convert_to_old_resolve_output(self.wallet_manager, results) diff --git a/lbry/extras/daemon/json_response_encoder.py b/lbry/extras/daemon/json_response_encoder.py index da87da92e..63714a0e1 100644 --- a/lbry/extras/daemon/json_response_encoder.py +++ b/lbry/extras/daemon/json_response_encoder.py @@ -174,6 +174,10 @@ class JSONResponseEncoder(JSONEncoder): output['is_my_output'] = txo.is_my_output if txo.is_my_input is not None: output['is_my_input'] = txo.is_my_input + if txo.my_supports is not None: + output['my_supports'] = dewies_to_lbc(txo.my_supports) + if txo.my_tips is not None: + output['my_tips'] = dewies_to_lbc(txo.my_tips) if txo.is_internal_transfer is not None: output['is_internal_transfer'] = txo.is_internal_transfer diff --git a/lbry/testcase.py b/lbry/testcase.py index 798937db6..56c9cb4c6 100644 --- a/lbry/testcase.py +++ b/lbry/testcase.py @@ -490,8 +490,8 @@ class CommandTestCase(IntegrationTestCase): self.daemon.jsonrpc_stream_update(claim_id, **kwargs), confirm ) - def stream_repost(self, claim_id, name='repost', bid='1.0', confirm=True, **kwargs): - return self.confirm_and_render( + async def stream_repost(self, claim_id, name='repost', bid='1.0', confirm=True, **kwargs): + return await self.confirm_and_render( self.daemon.jsonrpc_stream_repost(claim_id=claim_id, name=name, bid=bid, **kwargs), confirm ) @@ -502,6 +502,11 @@ class CommandTestCase(IntegrationTestCase): self.daemon.jsonrpc_stream_abandon(*args, **kwargs), confirm ) + async def purchase_create(self, *args, confirm=True, **kwargs): + return await self.confirm_and_render( + self.daemon.jsonrpc_purchase_create(*args, **kwargs), confirm + ) + async def publish(self, name, *args, confirm=True, **kwargs): return await self.confirm_and_render( self.daemon.jsonrpc_publish(name, *args, **kwargs), confirm @@ -560,8 +565,8 @@ class CommandTestCase(IntegrationTestCase): self.daemon.jsonrpc_wallet_send(*args, **kwargs), confirm ) - async def resolve(self, uri): - return (await self.out(self.daemon.jsonrpc_resolve(uri)))[uri] + async def resolve(self, uri, **kwargs): + return (await self.out(self.daemon.jsonrpc_resolve(uri, **kwargs)))[uri] async def claim_search(self, **kwargs): return (await self.out(self.daemon.jsonrpc_claim_search(**kwargs)))['items'] diff --git a/lbry/wallet/database.py b/lbry/wallet/database.py index d8265459e..53f4cf650 100644 --- a/lbry/wallet/database.py +++ b/lbry/wallet/database.py @@ -446,7 +446,7 @@ class Database(SQLiteMixin): ); create index if not exists txo_txid_idx on txo (txid); create index if not exists txo_address_idx on txo (address); - create index if not exists txo_claim_id_idx on txo (claim_id); + create index if not exists txo_claim_id_idx on txo (claim_id, txo_type); create index if not exists txo_claim_name_idx on txo (claim_name); create index if not exists txo_txo_type_idx on txo (txo_type); create index if not exists txo_channel_id_idx on txo (channel_id); @@ -676,7 +676,7 @@ class Database(SQLiteMixin): constraints.pop('limit', None) constraints.pop('order_by', None) count = await self.select_transactions('COUNT(*) as total', **constraints) - return count[0]['total'] + return count[0]['total'] or 0 async def get_transaction(self, **constraints): txs = await self.get_transactions(limit=1, **constraints) @@ -865,12 +865,12 @@ class Database(SQLiteMixin): async def get_txo_count(self, unspent=False, **constraints): self._clean_txo_constraints_for_aggregation(unspent, constraints) count = await self.select_txos('COUNT(*) as total', **constraints) - return count[0]['total'] + return count[0]['total'] or 0 async def get_txo_sum(self, unspent=False, **constraints): self._clean_txo_constraints_for_aggregation(unspent, constraints) result = await self.select_txos('SUM(amount) as total', **constraints) - return result[0]['total'] + return result[0]['total'] or 0 def get_utxos(self, read_only=False, **constraints): return self.get_txos(unspent=True, read_only=read_only, **constraints) @@ -908,7 +908,7 @@ class Database(SQLiteMixin): async def get_address_count(self, cols=None, read_only=False, **constraints): count = await self.select_addresses('COUNT(*) as total', read_only=read_only, **constraints) - return count[0]['total'] + return count[0]['total'] or 0 async def get_address(self, read_only=False, **constraints): addresses = await self.get_addresses(read_only=read_only, limit=1, **constraints) diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index 639446d3f..12d202254 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -25,7 +25,7 @@ from .account import Account, AddressManager, SingleKey from .network import Network from .transaction import Transaction, Output from .header import Headers, UnvalidatedHeaders -from .constants import TXO_TYPES, COIN, NULL_HASH32 +from .constants import TXO_TYPES, CLAIM_TYPES, COIN, NULL_HASH32 from .bip32 import PubKey, PrivateKey from .coinselection import CoinSelector @@ -646,7 +646,13 @@ class Ledger(metaclass=LedgerRegistry): print(record['history'], addresses, tx.id) raise asyncio.TimeoutError('Timed out waiting for transaction.') - async def _inflate_outputs(self, query, accounts) -> Tuple[List[Output], dict, int, int]: + async def _inflate_outputs( + self, query, accounts, + include_purchase_receipt=False, + include_is_my_output=False, + include_my_supports=False, + include_my_tips=False + ) -> Tuple[List[Output], dict, int, int]: encoded_outputs = await query outputs = Outputs.from_base64(encoded_outputs or b'') # TODO: why is the server returning None? txs = [] @@ -654,7 +660,7 @@ class Ledger(metaclass=LedgerRegistry): txs: List[Transaction] = await asyncio.gather(*( self.cache_transaction(*tx) for tx in outputs.txs )) - if accounts: + if include_purchase_receipt and accounts: priced_claims = [] for tx in txs: for txo in tx.outputs: @@ -671,11 +677,36 @@ class Ledger(metaclass=LedgerRegistry): for txo in priced_claims: txo.purchase_receipt = receipts.get(txo.claim_id) txos, blocked = outputs.inflate(txs) + if any((include_is_my_output, include_my_supports, include_my_tips)): + for txo in txos: + if isinstance(txo, Output) and txo.can_decode_claim: + if include_is_my_output: + mine = await self.db.get_txo_count( + claim_id=txo.claim_id, txo_type__in=CLAIM_TYPES, is_my_output=True, + unspent=True, accounts=accounts + ) + if mine: + txo.is_my_output = True + else: + txo.is_my_output = False + if include_my_supports: + supports = await self.db.get_txo_sum( + claim_id=txo.claim_id, txo_type=TXO_TYPES['support'], + is_my_input=True, is_my_output=True, + unspent=True, accounts=accounts + ) + txo.my_supports = supports + if include_my_tips: + tips = await self.db.get_txo_sum( + claim_id=txo.claim_id, txo_type=TXO_TYPES['support'], + is_my_input=True, is_my_output=False, accounts=accounts + ) + txo.my_tips = tips return txos, blocked, outputs.offset, outputs.total - async def resolve(self, accounts, urls): + async def resolve(self, accounts, urls, **kwargs): resolve = partial(self.network.retriable_call, self.network.resolve) - txos = (await self._inflate_outputs(resolve(urls), accounts))[0] + txos = (await self._inflate_outputs(resolve(urls), accounts, **kwargs))[0] assert len(urls) == len(txos), "Mismatch between urls requested for resolve and responses received." result = {} for url, txo in zip(urls, txos): diff --git a/lbry/wallet/transaction.py b/lbry/wallet/transaction.py index 264357f56..d8518999f 100644 --- a/lbry/wallet/transaction.py +++ b/lbry/wallet/transaction.py @@ -208,7 +208,7 @@ class Output(InputOutput): __slots__ = ( 'amount', 'script', 'is_internal_transfer', 'is_spent', 'is_my_output', 'is_my_input', - 'channel', 'private_key', 'meta', + 'channel', 'private_key', 'meta', 'my_supports', 'my_tips', 'purchase', 'purchased_claim', 'purchase_receipt', 'reposted_claim', 'claims', ) @@ -217,6 +217,7 @@ class Output(InputOutput): tx_ref: TXRef = None, position: int = None, is_internal_transfer: Optional[bool] = None, is_spent: Optional[bool] = None, is_my_output: Optional[bool] = None, is_my_input: Optional[bool] = None, + my_supports: Optional[int] = None, my_tips: Optional[int] = None, channel: Optional['Output'] = None, private_key: Optional[str] = None ) -> None: super().__init__(tx_ref, position) @@ -226,6 +227,8 @@ class Output(InputOutput): self.is_spent = is_spent self.is_my_output = is_my_output self.is_my_input = is_my_input + self.my_supports = my_supports + self.my_tips = my_tips self.channel = channel self.private_key = private_key self.purchase: 'Output' = None # txo containing purchase metadata diff --git a/tests/integration/blockchain/test_resolve_command.py b/tests/integration/blockchain/test_resolve_command.py index eff769302..a86330129 100644 --- a/tests/integration/blockchain/test_resolve_command.py +++ b/tests/integration/blockchain/test_resolve_command.py @@ -263,6 +263,49 @@ class ResolveCommand(BaseResolveTestCase): await self.resolve('@olds/bad_example') ) + async def test_resolve_with_includes(self): + wallet2 = await self.daemon.jsonrpc_wallet_create('wallet2', create_account=True) + address2 = await self.daemon.jsonrpc_address_unused(wallet_id=wallet2.id) + + await self.wallet_send('1.0', address2) + + stream = await self.stream_create( + 'priced', '0.1', wallet_id=wallet2.id, + fee_amount='0.5', fee_currency='LBC', fee_address=address2 + ) + stream_id = self.get_claim_id(stream) + + resolve = await self.resolve('priced') + self.assertNotIn('is_my_output', resolve) + self.assertNotIn('purchase_receipt', resolve) + self.assertNotIn('my_supports', resolve) + self.assertNotIn('my_tips', resolve) + + # is_my_output + resolve = await self.resolve('priced', include_is_my_output=True) + self.assertFalse(resolve['is_my_output']) + resolve = await self.resolve('priced', wallet_id=wallet2.id, include_is_my_output=True) + self.assertTrue(resolve['is_my_output']) + + # purchase receipt + resolve = await self.resolve('priced', include_purchase_receipt=True) + self.assertNotIn('purchase_receipt', resolve) + await self.purchase_create(stream_id) + resolve = await self.resolve('priced', include_purchase_receipt=True) + self.assertEqual('0.5', resolve['purchase_receipt']['amount']) + + # my supports and my tips + resolve = await self.resolve('priced', include_my_supports=True, include_my_tips=True) + self.assertEqual('0.0', resolve['my_supports']) + self.assertEqual('0.0', resolve['my_tips']) + await self.support_create(stream_id, '0.3') + await self.support_create(stream_id, '0.2') + await self.support_create(stream_id, '0.4', tip=True) + await self.support_create(stream_id, '0.5', tip=True) + resolve = await self.resolve('priced', include_my_supports=True, include_my_tips=True) + self.assertEqual('0.5', resolve['my_supports']) + self.assertEqual('0.9', resolve['my_tips']) + class ResolveAfterReorg(BaseResolveTestCase): From 76376f0d333578fe29e5a8ae377989e6b9ff50f7 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sun, 22 Mar 2020 00:24:38 -0400 Subject: [PATCH 2/5] lint --- lbry/extras/daemon/daemon.py | 2 +- lbry/wallet/ledger.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index 1220092d7..9249c7a8f 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -934,7 +934,7 @@ class Daemon(metaclass=JSONRPCServerType): Options: --urls= : (str, list) one or more urls to resolve --wallet_id= : (str) wallet to check for claim purchase reciepts - --include_purchase_receipt : (bool) lookup and include a receipt if this wallet + --include_purchase_receipt : (bool) lookup and include a receipt if this wallet has purchased the claim being resolved --include_is_my_output : (bool) lookup and include a boolean indicating if claim being resolved is yours diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index 12d202254..c99d7f5ec 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -651,8 +651,7 @@ class Ledger(metaclass=LedgerRegistry): include_purchase_receipt=False, include_is_my_output=False, include_my_supports=False, - include_my_tips=False - ) -> Tuple[List[Output], dict, int, int]: + include_my_tips=False) -> Tuple[List[Output], dict, int, int]: encoded_outputs = await query outputs = Outputs.from_base64(encoded_outputs or b'') # TODO: why is the server returning None? txs = [] From bdd2ac2c25b6e4a6cf845c2f5013ef0579617a31 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sun, 22 Mar 2020 01:13:26 -0400 Subject: [PATCH 3/5] renamed some flags --- lbry/extras/daemon/daemon.py | 17 +++++++--- lbry/extras/daemon/json_response_encoder.py | 10 +++--- lbry/stream/stream_manager.py | 2 +- lbry/wallet/ledger.py | 32 +++++++++++++------ lbry/wallet/transaction.py | 16 +++++++--- .../blockchain/test_purchase_command.py | 2 +- .../blockchain/test_resolve_command.py | 30 ++++++++++++----- 7 files changed, 76 insertions(+), 33 deletions(-) diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index 9249c7a8f..d5ab35889 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -928,8 +928,9 @@ class Daemon(metaclass=JSONRPCServerType): resolve ... [--wallet_id=] [--include_purchase_receipt] [--include_is_my_output] - [--include_my_supports] - [--include_my_tips] + [--include_sent_supports] + [--include_sent_tips] + [--include_received_tips] Options: --urls= : (str, list) one or more urls to resolve @@ -938,10 +939,14 @@ class Daemon(metaclass=JSONRPCServerType): has purchased the claim being resolved --include_is_my_output : (bool) lookup and include a boolean indicating if claim being resolved is yours - --include_my_supports : (bool) lookup and sum the total amount + --include_sent_supports : (bool) lookup and sum the total amount of supports you've made to this claim - --include_my_tips : (bool) lookup and sum the total amount + --include_sent_tips : (bool) lookup and sum the total amount of tips you've made to this claim + (only makes sense when claim is not yours) + --include_received_tips : (bool) lookup and sum the total amount + of tips you've received to this claim + (only makes sense when claim is yours) Returns: Dictionary of results, keyed by url @@ -2244,7 +2249,7 @@ class Daemon(metaclass=JSONRPCServerType): [--any_locations=...] [--all_locations=...] [--not_locations=...] [--order_by=...] [--page=] [--page_size=] - [--wallet_id=] + [--wallet_id=] [--include_purchase_receipt] Options: --name= : (str) claim name (normalized) @@ -2346,6 +2351,8 @@ class Daemon(metaclass=JSONRPCServerType): --no_totals : (bool) do not calculate the total number of pages and items in result set (significant performance boost) --wallet_id= : (str) wallet to check for claim purchase reciepts + --include_purchase_receipt : (bool) lookup and include a receipt if this wallet + has purchased the claim Returns: {Paginated[Output]} """ diff --git a/lbry/extras/daemon/json_response_encoder.py b/lbry/extras/daemon/json_response_encoder.py index 63714a0e1..997e2019e 100644 --- a/lbry/extras/daemon/json_response_encoder.py +++ b/lbry/extras/daemon/json_response_encoder.py @@ -174,10 +174,12 @@ class JSONResponseEncoder(JSONEncoder): output['is_my_output'] = txo.is_my_output if txo.is_my_input is not None: output['is_my_input'] = txo.is_my_input - if txo.my_supports is not None: - output['my_supports'] = dewies_to_lbc(txo.my_supports) - if txo.my_tips is not None: - output['my_tips'] = dewies_to_lbc(txo.my_tips) + if txo.sent_supports is not None: + output['sent_supports'] = dewies_to_lbc(txo.sent_supports) + if txo.sent_tips is not None: + output['sent_tips'] = dewies_to_lbc(txo.sent_tips) + if txo.received_tips is not None: + output['received_tips'] = dewies_to_lbc(txo.received_tips) if txo.is_internal_transfer is not None: output['is_internal_transfer'] = txo.is_internal_transfer diff --git a/lbry/stream/stream_manager.py b/lbry/stream/stream_manager.py index 18e8b5ddc..92983b368 100644 --- a/lbry/stream/stream_manager.py +++ b/lbry/stream/stream_manager.py @@ -378,7 +378,7 @@ class StreamManager: raise ResolveError("cannot download a channel claim, specify a /path") try: response = await asyncio.wait_for( - manager.ledger.resolve(wallet.accounts, [uri]), + manager.ledger.resolve(wallet.accounts, [uri], include_purchase_receipt=True), resolve_timeout ) resolved_result = self._convert_to_old_resolve_output(manager, response) diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index c99d7f5ec..529f3243f 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -650,8 +650,9 @@ class Ledger(metaclass=LedgerRegistry): self, query, accounts, include_purchase_receipt=False, include_is_my_output=False, - include_my_supports=False, - include_my_tips=False) -> Tuple[List[Output], dict, int, int]: + include_sent_supports=False, + include_sent_tips=False, + include_received_tips=False) -> Tuple[List[Output], dict, int, int]: encoded_outputs = await query outputs = Outputs.from_base64(encoded_outputs or b'') # TODO: why is the server returning None? txs = [] @@ -676,7 +677,7 @@ class Ledger(metaclass=LedgerRegistry): for txo in priced_claims: txo.purchase_receipt = receipts.get(txo.claim_id) txos, blocked = outputs.inflate(txs) - if any((include_is_my_output, include_my_supports, include_my_tips)): + if any((include_is_my_output, include_sent_supports, include_sent_tips)): for txo in txos: if isinstance(txo, Output) and txo.can_decode_claim: if include_is_my_output: @@ -688,19 +689,27 @@ class Ledger(metaclass=LedgerRegistry): txo.is_my_output = True else: txo.is_my_output = False - if include_my_supports: + if include_sent_supports: supports = await self.db.get_txo_sum( claim_id=txo.claim_id, txo_type=TXO_TYPES['support'], is_my_input=True, is_my_output=True, unspent=True, accounts=accounts ) - txo.my_supports = supports - if include_my_tips: + txo.sent_supports = supports + if include_sent_tips: tips = await self.db.get_txo_sum( claim_id=txo.claim_id, txo_type=TXO_TYPES['support'], - is_my_input=True, is_my_output=False, accounts=accounts + is_my_input=True, is_my_output=False, + accounts=accounts ) - txo.my_tips = tips + txo.sent_tips = tips + if include_received_tips: + tips = await self.db.get_txo_sum( + claim_id=txo.claim_id, txo_type=TXO_TYPES['support'], + is_my_input=False, is_my_output=True, + accounts=accounts + ) + txo.received_tips = tips return txos, blocked, outputs.offset, outputs.total async def resolve(self, accounts, urls, **kwargs): @@ -718,8 +727,11 @@ class Ledger(metaclass=LedgerRegistry): result[url] = txo return result - async def claim_search(self, accounts, **kwargs) -> Tuple[List[Output], dict, int, int]: - return await self._inflate_outputs(self.network.claim_search(**kwargs), accounts) + async def claim_search( + self, accounts, include_purchase_receipt=False, **kwargs) -> Tuple[List[Output], dict, int, int]: + return await self._inflate_outputs( + self.network.claim_search(**kwargs), accounts, include_purchase_receipt=include_purchase_receipt + ) async def get_claim_by_claim_id(self, accounts, claim_id) -> Output: for claim in (await self.claim_search(accounts, claim_id=claim_id))[0]: diff --git a/lbry/wallet/transaction.py b/lbry/wallet/transaction.py index d8518999f..693ccc91b 100644 --- a/lbry/wallet/transaction.py +++ b/lbry/wallet/transaction.py @@ -208,7 +208,7 @@ class Output(InputOutput): __slots__ = ( 'amount', 'script', 'is_internal_transfer', 'is_spent', 'is_my_output', 'is_my_input', - 'channel', 'private_key', 'meta', 'my_supports', 'my_tips', + 'channel', 'private_key', 'meta', 'sent_supports', 'sent_tips', 'received_tips', 'purchase', 'purchased_claim', 'purchase_receipt', 'reposted_claim', 'claims', ) @@ -217,7 +217,8 @@ class Output(InputOutput): tx_ref: TXRef = None, position: int = None, is_internal_transfer: Optional[bool] = None, is_spent: Optional[bool] = None, is_my_output: Optional[bool] = None, is_my_input: Optional[bool] = None, - my_supports: Optional[int] = None, my_tips: Optional[int] = None, + sent_supports: Optional[int] = None, sent_tips: Optional[int] = None, + received_tips: Optional[int] = None, channel: Optional['Output'] = None, private_key: Optional[str] = None ) -> None: super().__init__(tx_ref, position) @@ -227,8 +228,9 @@ class Output(InputOutput): self.is_spent = is_spent self.is_my_output = is_my_output self.is_my_input = is_my_input - self.my_supports = my_supports - self.my_tips = my_tips + self.sent_supports = sent_supports + self.sent_tips = sent_tips + self.received_tips = received_tips self.channel = channel self.private_key = private_key self.purchase: 'Output' = None # txo containing purchase metadata @@ -244,11 +246,17 @@ class Output(InputOutput): self.is_spent = None self.is_my_output = None self.is_my_input = None + self.sent_supports = None + self.sent_tips = None + self.received_tips = None else: self.is_internal_transfer = annotated.is_internal_transfer self.is_spent = annotated.is_spent self.is_my_output = annotated.is_my_output self.is_my_input = annotated.is_my_input + self.sent_supports = annotated.sent_supports + self.sent_tips = annotated.sent_tips + self.received_tips = annotated.received_tips self.channel = annotated.channel if annotated else None self.private_key = annotated.private_key if annotated else None diff --git a/tests/integration/blockchain/test_purchase_command.py b/tests/integration/blockchain/test_purchase_command.py index e497d6d72..ae68dd7f9 100644 --- a/tests/integration/blockchain/test_purchase_command.py +++ b/tests/integration/blockchain/test_purchase_command.py @@ -142,7 +142,7 @@ class PurchaseCommandTests(CommandTestCase): self.assertEqual(result['items'][0]['purchase_info'][0]['claim_id'], claim_id2) self.assertEqual(result['items'][2]['purchase_info'][0]['claim_id'], claim_id1) - result = await self.claim_search() + result = await self.claim_search(include_purchase_receipt=True) self.assertEqual(result[0]['claim_id'], result[0]['purchase_receipt']['claim_id']) self.assertEqual(result[1]['claim_id'], result[1]['purchase_receipt']['claim_id']) diff --git a/tests/integration/blockchain/test_resolve_command.py b/tests/integration/blockchain/test_resolve_command.py index a86330129..1874f5f89 100644 --- a/tests/integration/blockchain/test_resolve_command.py +++ b/tests/integration/blockchain/test_resolve_command.py @@ -278,8 +278,9 @@ class ResolveCommand(BaseResolveTestCase): resolve = await self.resolve('priced') self.assertNotIn('is_my_output', resolve) self.assertNotIn('purchase_receipt', resolve) - self.assertNotIn('my_supports', resolve) - self.assertNotIn('my_tips', resolve) + self.assertNotIn('sent_supports', resolve) + self.assertNotIn('sent_tips', resolve) + self.assertNotIn('received_tips', resolve) # is_my_output resolve = await self.resolve('priced', include_is_my_output=True) @@ -295,16 +296,29 @@ class ResolveCommand(BaseResolveTestCase): self.assertEqual('0.5', resolve['purchase_receipt']['amount']) # my supports and my tips - resolve = await self.resolve('priced', include_my_supports=True, include_my_tips=True) - self.assertEqual('0.0', resolve['my_supports']) - self.assertEqual('0.0', resolve['my_tips']) + resolve = await self.resolve( + 'priced', include_sent_supports=True, include_sent_tips=True, include_received_tips=True + ) + self.assertEqual('0.0', resolve['sent_supports']) + self.assertEqual('0.0', resolve['sent_tips']) + self.assertEqual('0.0', resolve['received_tips']) await self.support_create(stream_id, '0.3') await self.support_create(stream_id, '0.2') await self.support_create(stream_id, '0.4', tip=True) await self.support_create(stream_id, '0.5', tip=True) - resolve = await self.resolve('priced', include_my_supports=True, include_my_tips=True) - self.assertEqual('0.5', resolve['my_supports']) - self.assertEqual('0.9', resolve['my_tips']) + resolve = await self.resolve( + 'priced', include_sent_supports=True, include_sent_tips=True, include_received_tips=True + ) + self.assertEqual('0.5', resolve['sent_supports']) + self.assertEqual('0.9', resolve['sent_tips']) + self.assertEqual('0.0', resolve['received_tips']) + + resolve = await self.resolve( + 'priced', include_sent_supports=True, include_sent_tips=True, include_received_tips=True, + wallet_id=wallet2.id + ) + self.assertEqual('0.0', resolve['sent_tips']) + self.assertEqual('0.9', resolve['received_tips']) class ResolveAfterReorg(BaseResolveTestCase): From b5c24d6a4850bc426dcf614a219e4a28fce7bd78 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sun, 22 Mar 2020 01:29:26 -0400 Subject: [PATCH 4/5] fixing unit tests --- lbry/wallet/ledger.py | 4 ++++ tests/integration/blockchain/test_resolve_command.py | 3 +++ tests/unit/stream/test_stream_manager.py | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index 529f3243f..0376cb5a0 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -710,6 +710,10 @@ class Ledger(metaclass=LedgerRegistry): accounts=accounts ) txo.received_tips = tips + if not include_purchase_receipt: + # txo's are cached across wallets, this prevents + # leaking receipts between wallets + txo.purchase_receipt = None return txos, blocked, outputs.offset, outputs.total async def resolve(self, accounts, urls, **kwargs): diff --git a/tests/integration/blockchain/test_resolve_command.py b/tests/integration/blockchain/test_resolve_command.py index 1874f5f89..7b9b56196 100644 --- a/tests/integration/blockchain/test_resolve_command.py +++ b/tests/integration/blockchain/test_resolve_command.py @@ -317,8 +317,11 @@ class ResolveCommand(BaseResolveTestCase): 'priced', include_sent_supports=True, include_sent_tips=True, include_received_tips=True, wallet_id=wallet2.id ) + self.assertEqual('0.0', resolve['sent_supports']) self.assertEqual('0.0', resolve['sent_tips']) self.assertEqual('0.9', resolve['received_tips']) + self.assertEqual('1.4', resolve['meta']['support_amount']) + self.assertNotIn('purchase_receipt', resolve) # prevent leaking cached receipts class ResolveAfterReorg(BaseResolveTestCase): diff --git a/tests/unit/stream/test_stream_manager.py b/tests/unit/stream/test_stream_manager.py index a3967a844..4dfb76b35 100644 --- a/tests/unit/stream/test_stream_manager.py +++ b/tests/unit/stream/test_stream_manager.py @@ -105,7 +105,7 @@ async def get_mock_wallet(sd_hash, storage, balance=10.0, fee=None): network=manager.ledger.network, server=('fakespv.lbry.com', 50001) ) - async def mock_resolve(*args): + async def mock_resolve(*args, **kwargs): result = {txo.meta['permanent_url']: txo} claims = [ StreamManager._convert_to_old_resolve_output(manager, result)[txo.meta['permanent_url']] From 09644914a6875600ab1709c91189268a9e8861c1 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sun, 22 Mar 2020 01:51:09 -0400 Subject: [PATCH 5/5] added --include_is_my_output to claim_search --- lbry/extras/daemon/daemon.py | 4 +++- lbry/wallet/ledger.py | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index d5ab35889..270dde189 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -2249,7 +2249,7 @@ class Daemon(metaclass=JSONRPCServerType): [--any_locations=...] [--all_locations=...] [--not_locations=...] [--order_by=...] [--page=] [--page_size=] - [--wallet_id=] [--include_purchase_receipt] + [--wallet_id=] [--include_purchase_receipt] [--include_is_my_output] Options: --name= : (str) claim name (normalized) @@ -2353,6 +2353,8 @@ class Daemon(metaclass=JSONRPCServerType): --wallet_id= : (str) wallet to check for claim purchase reciepts --include_purchase_receipt : (bool) lookup and include a receipt if this wallet has purchased the claim + --include_is_my_output : (bool) lookup and include a boolean indicating + if claim being resolved is yours Returns: {Paginated[Output]} """ diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index 0376cb5a0..c9fefd76d 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -732,9 +732,12 @@ class Ledger(metaclass=LedgerRegistry): return result async def claim_search( - self, accounts, include_purchase_receipt=False, **kwargs) -> Tuple[List[Output], dict, int, int]: + self, accounts, include_purchase_receipt=False, include_is_my_output=False, + **kwargs) -> Tuple[List[Output], dict, int, int]: return await self._inflate_outputs( - self.network.claim_search(**kwargs), accounts, include_purchase_receipt=include_purchase_receipt + self.network.claim_search(**kwargs), accounts, + include_purchase_receipt=include_purchase_receipt, + include_is_my_output=include_is_my_output ) async def get_claim_by_claim_id(self, accounts, claim_id) -> Output: