diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index e211b5eb2..cbfd40949 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -1556,7 +1556,7 @@ class Daemon(metaclass=JSONRPCServerType): wallet = self.wallet_manager.get_wallet_or_default(wallet_id) account = wallet.get_account_or_default(account_id) balance = await account.get_detailed_balance( - confirmations=confirmations, reserved_subtotals=True, read_only=True + confirmations=confirmations, read_only=True ) return dict_values_to_lbc(balance) diff --git a/lbry/wallet/account.py b/lbry/wallet/account.py index 83185cee6..e82003363 100644 --- a/lbry/wallet/account.py +++ b/lbry/wallet/account.py @@ -566,35 +566,14 @@ class Account: if gap_changed: self.wallet.save() - async def get_detailed_balance(self, confirmations=0, reserved_subtotals=False, read_only=False): - tips_balance, supports_balance, claims_balance = 0, 0, 0 - get_total_balance = partial(self.get_balance, read_only=read_only, confirmations=confirmations, - include_claims=True) - total = await get_total_balance() - if reserved_subtotals: - claims_balance = await get_total_balance(txo_type__in=CLAIM_TYPES) - for txo in await self.get_support_summary(): - if confirmations > 0 and not 0 < txo.tx_ref.height <= self.ledger.headers.height - (confirmations - 1): - continue - if txo.is_my_input: - supports_balance += txo.amount - else: - tips_balance += txo.amount - reserved = claims_balance + supports_balance + tips_balance - else: - reserved = await self.get_balance( - confirmations=confirmations, include_claims=True, txo_type__gt=0 - ) - return { - 'total': total, - 'available': total - reserved, - 'reserved': reserved, - 'reserved_subtotals': { - 'claims': claims_balance, - 'supports': supports_balance, - 'tips': tips_balance - } if reserved_subtotals else None - } + async def get_detailed_balance(self, confirmations=0, read_only=False): + constraints = {} + if confirmations > 0: + height = self.ledger.headers.height - (confirmations-1) + constraints.update({'height__lte': height, 'height__gt': 0}) + return await self.ledger.db.get_detailed_balance( + accounts=[self], read_only=read_only, **constraints + ) def get_transaction_history(self, read_only=False, **constraints): return self.ledger.get_transaction_history( diff --git a/lbry/wallet/database.py b/lbry/wallet/database.py index 7ca342421..dc21c3f92 100644 --- a/lbry/wallet/database.py +++ b/lbry/wallet/database.py @@ -1142,6 +1142,35 @@ class Database(SQLiteMixin): ) return balance[0]['total'] or 0 + async def get_detailed_balance(self, accounts, read_only=False, **constraints): + constraints['accounts'] = accounts + result = (await self.select_txos( + f"COALESCE(SUM(amount), 0) AS total," + f"COALESCE(SUM(CASE WHEN txo_type != {TXO_TYPES['other']} THEN amount ELSE 0 END), 0) AS reserved," + f"COALESCE(SUM(CASE WHEN txo_type IN ({','.join(map(str, CLAIM_TYPES))}) THEN amount ELSE 0 END), 0) AS claims," + f"COALESCE(SUM(CASE WHEN txo_type = {TXO_TYPES['support']} THEN amount ELSE 0 END), 0) AS supports," + f"COALESCE(SUM(" + f" CASE WHEN" + f" txo_type = {TXO_TYPES['support']} AND" + f" TXI.address IS NOT NULL AND" + f" TXI.address IN (SELECT address FROM account_address WHERE account = :$account__in0)" + f" THEN amount ELSE 0 END), 0) AS my_supports", + is_spent=False, + include_is_my_input=True, + read_only=read_only, + **constraints + ))[0] + return { + "total": result["total"], + "available": result["total"] - result["reserved"], + "reserved": result["reserved"], + "reserved_subtotals": { + "claims": result["claims"], + "supports": result["my_supports"], + "tips": result["supports"] - result["my_supports"] + } + } + async def select_addresses(self, cols, read_only=False, **constraints): return await self.db.execute_fetchall(*query( f"SELECT {cols} FROM pubkey_address JOIN account_address USING (address)", diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index 244a7eace..fb1dd78b4 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -1171,7 +1171,7 @@ class Ledger(metaclass=LedgerRegistry): balance = self._balance_cache.get(account.id) if not balance: balance = self._balance_cache[account.id] = \ - await account.get_detailed_balance(confirmations, reserved_subtotals=True) + await account.get_detailed_balance(confirmations) for key, value in balance.items(): if key == 'reserved_subtotals': for subkey, subvalue in value.items(): @@ -1180,6 +1180,7 @@ class Ledger(metaclass=LedgerRegistry): result[key] += value return result + class TestNetLedger(Ledger): network_name = 'testnet' pubkey_address_prefix = bytes((111,))