Skip to content

Commit 8c7fec7

Browse files
committed
poller: unspend coins before spending new
This change ensures that the spend txid of a coin is updated directly to another value in case a conflicting spend is detected. The previous order caused the spend txid to first be cleared, which would misleadingly make the coin appear as confirmed rather than spending.
1 parent b241716 commit 8c7fec7

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

src/bitcoin/poller/looper.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ fn updates(
245245
db_conn.new_unspent_coins(&updated_coins.received);
246246
db_conn.remove_coins(&updated_coins.expired);
247247
db_conn.confirm_coins(&updated_coins.confirmed);
248-
db_conn.spend_coins(&updated_coins.spending);
249248
db_conn.unspend_coins(&updated_coins.expired_spending);
249+
db_conn.spend_coins(&updated_coins.spending);
250250
db_conn.confirm_spend(&updated_coins.spent);
251251
if latest_tip != current_tip {
252252
db_conn.update_tip(&latest_tip);

tests/test_chain.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fixtures import *
44
from test_framework.utils import (
55
wait_for,
6+
wait_for_while_condition_holds,
67
get_txid,
78
spend_coins,
89
RpcError,
@@ -407,7 +408,13 @@ def is_spent_by(lianad, outpoint, txid):
407408
return False
408409
return coin["spend_info"]["txid"] == txid.hex()
409410

410-
wait_for(lambda: is_spent_by(lianad, spent_coin["outpoint"], txid_b))
411+
wait_for_while_condition_holds(
412+
lambda: is_spent_by(lianad, spent_coin["outpoint"], txid_b),
413+
lambda: lianad.rpc.listcoins([], [spent_coin["outpoint"]])["coins"][0][
414+
"spend_info"
415+
]
416+
is not None, # The spend txid changes directly from txid_a to txid_b
417+
)
411418

412419

413420
def test_spend_replacement(lianad, bitcoind):
@@ -454,11 +461,15 @@ def test_spend_replacement(lianad, bitcoind):
454461
# newly marked as spending, the second one's spend_txid should be updated and
455462
# the first one's spend txid should be dropped.
456463
second_txid = sign_and_broadcast_psbt(lianad, second_psbt)
457-
wait_for(
464+
wait_for_while_condition_holds(
458465
lambda: all(
459466
c["spend_info"] is not None and c["spend_info"]["txid"] == second_txid
460467
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
461-
)
468+
),
469+
lambda: lianad.rpc.listcoins([], [coins[1]["outpoint"]])["coins"][0][
470+
"spend_info"
471+
]
472+
is not None, # The spend txid of coin from first spend is updated directly
462473
)
463474
wait_for(
464475
lambda: lianad.rpc.listcoins([], [first_outpoints[0]])["coins"][0]["spend_info"]
@@ -467,11 +478,15 @@ def test_spend_replacement(lianad, bitcoind):
467478

468479
# Now RBF the second transaction with a send-to-self, just because.
469480
third_txid = sign_and_broadcast_psbt(lianad, third_psbt)
470-
wait_for(
481+
wait_for_while_condition_holds(
471482
lambda: all(
472483
c["spend_info"] is not None and c["spend_info"]["txid"] == third_txid
473484
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
474-
)
485+
),
486+
lambda: all(
487+
c["spend_info"] is not None
488+
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
489+
), # The spend txid of all coins are updated directly
475490
)
476491
assert (
477492
lianad.rpc.listcoins([], [first_outpoints[0]])["coins"][0]["spend_info"] is None

0 commit comments

Comments
 (0)