1
0

lnpeer.reestablish_chan: enforce order of replaying commitsig/revack

When replaying messages during channel-reestablishment,
previously we first resent all update messages, along with potential commitment_signed messages,
and then we potentially resent a single revoke_and_ack.

This can result in incorrect behaviour in case both a commitment_signed and a revoke_and_ack needs to be resent.
When replaying messages, the relative order of commitment_signed and revoke_and_messages needs to be preserved.
(the order of updates (htlc/fee) in relation to the revack messages does not matter)

implements https://github.com/lightning/bolts/pull/810

The logic here is somewhat based on what c-lightning does:
01e5f1886e/channeld/channeld.c (L3059)
This commit is contained in:
SomberNight
2022-05-24 23:49:58 +02:00
parent 7abc7c720f
commit ef4477a930
3 changed files with 187 additions and 24 deletions

View File

@@ -28,6 +28,7 @@ class HTLCManager:
log[LOCAL] = deepcopy(initial)
log[REMOTE] = deepcopy(initial)
log[LOCAL]['unacked_updates'] = {}
log[LOCAL]['was_revoke_last'] = False
# maybe bootstrap fee_updates if initial_feerate was provided
if initial_feerate is not None:
@@ -155,6 +156,7 @@ class HTLCManager:
def send_ctx(self) -> None:
assert self.ctn_latest(REMOTE) == self.ctn_oldest_unrevoked(REMOTE), (self.ctn_latest(REMOTE), self.ctn_oldest_unrevoked(REMOTE))
self._set_revack_pending(REMOTE, True)
self.log[LOCAL]['was_revoke_last'] = False
@with_lock
def recv_ctx(self) -> None:
@@ -165,6 +167,7 @@ class HTLCManager:
def send_rev(self) -> None:
self.log[LOCAL]['ctn'] += 1
self._set_revack_pending(LOCAL, False)
self.log[LOCAL]['was_revoke_last'] = True
# htlcs
for htlc_id in self._maybe_active_htlc_ids[REMOTE]:
ctns = self.log[REMOTE]['locked_in'][htlc_id]
@@ -287,6 +290,11 @@ class HTLCManager:
return {ctn: [bfh(msg) for msg in messages]
for ctn, messages in self.log[LOCAL]['unacked_updates'].items()}
@with_lock
def was_revoke_last(self) -> bool:
"""Whether we sent a revoke_and_ack after the last commitment_signed we sent."""
return self.log[LOCAL].get('was_revoke_last') or False
##### Queries re HTLCs:
def get_htlc_by_id(self, htlc_proposer: HTLCOwner, htlc_id: int) -> UpdateAddHtlc: