From 90e06abba27a03bba495ba051a8430625882c3dd Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Mon, 5 Nov 2018 00:09:30 -0500 Subject: [PATCH] fixes for #1569 --- lbrynet/extras/wallet/manager.py | 86 ++++++++++++-------- lbrynet/extras/wallet/transaction.py | 15 ++++ tests/integration/wallet/test_commands.py | 98 +++++++++++++++++++++++ tox.ini | 1 + 4 files changed, 167 insertions(+), 33 deletions(-) diff --git a/lbrynet/extras/wallet/manager.py b/lbrynet/extras/wallet/manager.py index 71b22d3b6..8e11cc1bd 100644 --- a/lbrynet/extras/wallet/manager.py +++ b/lbrynet/extras/wallet/manager.py @@ -296,40 +296,60 @@ class LbryWalletManager(BaseWalletManager): 'fee': dewies_to_lbc(tx.fee), 'date': datetime.fromtimestamp(ts).isoformat(' ')[:-3] if tx.height > 0 else None, 'confirmations': headers.height - tx.height if tx.height > 0 else 0, - 'claim_info': [{ - 'address': txo.get_address(account.ledger), - 'balance_delta': dewies_to_lbc(-txo.amount), - 'amount': dewies_to_lbc(txo.amount), - 'claim_id': txo.claim_id, - 'claim_name': txo.claim_name, - 'nout': txo.position - } for txo in tx.my_claim_outputs], - 'update_info': [{ - 'address': txo.get_address(account.ledger), - 'balance_delta': dewies_to_lbc(-txo.amount), - 'amount': dewies_to_lbc(txo.amount), - 'claim_id': txo.claim_id, - 'claim_name': txo.claim_name, - 'nout': txo.position - } for txo in tx.my_update_outputs], - 'support_info': [{ - 'address': txo.get_address(account.ledger), - 'balance_delta': dewies_to_lbc(txo.amount), - 'amount': dewies_to_lbc(txo.amount), - 'claim_id': txo.claim_id, - 'claim_name': txo.claim_name, - 'is_tip': not txo.is_my_account, - 'nout': txo.position - } for txo in tx.my_support_outputs], - 'abandon_info': [{ - 'address': txo.get_address(account.ledger), - 'balance_delta': dewies_to_lbc(-txo.amount), - 'amount': dewies_to_lbc(txo.amount), - 'claim_id': txo.claim_id, - 'claim_name': txo.claim_name, - 'nout': txo.position - } for txo in tx.my_abandon_outputs], + 'claim_info': [], + 'update_info': [], + 'support_info': [], + 'abandon_info': [] } + for txo in tx.my_claim_outputs: + item['claim_info'].append({ + 'address': txo.get_address(account.ledger), + 'balance_delta': dewies_to_lbc(-txo.amount), + 'amount': dewies_to_lbc(txo.amount), + 'claim_id': txo.claim_id, + 'claim_name': txo.claim_name, + 'nout': txo.position + }) + for txo in tx.my_update_outputs: + item['update_info'].append({ + 'address': txo.get_address(account.ledger), + 'balance_delta': dewies_to_lbc(-txo.amount), + 'amount': dewies_to_lbc(txo.amount), + 'claim_id': txo.claim_id, + 'claim_name': txo.claim_name, + 'nout': txo.position + }) + for txo in tx.my_support_outputs: + is_tip = next(tx.my_inputs, None) is None + item['support_info'].append({ + 'address': txo.get_address(account.ledger), + 'balance_delta': dewies_to_lbc(txo.amount if is_tip else -txo.amount), + 'amount': dewies_to_lbc(txo.amount), + 'claim_id': txo.claim_id, + 'claim_name': txo.claim_name, + 'is_tip': is_tip, + 'nout': txo.position + }) + for txo in tx.other_support_outputs: + is_tip = next(tx.my_inputs, None) is not None + item['support_info'].append({ + 'address': txo.get_address(account.ledger), + 'balance_delta': dewies_to_lbc(-txo.amount), + 'amount': dewies_to_lbc(txo.amount), + 'claim_id': txo.claim_id, + 'claim_name': txo.claim_name, + 'is_tip': is_tip, + 'nout': txo.position + }) + for txo in tx.my_abandon_outputs: + item['abandon_info'].append({ + 'address': txo.get_address(account.ledger), + 'balance_delta': dewies_to_lbc(-txo.amount), + 'amount': dewies_to_lbc(txo.amount), + 'claim_id': txo.claim_id, + 'claim_name': txo.claim_name, + 'nout': txo.position + }) if all([txi.txo_ref.txo is not None for txi in tx.inputs]): item['fee'] = dewies_to_lbc(tx.fee) else: diff --git a/lbrynet/extras/wallet/transaction.py b/lbrynet/extras/wallet/transaction.py index 8c101cd39..55856d7cf 100644 --- a/lbrynet/extras/wallet/transaction.py +++ b/lbrynet/extras/wallet/transaction.py @@ -161,11 +161,22 @@ class Transaction(BaseTransaction): def abandon(cls, claims: Iterable[Output], funding_accounts: Iterable[Account], change_account: Account): return cls.create([Input.spend(txo) for txo in claims], [], funding_accounts, change_account) + @property + def my_inputs(self): + for txi in self.inputs: + if txi.txo_ref.txo is not None and txi.txo_ref.txo.is_my_account: + yield txi + def _filter_my_outputs(self, f): for txo in self.outputs: if txo.is_my_account and f(txo.script): yield txo + def _filter_other_outputs(self, f): + for txo in self.outputs: + if not txo.is_my_account and f(txo.script): + yield txo + @property def my_claim_outputs(self): return self._filter_my_outputs(lambda s: s.is_claim_name) @@ -178,6 +189,10 @@ class Transaction(BaseTransaction): def my_support_outputs(self): return self._filter_my_outputs(lambda s: s.is_support_claim) + @property + def other_support_outputs(self): + return self._filter_other_outputs(lambda s: s.is_support_claim) + @property def my_abandon_outputs(self): for txi in self.inputs: diff --git a/tests/integration/wallet/test_commands.py b/tests/integration/wallet/test_commands.py index c1f33b10b..d7d48cac4 100644 --- a/tests/integration/wallet/test_commands.py +++ b/tests/integration/wallet/test_commands.py @@ -2,6 +2,7 @@ import json import asyncio import tempfile import logging +from functools import partial from types import SimpleNamespace from twisted.trial import unittest @@ -527,3 +528,100 @@ class PublishCommand(CommandTestCase): 'hovercraft', '1.0', file_path=file.name, channel_name='@baz', channel_account_id=[account1_id] )) + + +class SupportingSupports(CommandTestCase): + + VERBOSITY = logging.INFO + + async def on_transaction_dict(self, tx): + await asyncio.wait([ + self.ledger.on_transaction.where( + partial(lambda address, event: address == event.address, address) + ) for address in self.get_all_addresses(tx) + ]) + + @staticmethod + def get_all_addresses(tx): + addresses = set() + for txi in tx['inputs']: + addresses.add(txi['address']) + for txo in tx['outputs']: + addresses.add(txo['address']) + return list(addresses) + + async def test_regular_supports_and_tip_supports(self): + # account2 will be used to send tips and supports to account1 + account2_id = (await self.daemon.jsonrpc_account_create('second account'))['id'] + + # give account2 some spending LBC + result = await self.out(self.daemon.jsonrpc_wallet_send( + '5.0', await self.daemon.jsonrpc_address_unused(account2_id) + )) + await self.confirm_tx(result['txid']) + + # create the claim we'll be tipping and supporting + with tempfile.NamedTemporaryFile() as file: + file.write(b'hi!') + file.flush() + claim = await self.out(self.daemon.jsonrpc_publish( + 'hovercraft', '1.0', file_path=file.name + )) + self.assertTrue(claim['success']) + await self.confirm_tx(claim['tx']['txid']) + + # account1 and account2 balances: + self.assertEqual('3.979769', await self.daemon.jsonrpc_account_balance()) + self.assertEqual('5.0', await self.daemon.jsonrpc_account_balance(account2_id)) + + # send a tip to the claim using account2 + tip = await self.out( + self.daemon.jsonrpc_claim_tip(claim['claim_id'], '1.0', account2_id) + ) + await self.on_transaction_dict(tip) + await self.generate(1) + await self.on_transaction_dict(tip) + + # tips don't affect balance so account1 balance is same but account2 balance went down + self.assertEqual('3.979769', await self.daemon.jsonrpc_account_balance()) + self.assertEqual('3.9998585', await self.daemon.jsonrpc_account_balance(account2_id)) + + # verify that the incoming tip is marked correctly as is_tip=True in account1 + txs = await self.out(self.daemon.jsonrpc_transaction_list()) + self.assertEqual(len(txs[0]['support_info']), 1) + self.assertEqual(txs[0]['support_info'][0]['balance_delta'], '1.0') + self.assertEqual(txs[0]['support_info'][0]['claim_id'], claim['claim_id']) + self.assertEqual(txs[0]['support_info'][0]['is_tip'], True) + self.assertEqual(txs[0]['value'], '1.0') + + # verify that the outgoing tip is marked correctly as is_tip=True in account2 + txs2 = await self.out( + self.daemon.jsonrpc_transaction_list(account2_id) + ) + self.assertEqual(len(txs2[0]['support_info']), 1) + self.assertEqual(txs2[0]['support_info'][0]['balance_delta'], '-1.0') + self.assertEqual(txs2[0]['support_info'][0]['claim_id'], claim['claim_id']) + self.assertEqual(txs2[0]['support_info'][0]['is_tip'], True) + self.assertEqual(txs2[0]['value'], '-1.0001415') + + # send a support to the claim using account2 + support = await self.out( + self.daemon.jsonrpc_claim_new_support('hovercraft', claim['claim_id'], '2.0', account2_id) + ) + await self.on_transaction_dict(support) + await self.generate(1) + await self.on_transaction_dict(support) + + # account2 balance went down ~2 + self.assertEqual('3.979769', await self.daemon.jsonrpc_account_balance()) + self.assertEqual('1.999717', await self.daemon.jsonrpc_account_balance(account2_id)) + + # verify that the outgoing support is marked correctly as is_tip=False in account2 + txs2 = await self.out( + self.daemon.jsonrpc_transaction_list(account2_id) + ) + self.assertEqual(len(txs2[0]['support_info']), 1) + self.assertEqual(txs2[0]['support_info'][0]['balance_delta'], '-2.0') + self.assertEqual(txs2[0]['support_info'][0]['claim_id'], claim['claim_id']) + self.assertEqual(txs2[0]['support_info'][0]['is_tip'], False) + self.assertEqual(txs2[0]['value'], '-0.0001415') diff --git a/tox.ini b/tox.ini index 02cb1ef1d..845a5519d 100644 --- a/tox.ini +++ b/tox.ini @@ -16,4 +16,5 @@ commands = coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.cli coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.AccountManagement coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.PublishCommand + coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.SupportingSupports coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.EpicAdventuresOfChris45