Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

poller: unspend expired before new spend #965

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bitcoin/poller/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ fn updates(
db_conn.new_unspent_coins(&updated_coins.received);
db_conn.remove_coins(&updated_coins.expired);
db_conn.confirm_coins(&updated_coins.confirmed);
db_conn.spend_coins(&updated_coins.spending);
db_conn.unspend_coins(&updated_coins.expired_spending);
db_conn.spend_coins(&updated_coins.spending);
db_conn.confirm_spend(&updated_coins.spent);
if latest_tip != current_tip {
db_conn.update_tip(&latest_tip);
Expand Down
25 changes: 20 additions & 5 deletions tests/test_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from fixtures import *
from test_framework.utils import (
wait_for,
wait_for_while_condition_holds,
get_txid,
spend_coins,
RpcError,
Expand Down Expand Up @@ -407,7 +408,13 @@ def is_spent_by(lianad, outpoint, txid):
return False
return coin["spend_info"]["txid"] == txid.hex()

wait_for(lambda: is_spent_by(lianad, spent_coin["outpoint"], txid_b))
wait_for_while_condition_holds(
lambda: is_spent_by(lianad, spent_coin["outpoint"], txid_b),
lambda: lianad.rpc.listcoins([], [spent_coin["outpoint"]])["coins"][0][
"spend_info"
]
is not None, # The spend txid changes directly from txid_a to txid_b
)


def test_spend_replacement(lianad, bitcoind):
Expand Down Expand Up @@ -454,11 +461,15 @@ def test_spend_replacement(lianad, bitcoind):
# newly marked as spending, the second one's spend_txid should be updated and
# the first one's spend txid should be dropped.
second_txid = sign_and_broadcast_psbt(lianad, second_psbt)
wait_for(
wait_for_while_condition_holds(
lambda: all(
c["spend_info"] is not None and c["spend_info"]["txid"] == second_txid
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
)
),
lambda: lianad.rpc.listcoins([], [coins[1]["outpoint"]])["coins"][0][
"spend_info"
]
is not None, # The spend txid of coin from first spend is updated directly
)
wait_for(
lambda: lianad.rpc.listcoins([], [first_outpoints[0]])["coins"][0]["spend_info"]
Expand All @@ -467,11 +478,15 @@ def test_spend_replacement(lianad, bitcoind):

# Now RBF the second transaction with a send-to-self, just because.
third_txid = sign_and_broadcast_psbt(lianad, third_psbt)
wait_for(
wait_for_while_condition_holds(
lambda: all(
c["spend_info"] is not None and c["spend_info"]["txid"] == third_txid
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
)
),
lambda: all(
c["spend_info"] is not None
for c in lianad.rpc.listcoins([], second_outpoints)["coins"]
), # The spend txid of all coins are updated directly
)
assert (
lianad.rpc.listcoins([], [first_outpoints[0]])["coins"][0]["spend_info"] is None
Expand Down
22 changes: 19 additions & 3 deletions tests/test_framework/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,33 @@ def wait_for(success, timeout=TIMEOUT, debug_fn=None):
debug_fn is logged at each call to success, it can be useful for debugging
when tests fail.
"""
wait_for_while_condition_holds(success, lambda: True, timeout, debug_fn)


def wait_for_while_condition_holds(success, condition, timeout=TIMEOUT, debug_fn=None):
"""
Run success() either until it returns True, or until the timeout is reached,
as long as condition() holds.
debug_fn is logged at each call to success, it can be useful for debugging
when tests fail.
"""
start_time = time.time()
interval = 0.25
while not success() and time.time() < start_time + timeout:
while True:
if time.time() >= start_time + timeout:
raise ValueError("Error waiting for {}", success)
if not condition():
raise ValueError(
"Condition {} not met while waiting for {}", condition, success
)
if success():
return
if debug_fn is not None:
logging.info(debug_fn())
time.sleep(interval)
interval *= 2
if interval > 5:
interval = 5
if time.time() > start_time + timeout:
raise ValueError("Error waiting for {}", success)


def get_txid(hex_tx):
Expand Down
Loading