diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index 070c77bd6..6f31b5e6a 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -2194,7 +2194,7 @@ class Daemon(metaclass=JSONRPCServerType): claim_list [--claim_type=...] [--claim_id=...] [--name=...] [--channel_id=...] [--account_id=] [--wallet_id=] [--page=] [--page_size=] - [--resolve] [--order_by=] [--no_totals] + [--resolve] [--order_by=] [--no_totals] [--include_received_tips] Options: --claim_type= : (str or list) claim type: channel, stream, repost, collection @@ -2209,6 +2209,7 @@ class Daemon(metaclass=JSONRPCServerType): --order_by= : (str) field to order by: 'name', 'height', 'amount' --no_totals : (bool) do not calculate the total number of pages and items in result set (significant performance boost) + --include_received_tips : (bool) calculate the amount of tips recieved for claim outputs Returns: {Paginated[Output]} """ @@ -4170,7 +4171,7 @@ class Daemon(metaclass=JSONRPCServerType): @requires(WALLET_COMPONENT) def jsonrpc_txo_list( self, account_id=None, wallet_id=None, page=None, page_size=None, - resolve=False, order_by=None, no_totals=False, **kwargs): + resolve=False, order_by=None, no_totals=False, include_received_tips=False, **kwargs): """ List my transaction outputs. @@ -4180,7 +4181,7 @@ class Daemon(metaclass=JSONRPCServerType): [--is_my_input_or_output | [[--is_my_output | --is_not_my_output] [--is_my_input | --is_not_my_input]] ] - [--exclude_internal_transfers] + [--exclude_internal_transfers] [--include_received_tips] [--wallet_id=] [--page=] [--page_size=] [--resolve] [--order_by=][--no_totals] @@ -4203,6 +4204,7 @@ class Daemon(metaclass=JSONRPCServerType): "--is_my_input --is_my_output --type=other" this allows to exclude "change" payments, this flag can be used in combination with any of the other flags + --include_received_tips : (bool) calculate the amount of tips recieved for claim outputs --account_id= : (str) id of the account to query --wallet_id= : (str) restrict results to specific wallet --page= : (int) page to return during paginating @@ -4227,6 +4229,7 @@ class Daemon(metaclass=JSONRPCServerType): 'include_is_spent': True, 'include_is_my_input': True, 'include_is_my_output': True, + 'include_received_tips': include_received_tips } if order_by is not None: if order_by == 'name': diff --git a/lbry/wallet/database.py b/lbry/wallet/database.py index 53f4cf650..218e54cc5 100644 --- a/lbry/wallet/database.py +++ b/lbry/wallet/database.py @@ -750,6 +750,7 @@ class Database(SQLiteMixin): include_is_spent = constraints.get('include_is_spent', False) include_is_my_input = constraints.get('include_is_my_input', False) include_is_my_output = constraints.pop('include_is_my_output', False) + include_received_tips = constraints.pop('include_received_tips', False) select_columns = [ "tx.txid, raw, tx.height, tx.position as tx_position, tx.is_verified, " @@ -777,12 +778,20 @@ class Database(SQLiteMixin): select_columns.append(f"""( txi.address IS NOT NULL AND txi.address IN (SELECT address FROM account_address WHERE {my_accounts_sql}) - ) AS is_my_input - """) + ) AS is_my_input""") if include_is_spent: select_columns.append("spent.txoid IS NOT NULL AS is_spent") + if include_received_tips: + select_columns.append(f"""( + SELECT COALESCE(SUM(support.amount), 0) FROM txo AS support WHERE + support.claim_id = txo.claim_id AND + support.txo_type = {TXO_TYPES['support']} AND + support.address IN (SELECT address FROM account_address WHERE {my_accounts_sql}) AND + support.txoid NOT IN (SELECT txoid FROM txi) + ) AS received_tips""") + if 'order_by' not in constraints or constraints['order_by'] == 'height': constraints['order_by'] = [ "tx.height=0 DESC", "tx.height DESC", "tx.position DESC", "txo.position" @@ -820,6 +829,8 @@ class Database(SQLiteMixin): txo.is_internal_transfer = True else: txo.is_internal_transfer = False + if include_received_tips: + txo.received_tips = row['received_tips'] txos.append(txo) channel_ids = set() @@ -854,6 +865,7 @@ class Database(SQLiteMixin): def _clean_txo_constraints_for_aggregation(self, unspent, constraints): constraints.pop('include_is_my_input', None) constraints.pop('include_is_my_output', None) + constraints.pop('include_received_tips', None) constraints.pop('wallet', None) constraints.pop('resolve', None) constraints.pop('offset', None) diff --git a/tests/integration/blockchain/test_claim_commands.py b/tests/integration/blockchain/test_claim_commands.py index 7e3729cbc..1156917c5 100644 --- a/tests/integration/blockchain/test_claim_commands.py +++ b/tests/integration/blockchain/test_claim_commands.py @@ -690,6 +690,44 @@ class ClaimCommands(ClaimTestCase): await self.assertClaimList([stream1_id, stream3_id, stream2_id], claim_type='stream', order_by='amount') await self.assertClaimList([stream3_id, stream2_id, stream1_id], claim_type='stream', order_by='height') + async def test_claim_list_with_tips(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('5.0', address2) + + stream1_id = self.get_claim_id(await self.stream_create('one')) + stream2_id = self.get_claim_id(await self.stream_create('two')) + + claims = await self.claim_list() + self.assertNotIn('received_tips', claims[0]) + self.assertNotIn('received_tips', claims[1]) + + claims = await self.claim_list(include_received_tips=True) + self.assertEqual('0.0', claims[0]['received_tips']) + self.assertEqual('0.0', claims[1]['received_tips']) + + await self.support_create(stream1_id, '0.7', tip=True) + await self.support_create(stream1_id, '0.3', tip=True, wallet_id=wallet2.id) + await self.support_create(stream1_id, '0.2', tip=True, wallet_id=wallet2.id) + await self.support_create(stream2_id, '0.4', tip=True, wallet_id=wallet2.id) + await self.support_create(stream2_id, '0.5', tip=True, wallet_id=wallet2.id) + await self.support_create(stream2_id, '0.1', tip=True, wallet_id=wallet2.id) + + claims = await self.claim_list(include_received_tips=True) + self.assertEqual('1.0', claims[0]['received_tips']) + self.assertEqual('1.2', claims[1]['received_tips']) + + await self.support_abandon(stream1_id) + claims = await self.claim_list(include_received_tips=True) + self.assertEqual('1.0', claims[0]['received_tips']) + self.assertEqual('0.0', claims[1]['received_tips']) + + await self.support_abandon(stream2_id) + claims = await self.claim_list(include_received_tips=True) + self.assertEqual('0.0', claims[0]['received_tips']) + self.assertEqual('0.0', claims[1]['received_tips']) + class ChannelCommands(CommandTestCase):