diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index dbf9ae20d..819f83c0d 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -4461,7 +4461,7 @@ class Daemon(metaclass=JSONRPCServerType): @requires(WALLET_COMPONENT) async def jsonrpc_txo_spend( - self, account_id=None, wallet_id=None, batch_size=500, + self, account_id=None, wallet_id=None, batch_size=100, include_full_tx=False, preview=False, blocking=False, **kwargs): """ Spend transaction outputs, batching into multiple transactions as necessary. @@ -4500,7 +4500,10 @@ class Daemon(metaclass=JSONRPCServerType): accounts = [wallet.get_account_or_error(account_id)] if account_id else wallet.accounts txos = await self.ledger.get_txos( wallet=wallet, accounts=accounts, read_only=True, - **self._constrain_txo_from_kwargs({}, is_not_spent=True, is_my_output=True, **kwargs) + no_tx=True, no_channel_info=True, + **self._constrain_txo_from_kwargs( + {}, is_not_spent=True, is_my_output=True, **kwargs + ) ) txs = [] while txos: diff --git a/lbry/wallet/database.py b/lbry/wallet/database.py index d980bb72d..7ca342421 100644 --- a/lbry/wallet/database.py +++ b/lbry/wallet/database.py @@ -965,16 +965,18 @@ class Database(SQLiteMixin): sql.append("LEFT JOIN txi ON (txi.position=0 AND txi.txid=txo.txid)") return await self.db.execute_fetchall(*query(' '.join(sql), **constraints), read_only=read_only) - async def get_txos(self, wallet=None, no_tx=False, read_only=False, **constraints): + async def get_txos(self, wallet=None, no_tx=False, no_channel_info=False, read_only=False, **constraints): 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, " + "tx.txid, tx.height, tx.position as tx_position, tx.is_verified, " "txo_type, txo.position as txo_position, amount, script" ] + if not no_tx: + select_columns.append("raw") my_accounts = {a.public_key.address for a in wallet.accounts} if wallet else set() my_accounts_sql = "" @@ -1052,32 +1054,33 @@ class Database(SQLiteMixin): txo.received_tips = row['received_tips'] txos.append(txo) - channel_ids = set() - for txo in txos: - if txo.is_claim and txo.can_decode_claim: - if txo.claim.is_signed: - channel_ids.add(txo.claim.signing_channel_id) - if txo.claim.is_channel and wallet: - for account in wallet.accounts: - private_key = await account.get_channel_private_key( - txo.claim.channel.public_key_bytes - ) - if private_key: - txo.private_key = private_key - break - - if channel_ids: - channels = { - txo.claim_id: txo for txo in - (await self.get_channels( - wallet=wallet, - claim_id__in=channel_ids, - read_only=read_only - )) - } + if not no_channel_info: + channel_ids = set() for txo in txos: if txo.is_claim and txo.can_decode_claim: - txo.channel = channels.get(txo.claim.signing_channel_id, None) + if txo.claim.is_signed: + channel_ids.add(txo.claim.signing_channel_id) + if txo.claim.is_channel and wallet: + for account in wallet.accounts: + private_key = await account.get_channel_private_key( + txo.claim.channel.public_key_bytes + ) + if private_key: + txo.private_key = private_key + break + + if channel_ids: + channels = { + txo.claim_id: txo for txo in + (await self.get_channels( + wallet=wallet, + claim_id__in=channel_ids, + read_only=read_only + )) + } + for txo in txos: + if txo.is_claim and txo.can_decode_claim: + txo.channel = channels.get(txo.claim.signing_channel_id, None) return txos diff --git a/lbry/wallet/ledger.py b/lbry/wallet/ledger.py index c68ad3407..cd1a78d4e 100644 --- a/lbry/wallet/ledger.py +++ b/lbry/wallet/ledger.py @@ -231,7 +231,7 @@ class Ledger(metaclass=LedgerRegistry): async def get_effective_amount_estimators(self, funding_accounts: Iterable[Account]): estimators = [] for account in funding_accounts: - utxos = await account.get_utxos() + utxos = await account.get_utxos(no_tx=True, no_channel_info=True) for utxo in utxos: estimators.append(utxo.get_estimator(self)) return estimators diff --git a/lbry/wallet/transaction.py b/lbry/wallet/transaction.py index d5a60c354..c05d7bc12 100644 --- a/lbry/wallet/transaction.py +++ b/lbry/wallet/transaction.py @@ -539,6 +539,7 @@ class Transaction: height: int = -2, position: int = -1, julian_day: int = None) -> None: self._raw = raw self._raw_sans_segwit = None + self._raw_outputs = None self.is_segwit_flag = 0 self.witnesses: List[bytes] = [] self.ref = TXRefMutable(self) @@ -600,6 +601,7 @@ class Transaction: def _reset(self): self._raw = None self._raw_sans_segwit = None + self._raw_outputs = None self.ref.reset() @property @@ -693,9 +695,7 @@ class Transaction: stream.write_compact_size(len(self._inputs)) for txin in self._inputs: txin.serialize_to(stream) - stream.write_compact_size(len(self._outputs)) - for txout in self._outputs: - txout.serialize_to(stream) + self._serialize_outputs(stream) stream.write_uint32(self.locktime) return stream.get_bytes() @@ -709,13 +709,19 @@ class Transaction: txin.serialize_to(stream, txin.txo_ref.txo.script.source) else: txin.serialize_to(stream, b'') - stream.write_compact_size(len(self._outputs)) - for txout in self._outputs: - txout.serialize_to(stream) + self._serialize_outputs(stream) stream.write_uint32(self.locktime) stream.write_uint32(self.signature_hash_type(1)) # signature hash type: SIGHASH_ALL return stream.get_bytes() + def _serialize_outputs(self, stream): + if self._raw_outputs is None: + self._raw_outputs = BCDataStream() + self._raw_outputs.write_compact_size(len(self._outputs)) + for txout in self._outputs: + txout.serialize_to(self._raw_outputs) + stream.write(self._raw_outputs.get_bytes()) + def _deserialize(self): if self._raw is not None: stream = BCDataStream(self._raw)