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):