tlnpeer: reestablish_channel - fix data_loss_protect edge case - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 940fc86749831265c8b4accd9d500b6b9ece2ce2 DIR parent 107f271e583405ea6e3f4fbe7d72733b740a3b98 HTML Author: SomberNight <somber.night@protonmail.com> Date: Mon, 5 Aug 2019 17:43:06 +0200 lnpeer: reestablish_channel - fix data_loss_protect edge case Diffstat: M electrum/lnchannel.py | 1 + M electrum/lnpeer.py | 11 ++++++++++- M electrum/lnutil.py | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) --- DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py t@@ -490,6 +490,7 @@ class Channel(Logger): def get_secret_and_point(self, subject, ctn) -> Tuple[Optional[bytes], bytes]: assert type(subject) is HTLCOwner + assert ctn >= 0, ctn offset = ctn - self.get_oldest_unrevoked_ctn(subject) if subject == REMOTE: if offset > 1: DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py t@@ -743,6 +743,11 @@ class Peer(Logger): their_oldest_unrevoked_remote_ctn = int.from_bytes(channel_reestablish_msg["next_remote_revocation_number"], 'big') their_local_pcp = channel_reestablish_msg.get("my_current_per_commitment_point") their_claim_of_our_last_per_commitment_secret = channel_reestablish_msg.get("your_last_per_commitment_secret") + # sanity checks of received values + if their_next_local_ctn < 0: + raise RemoteMisbehaving(f"channel reestablish: their_next_local_ctn < 0") + if their_oldest_unrevoked_remote_ctn < 0: + raise RemoteMisbehaving(f"channel reestablish: their_oldest_unrevoked_remote_ctn < 0") should_close_we_are_ahead = False should_close_they_are_ahead = False t@@ -788,7 +793,11 @@ class Peer(Logger): if their_local_pcp is None or their_claim_of_our_last_per_commitment_secret is None: # if DLP was enabled, absence of fields is not OK return not dlp_enabled - our_pcs, __ = chan.get_secret_and_point(LOCAL, their_oldest_unrevoked_remote_ctn - 1) + if their_oldest_unrevoked_remote_ctn > 0: + our_pcs, __ = chan.get_secret_and_point(LOCAL, their_oldest_unrevoked_remote_ctn - 1) + else: + assert their_oldest_unrevoked_remote_ctn == 0 + our_pcs = bytes(32) if our_pcs != their_claim_of_our_last_per_commitment_secret: self.logger.error(f"channel_reestablish: (DLP) local PCS mismatch: {bh2u(our_pcs)} != {bh2u(their_claim_of_our_last_per_commitment_secret)}") return False DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py t@@ -151,6 +151,7 @@ class RevocationStore: self.index -= 1 def retrieve_secret(self, index: int) -> bytes: + assert index <= self.START_INDEX, index for bucket in self.buckets: if bucket is None: raise UnableToDeriveSecret()