lnhtlc: local update raw messages must not be deleted before acked
In recv_rev() previously all unacked_local_updates were deleted as it was assumed that all of them have been acked at that point by the revoke_and_ack itself. However this is not necessarily the case: see new test case. renamed log['unacked_local_updates'] to log['unacked_local_updates2'] to avoid breaking existing wallet files
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from copy import deepcopy
|
||||
from typing import Optional, Sequence, Tuple, List
|
||||
from typing import Optional, Sequence, Tuple, List, Dict
|
||||
|
||||
from .lnutil import SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, UpdateAddHtlc, Direction, FeeUpdate
|
||||
from .util import bh2u, bfh
|
||||
@@ -33,9 +33,10 @@ class HTLCManager:
|
||||
log[sub]['fails'] = {int(htlc_id): coerceHtlcOwner2IntMap(ctns) for htlc_id, ctns in log[sub]['fails'].items()}
|
||||
# "side who initiated fee update" -> action -> list of FeeUpdates
|
||||
log[sub]['fee_updates'] = [FeeUpdate.from_dict(fee_upd) for fee_upd in log[sub]['fee_updates']]
|
||||
if 'unacked_local_updates' not in log:
|
||||
log['unacked_local_updates'] = []
|
||||
log['unacked_local_updates'] = [bfh(upd) for upd in log['unacked_local_updates']]
|
||||
if 'unacked_local_updates2' not in log:
|
||||
log['unacked_local_updates2'] = {}
|
||||
log['unacked_local_updates2'] = {int(ctn): [bfh(msg) for msg in messages]
|
||||
for ctn, messages in log['unacked_local_updates2'].items()}
|
||||
# maybe bootstrap fee_updates if initial_feerate was provided
|
||||
if initial_feerate is not None:
|
||||
assert type(initial_feerate) is int
|
||||
@@ -74,7 +75,8 @@ class HTLCManager:
|
||||
log[sub]['adds'] = d
|
||||
# fee_updates
|
||||
log[sub]['fee_updates'] = [FeeUpdate.to_dict(fee_upd) for fee_upd in log[sub]['fee_updates']]
|
||||
log['unacked_local_updates'] = [bh2u(upd) for upd in log['unacked_local_updates']]
|
||||
log['unacked_local_updates2'] = {ctn: [bh2u(msg) for msg in messages]
|
||||
for ctn, messages in log['unacked_local_updates2'].items()}
|
||||
return log
|
||||
|
||||
##### Actions on channel:
|
||||
@@ -175,7 +177,7 @@ class HTLCManager:
|
||||
if fee_update.ctns[LOCAL] is None and fee_update.ctns[REMOTE] <= self.ctn_latest(REMOTE):
|
||||
fee_update.ctns[LOCAL] = self.ctn_latest(LOCAL) + 1
|
||||
# no need to keep local update raw msgs anymore, they have just been ACKed.
|
||||
self.log['unacked_local_updates'].clear()
|
||||
self.log['unacked_local_updates2'].pop(self.log[REMOTE]['ctn'], None)
|
||||
|
||||
def discard_unsigned_remote_updates(self):
|
||||
"""Discard updates sent by the remote, that the remote itself
|
||||
@@ -200,11 +202,22 @@ class HTLCManager:
|
||||
if fee_update.ctns[LOCAL] > self.ctn_latest(LOCAL):
|
||||
del self.log[REMOTE]['fee_updates'][i]
|
||||
|
||||
def store_local_update_raw_msg(self, raw_update_msg: bytes):
|
||||
self.log['unacked_local_updates'].append(raw_update_msg)
|
||||
def store_local_update_raw_msg(self, raw_update_msg: bytes, *, is_commitment_signed: bool) -> None:
|
||||
"""We need to be able to replay unacknowledged updates we sent to the remote
|
||||
in case of disconnections. Hence, raw update and commitment_signed messages
|
||||
are stored temporarily (until they are acked)."""
|
||||
# self.log['unacked_local_updates2'][ctn_idx] is a list of raw messages
|
||||
# containing some number of updates and then a single commitment_signed
|
||||
if is_commitment_signed:
|
||||
ctn_idx = self.ctn_latest(REMOTE)
|
||||
else:
|
||||
ctn_idx = self.ctn_latest(REMOTE) + 1
|
||||
if ctn_idx not in self.log['unacked_local_updates2']:
|
||||
self.log['unacked_local_updates2'][ctn_idx] = []
|
||||
self.log['unacked_local_updates2'][ctn_idx].append(raw_update_msg)
|
||||
|
||||
def get_unacked_local_updates(self) -> Sequence[bytes]:
|
||||
return self.log['unacked_local_updates']
|
||||
def get_unacked_local_updates(self) -> Dict[int, Sequence[bytes]]:
|
||||
return self.log['unacked_local_updates2']
|
||||
|
||||
##### Queries re HTLCs:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user