mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-28 16:01:30 +00:00
wallet: simplify get_wallet_delta
This commit is contained in:
parent
da6080421e
commit
f125a06453
4 changed files with 62 additions and 77 deletions
|
@ -57,6 +57,14 @@ class HistoryItem(NamedTuple):
|
||||||
balance: Optional[int]
|
balance: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
|
class TxWalletDelta(NamedTuple):
|
||||||
|
is_relevant: bool # "related to wallet?"
|
||||||
|
is_any_input_ismine: bool
|
||||||
|
is_all_input_ismine: bool
|
||||||
|
delta: int
|
||||||
|
fee: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class AddressSynchronizer(Logger):
|
class AddressSynchronizer(Logger):
|
||||||
"""
|
"""
|
||||||
inherited by wallet
|
inherited by wallet
|
||||||
|
@ -652,7 +660,7 @@ class AddressSynchronizer(Logger):
|
||||||
def get_tx_delta(self, tx_hash, address):
|
def get_tx_delta(self, tx_hash, address):
|
||||||
"""effect of tx on address"""
|
"""effect of tx on address"""
|
||||||
delta = 0
|
delta = 0
|
||||||
# substract the value of coins sent from address
|
# subtract the value of coins sent from address
|
||||||
d = self.db.get_txi_addr(tx_hash, address)
|
d = self.db.get_txi_addr(tx_hash, address)
|
||||||
for n, v in d:
|
for n, v in d:
|
||||||
delta -= v
|
delta -= v
|
||||||
|
@ -662,65 +670,43 @@ class AddressSynchronizer(Logger):
|
||||||
delta += v
|
delta += v
|
||||||
return delta
|
return delta
|
||||||
|
|
||||||
@with_transaction_lock
|
def get_wallet_delta(self, tx: Transaction) -> TxWalletDelta:
|
||||||
def get_tx_value(self, txid):
|
|
||||||
"""effect of tx on the entire domain"""
|
|
||||||
delta = 0
|
|
||||||
for addr in self.db.get_txi_addresses(txid):
|
|
||||||
d = self.db.get_txi_addr(txid, addr)
|
|
||||||
for n, v in d:
|
|
||||||
delta -= v
|
|
||||||
for addr in self.db.get_txo_addresses(txid):
|
|
||||||
d = self.db.get_txo_addr(txid, addr)
|
|
||||||
for n, (v, cb) in d.items():
|
|
||||||
delta += v
|
|
||||||
return delta
|
|
||||||
|
|
||||||
def get_wallet_delta(self, tx: Transaction):
|
|
||||||
"""effect of tx on wallet"""
|
"""effect of tx on wallet"""
|
||||||
is_relevant = False # "related to wallet?"
|
is_relevant = False # "related to wallet?"
|
||||||
is_mine = False # "is any input mine?"
|
num_input_ismine = 0
|
||||||
is_pruned = False
|
v_in = v_in_mine = v_out = v_out_mine = 0
|
||||||
is_partial = False
|
with self.lock, self.transaction_lock:
|
||||||
v_in = v_out = v_out_mine = 0
|
|
||||||
for txin in tx.inputs():
|
for txin in tx.inputs():
|
||||||
addr = self.get_txin_address(txin)
|
addr = self.get_txin_address(txin)
|
||||||
if self.is_mine(addr):
|
|
||||||
is_mine = True
|
|
||||||
is_relevant = True
|
|
||||||
value = self.get_txin_value(txin, address=addr)
|
value = self.get_txin_value(txin, address=addr)
|
||||||
if value is None:
|
if self.is_mine(addr):
|
||||||
is_pruned = True
|
num_input_ismine += 1
|
||||||
else:
|
|
||||||
v_in += value
|
|
||||||
else:
|
|
||||||
is_partial = True
|
|
||||||
if not is_mine:
|
|
||||||
is_partial = False
|
|
||||||
for o in tx.outputs():
|
|
||||||
v_out += o.value
|
|
||||||
if self.is_mine(o.address):
|
|
||||||
v_out_mine += o.value
|
|
||||||
is_relevant = True
|
is_relevant = True
|
||||||
if is_pruned:
|
assert value is not None
|
||||||
# some inputs are mine:
|
v_in_mine += value
|
||||||
fee = None
|
if value is None:
|
||||||
if is_mine:
|
v_in = None
|
||||||
v = v_out_mine - v_out
|
elif v_in is not None:
|
||||||
else:
|
v_in += value
|
||||||
# no input is mine
|
for txout in tx.outputs():
|
||||||
v = v_out_mine
|
v_out += txout.value
|
||||||
else:
|
if self.is_mine(txout.address):
|
||||||
v = v_out_mine - v_in
|
v_out_mine += txout.value
|
||||||
if is_partial:
|
is_relevant = True
|
||||||
# some inputs are mine, but not all
|
delta = v_out_mine - v_in_mine
|
||||||
fee = None
|
if v_in is not None:
|
||||||
else:
|
|
||||||
# all inputs are mine
|
|
||||||
fee = v_in - v_out
|
fee = v_in - v_out
|
||||||
if not is_mine:
|
else:
|
||||||
fee = None
|
fee = None
|
||||||
return is_relevant, is_mine, v, fee
|
if fee is None and isinstance(tx, PartialTransaction):
|
||||||
|
fee = tx.get_fee()
|
||||||
|
return TxWalletDelta(
|
||||||
|
is_relevant=is_relevant,
|
||||||
|
is_any_input_ismine=num_input_ismine > 0,
|
||||||
|
is_all_input_ismine=num_input_ismine == len(tx.inputs()),
|
||||||
|
delta=delta,
|
||||||
|
fee=fee,
|
||||||
|
)
|
||||||
|
|
||||||
def get_tx_fee(self, txid: str) -> Optional[int]:
|
def get_tx_fee(self, txid: str) -> Optional[int]:
|
||||||
""" Returns tx_fee or None. Use server fee only if tx is unconfirmed and not mine"""
|
""" Returns tx_fee or None. Use server fee only if tx is unconfirmed and not mine"""
|
||||||
|
@ -747,8 +733,7 @@ class AddressSynchronizer(Logger):
|
||||||
tx = self.db.get_transaction(txid)
|
tx = self.db.get_transaction(txid)
|
||||||
if not tx:
|
if not tx:
|
||||||
return None
|
return None
|
||||||
with self.lock, self.transaction_lock:
|
fee = self.get_wallet_delta(tx).fee
|
||||||
is_relevant, is_mine, v, fee = self.get_wallet_delta(tx)
|
|
||||||
# save result
|
# save result
|
||||||
self.db.add_tx_fee_we_calculated(txid, fee)
|
self.db.add_tx_fee_we_calculated(txid, fee)
|
||||||
self.db.add_num_inputs_to_tx(txid, len(tx.inputs()))
|
self.db.add_num_inputs_to_tx(txid, len(tx.inputs()))
|
||||||
|
|
|
@ -232,7 +232,7 @@ class TxDialog(Factory.Popup):
|
||||||
|
|
||||||
def do_rbf(self):
|
def do_rbf(self):
|
||||||
from .bump_fee_dialog import BumpFeeDialog
|
from .bump_fee_dialog import BumpFeeDialog
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(self.tx)
|
fee = self.wallet.get_wallet_delta(self.tx).fee
|
||||||
if fee is None:
|
if fee is None:
|
||||||
self.app.show_error(_("Can't bump fee: unknown fee for original transaction."))
|
self.app.show_error(_("Can't bump fee: unknown fee for original transaction."))
|
||||||
return
|
return
|
||||||
|
@ -257,7 +257,7 @@ class TxDialog(Factory.Popup):
|
||||||
|
|
||||||
def do_dscancel(self):
|
def do_dscancel(self):
|
||||||
from .dscancel_dialog import DSCancelDialog
|
from .dscancel_dialog import DSCancelDialog
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(self.tx)
|
fee = self.wallet.get_wallet_delta(self.tx).fee
|
||||||
if fee is None:
|
if fee is None:
|
||||||
self.app.show_error(_('Cannot cancel transaction') + ': ' + _('unknown fee for original transaction'))
|
self.app.show_error(_('Cannot cancel transaction') + ': ' + _('unknown fee for original transaction'))
|
||||||
return
|
return
|
||||||
|
|
|
@ -812,18 +812,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||||
if len(txns) >= 3:
|
if len(txns) >= 3:
|
||||||
total_amount = 0
|
total_amount = 0
|
||||||
for tx in txns:
|
for tx in txns:
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
tx_wallet_delta = self.wallet.get_wallet_delta(tx)
|
||||||
if not is_relevant:
|
if not tx_wallet_delta.is_relevant:
|
||||||
continue
|
continue
|
||||||
total_amount += v
|
total_amount += tx_wallet_delta.delta
|
||||||
self.notify(_("{} new transactions: Total amount received in the new transactions {}")
|
self.notify(_("{} new transactions: Total amount received in the new transactions {}")
|
||||||
.format(len(txns), self.format_amount_and_units(total_amount)))
|
.format(len(txns), self.format_amount_and_units(total_amount)))
|
||||||
else:
|
else:
|
||||||
for tx in txns:
|
for tx in txns:
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
tx_wallet_delta = self.wallet.get_wallet_delta(tx)
|
||||||
if not is_relevant:
|
if not tx_wallet_delta.is_relevant:
|
||||||
continue
|
continue
|
||||||
self.notify(_("New transaction: {}").format(self.format_amount_and_units(v)))
|
self.notify(_("New transaction: {}").format(self.format_amount_and_units(tx_wallet_delta.delta)))
|
||||||
|
|
||||||
def notify(self, message):
|
def notify(self, message):
|
||||||
if self.tray:
|
if self.tray:
|
||||||
|
|
|
@ -557,10 +557,11 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||||
"""Returns a map: pubkey -> (keystore, derivation_suffix)"""
|
"""Returns a map: pubkey -> (keystore, derivation_suffix)"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_tx_info(self, tx) -> TxWalletDetails:
|
def get_tx_info(self, tx: Transaction) -> TxWalletDetails:
|
||||||
is_relevant, is_mine, v, fee = self.get_wallet_delta(tx)
|
tx_wallet_delta = self.get_wallet_delta(tx)
|
||||||
if fee is None and isinstance(tx, PartialTransaction):
|
is_relevant = tx_wallet_delta.is_relevant
|
||||||
fee = tx.get_fee()
|
is_any_input_ismine = tx_wallet_delta.is_any_input_ismine
|
||||||
|
fee = tx_wallet_delta.fee
|
||||||
exp_n = None
|
exp_n = None
|
||||||
can_broadcast = False
|
can_broadcast = False
|
||||||
can_bump = False
|
can_bump = False
|
||||||
|
@ -596,28 +597,27 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||||
size = tx.estimated_size()
|
size = tx.estimated_size()
|
||||||
fee_per_byte = fee / size
|
fee_per_byte = fee / size
|
||||||
exp_n = self.config.fee_to_depth(fee_per_byte)
|
exp_n = self.config.fee_to_depth(fee_per_byte)
|
||||||
can_bump = is_mine and not tx.is_final()
|
can_bump = is_any_input_ismine and not tx.is_final()
|
||||||
can_dscancel = (is_mine and not tx.is_final()
|
can_dscancel = (is_any_input_ismine and not tx.is_final()
|
||||||
and not all([self.is_mine(txout.address) for txout in tx.outputs()]))
|
and not all([self.is_mine(txout.address) for txout in tx.outputs()]))
|
||||||
else:
|
else:
|
||||||
status = _('Local')
|
status = _('Local')
|
||||||
can_broadcast = self.network is not None
|
can_broadcast = self.network is not None
|
||||||
can_bump = is_mine and not tx.is_final()
|
can_bump = is_any_input_ismine and not tx.is_final()
|
||||||
else:
|
else:
|
||||||
status = _("Signed")
|
status = _("Signed")
|
||||||
can_broadcast = self.network is not None
|
can_broadcast = self.network is not None
|
||||||
else:
|
else:
|
||||||
|
assert isinstance(tx, PartialTransaction)
|
||||||
s, r = tx.signature_count()
|
s, r = tx.signature_count()
|
||||||
status = _("Unsigned") if s == 0 else _('Partially signed') + ' (%d/%d)'%(s,r)
|
status = _("Unsigned") if s == 0 else _('Partially signed') + ' (%d/%d)'%(s,r)
|
||||||
|
|
||||||
if is_relevant:
|
if is_relevant:
|
||||||
if is_mine:
|
if tx_wallet_delta.is_all_input_ismine:
|
||||||
if fee is not None:
|
assert fee is not None
|
||||||
amount = v + fee
|
amount = tx_wallet_delta.delta + fee
|
||||||
else:
|
else:
|
||||||
amount = v
|
amount = tx_wallet_delta.delta
|
||||||
else:
|
|
||||||
amount = v
|
|
||||||
else:
|
else:
|
||||||
amount = None
|
amount = None
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue