Skip to content

Commit

Permalink
Chore: Thread safety for TxList and Cypress test fix (#2148) (#2161)
Browse files Browse the repository at this point in the history
* fixes psbt key error
* use lock to avoid concurrent access
  • Loading branch information
k9ert authored Feb 3, 2023
1 parent f19bcd1 commit 4c12246
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 37 deletions.
1 change: 1 addition & 0 deletions cypress/integration/spec_balances_amounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ describe('Test the rendering of balances and amounts', () => {
cy.get('#satoshis_hot_keys_hot_sign_btn').click()
cy.get('#hot_enter_passphrase__submit').click()
cy.get('#broadcast_local_btn').click()
cy.visit("/")
cy.selectWallet('Ghost wallet')
// Once again because only once doesn't work for some stupid unknown reason
cy.selectWallet('Ghost wallet')
Expand Down
82 changes: 45 additions & 37 deletions src/cryptoadvance/specter/txlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
SpecterTx,
)
from .util.tx import decoderawtransaction
from threading import RLock

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -456,6 +457,8 @@ class TxList(dict, AbstractTxListContext):
ItemCls = WalletAwareTxItem # for inheritance
PSBTCls = SpecterPSBT

lock = RLock()

def __init__(self, path, parent, addresses):
self.parent = parent
self.path = path
Expand Down Expand Up @@ -530,7 +533,11 @@ def get_transactions(self, current_blockheight=None) -> WalletAwareTxItem:

# Make a copy of all txs if the tx.ismine (which should be all of them)
# As TxItem is derived from Dict, the __Dict__ will return a TxItem
transactions: List(TxItem) = [tx.copy() for tx in self.values() if tx.ismine]
with self.lock:
tx_values = self.values()
transactions: List(TxItem) = [
tx.copy() for tx in self.values() if tx.ismine
]
# 1. sorted
transactions = sorted(transactions, key=lambda tx: tx["time"], reverse=True)

Expand Down Expand Up @@ -614,42 +621,43 @@ def add(self, txs):
}
(format of listtransactions)
"""
# here we store all addresses in transactions
# to set them used later
addresses = []
# first we add all transactions to cache
for txid in txs:
tx = txs[txid]
# find minimal from 3 times:
maxtime = 10445238000 # TODO: change after 31 dec 2300 lol
time = min(
tx.get("blocktime", maxtime),
tx.get("timereceived", maxtime),
tx.get("time", maxtime),
)
obj = {
"txid": txid,
"fee": tx.get("fee", None),
"blockheight": tx.get("blockheight", None),
"blockhash": tx.get("blockhash", None),
"time": time,
"blocktime": tx.get("blocktime", None),
"conflicts": tx.get("walletconflicts", []),
"bip125-replaceable": tx.get("bip125-replaceable", "no"),
"hex": tx.get("hex", None),
}
txitem = self.ItemCls(self, self._addresses, self.rawdir, **obj)
self[txid] = txitem
if txitem.tx:
for vout in txitem.tx.vout:
try:
addr = vout.script_pubkey.address(get_network(self.chain))
if addr not in addresses:
addresses.append(addr)
except:
pass # maybe not an address, but a raw script?
self._addresses.set_used(addresses)
self._save()
with self.lock:
# here we store all addresses in transactions
# to set them used later
addresses = []
# first we add all transactions to cache
for txid in txs:
tx = txs[txid]
# find minimal from 3 times:
maxtime = 10445238000 # TODO: change after 31 dec 2300 lol
time = min(
tx.get("blocktime", maxtime),
tx.get("timereceived", maxtime),
tx.get("time", maxtime),
)
obj = {
"txid": txid,
"fee": tx.get("fee", None),
"blockheight": tx.get("blockheight", None),
"blockhash": tx.get("blockhash", None),
"time": time,
"blocktime": tx.get("blocktime", None),
"conflicts": tx.get("walletconflicts", []),
"bip125-replaceable": tx.get("bip125-replaceable", "no"),
"hex": tx.get("hex", None),
}
txitem = self.ItemCls(self, self._addresses, self.rawdir, **obj)
self[txid] = txitem
if txitem.tx:
for vout in txitem.tx.vout:
try:
addr = vout.script_pubkey.address(get_network(self.chain))
if addr not in addresses:
addresses.append(addr)
except:
pass # maybe not an address, but a raw script?
self._addresses.set_used(addresses)
self._save()

def load(self, arr):
"""
Expand Down

0 comments on commit 4c12246

Please sign in to comment.