mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
lightningd/opening_control.c: Remove 'Try fundchannel_cancel again' error.
Changelog-Changed: `fundchannel_cancel` will now succeed even when executed while a `fundchannel_complete` is ongoing; in that case, it will be considered as cancelling the funding *after* the `fundchannel_complete` succeeds.
Let me introduce the concept of "Sequential Consistency":
All operations on parallel processes form a single total order agreed upon by all processes.
So for example, suppose we have parallel invocations of `fundchannel_complete` and `fundchannel_cancel`:
+--[fundchannel_complete]-->
|
--[fundchannel_start]-+
|
+--[fundchannel_cancel]---->
What "Sequential Consistency" means is that the above parallel operations can be serialized as a single total order as:
--[fundchannel_start]--[fundchannel_complete]--[fundchannel_cancel]-->
Or:
--[fundchannel_start]--[fundchannel_cancel]--[fundchannel_complete]-->
In the first case, `fundchannel_complete` succeeds, and the `fundchannel_cancel` invocation also succeeds, sending an `error` to the peer to make them forget the chanel.
In the second case, `fundchannel_cancel` succeeds, and the succeeding `fundchannel_complete` invocation fails, since the funding is already cancelled and there is nothing to complete.
Note that in both cases, `fundchannel_cancel` **always** succeeds.
Unfortunately, prior to this commit, `fundchannel_cancel` could fail with a `Try fundchannel_cancel again` error if the `fundchannel_complete` is ongoing when the `fundchannel_cancel` is initiated.
This violates Sequential Consistency, as there is no single total order that would have caused `fundchannel_cancel` to fail.
This commit is a minimal patch which just reschedules `fundchannel_cancel` to occur after any `fundchannel_complete` that is ongoing.
This commit is contained in:
committed by
ZmnSCPxj, ZmnSCPxj jxPCSmnZ
parent
e8936f9d23
commit
5db69f1b41
@@ -1025,7 +1025,7 @@ def test_funding_cancel_race(node_factory, bitcoind, executor):
|
||||
else:
|
||||
cancels.append(executor.submit(l1.rpc.fundchannel_cancel, n.info['id']))
|
||||
|
||||
# Only one should succeed.
|
||||
# Only up to one should succeed.
|
||||
success = False
|
||||
for c in completes:
|
||||
try:
|
||||
@@ -1036,23 +1036,25 @@ def test_funding_cancel_race(node_factory, bitcoind, executor):
|
||||
except RpcError:
|
||||
pass
|
||||
|
||||
# These may both succeed, iff the above didn't.
|
||||
# At least one of these must succeed, regardless of whether
|
||||
# the completes succeeded or not.
|
||||
cancelled = False
|
||||
for c in cancels:
|
||||
try:
|
||||
c.result(TIMEOUT)
|
||||
cancelled = True
|
||||
assert not success
|
||||
except RpcError:
|
||||
pass
|
||||
|
||||
if cancelled:
|
||||
num_cancel += 1
|
||||
else:
|
||||
assert success
|
||||
# cancel always succeeds, as per Sequential Consistency.
|
||||
# Either the cancel occurred before complete, in which
|
||||
# case it prevents complete from succeeding, or it
|
||||
# occurred after complete, in which case it errors the
|
||||
# channel to force the remote to forget it.
|
||||
assert cancelled
|
||||
num_cancel += 1
|
||||
|
||||
print("Cancelled {} complete {}".format(num_cancel, num_complete))
|
||||
assert num_cancel + num_complete == len(nodes)
|
||||
assert num_cancel == len(nodes)
|
||||
|
||||
# We should have raced at least once!
|
||||
if not VALGRIND:
|
||||
|
||||
Reference in New Issue
Block a user