diff --git a/lbrynet/daemon/json_response_encoder.py b/lbrynet/daemon/json_response_encoder.py index 222c6aa11..740545ebd 100644 --- a/lbrynet/daemon/json_response_encoder.py +++ b/lbrynet/daemon/json_response_encoder.py @@ -43,12 +43,32 @@ class JSONResponseEncoder(JSONEncoder): 'nout': txo.position, 'amount': dewies_to_lbc(txo.amount), 'address': txo.get_address(self.ledger), - 'is_claim': txo.script.is_claim_name, - 'is_support': txo.script.is_support_claim, - 'is_update': txo.script.is_update_claim, } if txo.is_change is not None: output['is_change'] = txo.is_change + if txo.is_my_account is not None: + output['is_mine'] = txo.is_my_account + if txo.script.is_claim_involved: + output.update({ + 'name': txo.claim_name, + 'claim_id': txo.claim_id, + 'permanent_url': txo.permanent_url, + 'is_claim': txo.script.is_claim_name, + 'is_support': txo.script.is_support_claim, + 'is_update': txo.script.is_update_claim + }) + if txo.script.is_claim_name: + output.update({ + 'category': 'claim', + 'value': txo.claim.claim_dict + }) + elif txo.script.is_update_claim: + output.update({ + 'category': 'update', + 'value': txo.claim.claim_dict + }) + elif txo.script.is_support_claim: + output['category'] = 'support' return output def encode_input(self, txi): diff --git a/lbrynet/wallet/account.py b/lbrynet/wallet/account.py index 5be829a19..6c50cd0a1 100644 --- a/lbrynet/wallet/account.py +++ b/lbrynet/wallet/account.py @@ -125,23 +125,11 @@ class Account(BaseAccount): constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0}) return super().get_unspent_outputs(**constraints) - @defer.inlineCallbacks def get_channels(self): - utxos = yield super().get_unspent_outputs( + return super().get_unspent_outputs( claim_type__any={'is_claim': 1, 'is_update': 1}, claim_name__like='@%' ) - channels = [] - for utxo in utxos: - d = ClaimDict.deserialize(utxo.script.values['claim']) - channels.append({ - 'name': utxo.claim_name, - 'claim_id': utxo.claim_id, - 'txid': utxo.tx_ref.id, - 'nout': utxo.position, - 'have_certificate': utxo.ref.id in self.certificates - }) - return channels @classmethod def get_private_key_from_seed(cls, ledger: 'baseledger.BaseLedger', seed: str, password: str): diff --git a/lbrynet/wallet/database.py b/lbrynet/wallet/database.py index ccaaf1a1c..7a22372d8 100644 --- a/lbrynet/wallet/database.py +++ b/lbrynet/wallet/database.py @@ -1,5 +1,5 @@ from twisted.internet import defer -from torba.basedatabase import BaseDatabase +from torba.basedatabase import BaseDatabase, constraints_to_sql from .certificate import Certificate @@ -46,6 +46,32 @@ class WalletDatabase(BaseDatabase): row['claim_name'] = txo.claim_name return row + @defer.inlineCallbacks + def get_txos(self, **constraints): + txos = yield super().get_txos(**constraints) + my_account = constraints.get('my_account', constraints.get('account')) + + claim_ids = set() + for txo in txos: + if txo.script.is_claim_name or txo.script.is_update_claim: + if 'publisherSignature' in txo.claim_dict: + claim_ids.add(txo.claim_dict['publisherSignature']['certificateId']) + + if claim_ids: + channels = { + txo.claim_id: txo for txo in + (yield super().get_utxos( + my_account=my_account, + claim_id__in=claim_ids + )) + } + for txo in txos: + if txo.script.is_claim_name or txo.script.is_update_claim: + if 'publisherSignature' in txo.claim_dict: + txo.channel = channels.get(txo.claim_dict['publisherSignature']['certificateId']) + + return txos + def get_claims(self, **constraints): constraints['claim_type__any'] = {'is_claim': 1, 'is_update': 1} return self.get_utxos(**constraints) diff --git a/lbrynet/wallet/transaction.py b/lbrynet/wallet/transaction.py index 5512669db..a50c572ea 100644 --- a/lbrynet/wallet/transaction.py +++ b/lbrynet/wallet/transaction.py @@ -1,12 +1,12 @@ import struct from binascii import hexlify, unhexlify -from typing import List, Iterable # pylint: disable=unused-import +from typing import List, Iterable, Optional -from .account import Account # pylint: disable=unused-import +from .account import Account from torba.basetransaction import BaseTransaction, BaseInput, BaseOutput from torba.hash import hash160 -from lbryschema.claim import ClaimDict # pylint: disable=unused-import +from lbryschema.claim import ClaimDict from .script import InputScript, OutputScript @@ -19,6 +19,17 @@ class Output(BaseOutput): script: OutputScript script_class = OutputScript + __slots__ = '_claim_dict', 'channel' + + def __init__(self, *args, channel: Optional['Output'] = None, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._claim_dict = None + self.channel = channel + + def update_annotations(self, annotated): + super().update_annotations(annotated) + self.channel = annotated.channel if annotated else None + def get_fee(self, ledger): name_fee = 0 if self.script.is_claim_name: @@ -42,9 +53,27 @@ class Output(BaseOutput): raise ValueError('No claim_name associated.') @property - def claim(self) -> bytes: + def claim(self) -> ClaimDict: + if self.script.is_claim_name or self.script.is_update_claim: + return ClaimDict.deserialize(self.script.values['claim']) + raise ValueError('Only claim name and claim update have the claim payload.') + + @property + def claim_dict(self) -> dict: + if self._claim_dict is None: + self._claim_dict = self.claim.claim_dict + return self._claim_dict + + @property + def permanent_url(self) -> str: if self.script.is_claim_involved: - return self.script.values['claim'] + if self.channel is not None: + return "{0}#{1}/{2}".format( + self.channel.claim_name, + self.channel.claim_id, + self.claim_name + ) + return "{}#{}".format(self.claim_name, self.claim_id) raise ValueError('No claim associated.') @classmethod