address_synchronizer.get_history now returns HistoryItem(NamedTuple)s
This commit is contained in:
@@ -26,7 +26,7 @@ import threading
|
||||
import asyncio
|
||||
import itertools
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple, NamedTuple, Sequence
|
||||
|
||||
from . import bitcoin
|
||||
from .bitcoin import COINBASE_MATURITY, TYPE_ADDRESS, TYPE_PUBKEY
|
||||
@@ -57,6 +57,14 @@ class UnrelatedTransactionException(AddTransactionException):
|
||||
return _("Transaction is unrelated to this wallet.")
|
||||
|
||||
|
||||
class HistoryItem(NamedTuple):
|
||||
txid: str
|
||||
tx_mined_status: TxMinedInfo
|
||||
delta: Optional[int]
|
||||
fee: Optional[int]
|
||||
balance: Optional[int]
|
||||
|
||||
|
||||
class AddressSynchronizer(Logger):
|
||||
"""
|
||||
inherited by wallet
|
||||
@@ -418,7 +426,7 @@ class AddressSynchronizer(Logger):
|
||||
return f
|
||||
|
||||
@with_local_height_cached
|
||||
def get_history(self, domain=None):
|
||||
def get_history(self, domain=None) -> Sequence[HistoryItem]:
|
||||
# get domain
|
||||
if domain is None:
|
||||
domain = self.get_addresses()
|
||||
@@ -448,7 +456,11 @@ class AddressSynchronizer(Logger):
|
||||
balance = c + u + x
|
||||
h2 = []
|
||||
for tx_hash, tx_mined_status, delta, fee in history:
|
||||
h2.append((tx_hash, tx_mined_status, delta, fee, balance))
|
||||
h2.append(HistoryItem(txid=tx_hash,
|
||||
tx_mined_status=tx_mined_status,
|
||||
delta=delta,
|
||||
fee=fee,
|
||||
balance=balance))
|
||||
if balance is None or delta is None:
|
||||
balance = None
|
||||
else:
|
||||
|
||||
@@ -94,9 +94,9 @@ class ElectrumGui:
|
||||
+ "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
|
||||
messages = []
|
||||
|
||||
for tx_hash, tx_mined_status, delta, balance in reversed(self.wallet.get_history()):
|
||||
if tx_mined_status.conf:
|
||||
timestamp = tx_mined_status.timestamp
|
||||
for hist_item in reversed(self.wallet.get_history()):
|
||||
if hist_item.tx_mined_status.conf:
|
||||
timestamp = hist_item.tx_mined_status.timestamp
|
||||
try:
|
||||
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
|
||||
except Exception:
|
||||
@@ -104,8 +104,9 @@ class ElectrumGui:
|
||||
else:
|
||||
time_str = 'unconfirmed'
|
||||
|
||||
label = self.wallet.get_label(tx_hash)
|
||||
messages.append( format_str%( time_str, label, format_satoshis(delta, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )
|
||||
label = self.wallet.get_label(hist_item.txid)
|
||||
messages.append(format_str % (time_str, label, format_satoshis(delta, whitespaces=True),
|
||||
format_satoshis(hist_item.balance, whitespaces=True)))
|
||||
|
||||
self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))
|
||||
|
||||
|
||||
@@ -117,9 +117,9 @@ class ElectrumGui:
|
||||
|
||||
b = 0
|
||||
self.history = []
|
||||
for tx_hash, tx_mined_status, value, balance in self.wallet.get_history():
|
||||
if tx_mined_status.conf:
|
||||
timestamp = tx_mined_status.timestamp
|
||||
for hist_item in self.wallet.get_history():
|
||||
if hist_item.tx_mined_status.conf:
|
||||
timestamp = hist_item.tx_mined_status.timestamp
|
||||
try:
|
||||
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
|
||||
except Exception:
|
||||
@@ -127,10 +127,11 @@ class ElectrumGui:
|
||||
else:
|
||||
time_str = 'unconfirmed'
|
||||
|
||||
label = self.wallet.get_label(tx_hash)
|
||||
label = self.wallet.get_label(hist_item.txid)
|
||||
if len(label) > 40:
|
||||
label = label[0:37] + '...'
|
||||
self.history.append( format_str%( time_str, label, format_satoshis(value, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )
|
||||
self.history.append(format_str % (time_str, label, format_satoshis(hist_item.value, whitespaces=True),
|
||||
format_satoshis(hist_item.balance, whitespaces=True)))
|
||||
|
||||
|
||||
def print_balance(self):
|
||||
|
||||
@@ -482,26 +482,27 @@ class Abstract_Wallet(AddressSynchronizer):
|
||||
# we also assume that block timestamps are monotonic (which is false...!)
|
||||
h = self.get_history(domain)
|
||||
balance = 0
|
||||
for tx_hash, tx_mined_status, value, fee, balance in h:
|
||||
if tx_mined_status.timestamp is None or tx_mined_status.timestamp > target_timestamp:
|
||||
return balance - value
|
||||
for hist_item in h:
|
||||
balance = hist_item.balance
|
||||
if hist_item.tx_mined_status.timestamp is None or hist_item.tx_mined_status.timestamp > target_timestamp:
|
||||
return balance - hist_item.delta
|
||||
# return last balance
|
||||
return balance
|
||||
|
||||
def get_onchain_history(self):
|
||||
for tx_hash, tx_mined_status, value, fee, balance in self.get_history():
|
||||
for hist_item in self.get_history():
|
||||
yield {
|
||||
'txid': tx_hash,
|
||||
'fee_sat': fee,
|
||||
'height': tx_mined_status.height,
|
||||
'confirmations': tx_mined_status.conf,
|
||||
'timestamp': tx_mined_status.timestamp,
|
||||
'incoming': True if value>0 else False,
|
||||
'bc_value': Satoshis(value),
|
||||
'bc_balance': Satoshis(balance),
|
||||
'date': timestamp_to_datetime(tx_mined_status.timestamp),
|
||||
'label': self.get_label(tx_hash),
|
||||
'txpos_in_block': tx_mined_status.txpos,
|
||||
'txid': hist_item.tx_mined_status,
|
||||
'fee_sat': hist_item.fee,
|
||||
'height': hist_item.tx_mined_status.height,
|
||||
'confirmations': hist_item.tx_mined_status.conf,
|
||||
'timestamp': hist_item.tx_mined_status.timestamp,
|
||||
'incoming': True if hist_item.delta>0 else False,
|
||||
'bc_value': Satoshis(hist_item.delta),
|
||||
'bc_balance': Satoshis(hist_item.balance),
|
||||
'date': timestamp_to_datetime(hist_item.tx_mined_status.timestamp),
|
||||
'label': self.get_label(hist_item.txid),
|
||||
'txpos_in_block': hist_item.tx_mined_status.txpos,
|
||||
}
|
||||
|
||||
def save_invoice(self, invoice):
|
||||
@@ -757,13 +758,18 @@ class Abstract_Wallet(AddressSynchronizer):
|
||||
|
||||
def get_unconfirmed_base_tx_for_batching(self) -> Optional[Transaction]:
|
||||
candidate = None
|
||||
for tx_hash, tx_mined_status, delta, fee, balance in self.get_history():
|
||||
for hist_item in self.get_history():
|
||||
# tx should not be mined yet
|
||||
if tx_mined_status.conf > 0: continue
|
||||
# tx should be "outgoing" from wallet
|
||||
if delta >= 0:
|
||||
if hist_item.tx_mined_status.conf > 0: continue
|
||||
# conservative future proofing of code: only allow known unconfirmed types
|
||||
if hist_item.tx_mined_status.height not in (TX_HEIGHT_UNCONFIRMED,
|
||||
TX_HEIGHT_UNCONF_PARENT,
|
||||
TX_HEIGHT_LOCAL):
|
||||
continue
|
||||
tx = self.db.get_transaction(tx_hash)
|
||||
# tx should be "outgoing" from wallet
|
||||
if hist_item.delta >= 0:
|
||||
continue
|
||||
tx = self.db.get_transaction(hist_item.txid)
|
||||
if not tx:
|
||||
continue
|
||||
# is_mine outputs should not be spent yet
|
||||
@@ -776,7 +782,7 @@ class Abstract_Wallet(AddressSynchronizer):
|
||||
if not all([self.is_mine(self.get_txin_address(txin)) for txin in tx.inputs()]):
|
||||
continue
|
||||
# prefer txns already in mempool (vs local)
|
||||
if tx_mined_status.height == TX_HEIGHT_LOCAL:
|
||||
if hist_item.tx_mined_status.height == TX_HEIGHT_LOCAL:
|
||||
candidate = tx
|
||||
continue
|
||||
# tx must have opted-in for RBF
|
||||
|
||||
Reference in New Issue
Block a user