tlnhtlc: move 'next_htlc_id' from ChannelConfig to lnhtlc log - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit c046f2cc1c7741ff8e0b8da50cc1365120c20ba7 DIR parent c8b19aec2ac45eb6464454a35413ad0baf79cb44 HTML Author: SomberNight <somber.night@protonmail.com> Date: Fri, 2 Aug 2019 20:54:41 +0200 lnhtlc: move 'next_htlc_id' from ChannelConfig to lnhtlc log Diffstat: M electrum/lnchannel.py | 8 ++++---- M electrum/lnhtlc.py | 12 ++++++++++++ M electrum/lnpeer.py | 10 +++++----- M electrum/lnutil.py | 2 -- M electrum/tests/test_lnchannel.py | 2 -- 5 files changed, 21 insertions(+), 13 deletions(-) --- DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py t@@ -243,10 +243,10 @@ class Channel(Logger): htlc = UpdateAddHtlc(**htlc) assert isinstance(htlc, UpdateAddHtlc) self._check_can_pay(htlc.amount_msat) - htlc = htlc._replace(htlc_id=self.config[LOCAL].next_htlc_id) + if htlc.htlc_id is None: + htlc = htlc._replace(htlc_id=self.hm.get_next_htlc_id(LOCAL)) self.hm.send_htlc(htlc) self.logger.info("add_htlc") - self.config[LOCAL]=self.config[LOCAL]._replace(next_htlc_id=htlc.htlc_id + 1) return htlc def receive_htlc(self, htlc: UpdateAddHtlc) -> UpdateAddHtlc: t@@ -260,14 +260,14 @@ class Channel(Logger): if isinstance(htlc, dict): # legacy conversion # FIXME remove htlc = UpdateAddHtlc(**htlc) assert isinstance(htlc, UpdateAddHtlc) - htlc = htlc._replace(htlc_id=self.config[REMOTE].next_htlc_id) + if htlc.htlc_id is None: # used in unit tests + htlc = htlc._replace(htlc_id=self.hm.get_next_htlc_id(REMOTE)) if 0 <= self.available_to_spend(REMOTE) < htlc.amount_msat: raise RemoteMisbehaving('Remote dipped below channel reserve.' +\ f' Available at remote: {self.available_to_spend(REMOTE)},' +\ f' HTLC amount: {htlc.amount_msat}') self.hm.recv_htlc(htlc) self.logger.info("receive_htlc") - self.config[REMOTE]=self.config[REMOTE]._replace(next_htlc_id=htlc.htlc_id + 1) return htlc def sign_next_commitment(self): DIR diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py t@@ -18,6 +18,7 @@ class HTLCManager: 'fails': {}, 'fee_updates': [], 'revack_pending': False, + 'next_htlc_id': 0, } log = {LOCAL: deepcopy(initial), REMOTE: deepcopy(initial)} else: t@@ -54,6 +55,9 @@ class HTLCManager: def _set_revack_pending(self, sub: HTLCOwner, pending: bool) -> None: self.log[sub]['revack_pending'] = pending + def get_next_htlc_id(self, sub: HTLCOwner) -> int: + return self.log[sub]['next_htlc_id'] + def to_save(self): log = deepcopy(self.log) for sub in (LOCAL, REMOTE): t@@ -75,14 +79,22 @@ class HTLCManager: def send_htlc(self, htlc: UpdateAddHtlc) -> UpdateAddHtlc: htlc_id = htlc.htlc_id + if htlc_id != self.get_next_htlc_id(LOCAL): + raise Exception(f"unexpected local htlc_id. next should be " + f"{self.get_next_htlc_id(LOCAL)} but got {htlc_id}") self.log[LOCAL]['adds'][htlc_id] = htlc self.log[LOCAL]['locked_in'][htlc_id] = {LOCAL: None, REMOTE: self.ctn_latest(REMOTE)+1} + self.log[LOCAL]['next_htlc_id'] += 1 return htlc def recv_htlc(self, htlc: UpdateAddHtlc) -> None: htlc_id = htlc.htlc_id + if htlc_id != self.get_next_htlc_id(REMOTE): + raise Exception(f"unexpected remote htlc_id. next should be " + f"{self.get_next_htlc_id(REMOTE)} but got {htlc_id}") self.log[REMOTE]['adds'][htlc_id] = htlc self.log[REMOTE]['locked_in'][htlc_id] = {LOCAL: self.ctn_latest(LOCAL)+1, REMOTE: None} + self.log[REMOTE]['next_htlc_id'] += 1 def send_settle(self, htlc_id: int) -> None: self.log[REMOTE]['settles'][htlc_id] = {LOCAL: None, REMOTE: self.ctn_latest(REMOTE) + 1} DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py t@@ -434,7 +434,6 @@ class Peer(Logger): max_accepted_htlcs=5, initial_msat=initial_msat, ctn=-1, - next_htlc_id=0, reserve_sat=546, per_commitment_secret_seed=keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey, funding_locked_received=False, t@@ -518,7 +517,6 @@ class Peer(Logger): max_accepted_htlcs=max_accepted_htlcs, initial_msat=push_msat, ctn = -1, - next_htlc_id = 0, reserve_sat = remote_reserve_sat, htlc_minimum_msat = htlc_min, t@@ -621,7 +619,6 @@ class Peer(Logger): max_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'), # TODO validate initial_msat=remote_balance_sat, ctn = -1, - next_htlc_id = 0, reserve_sat = remote_reserve_sat, htlc_minimum_msat=int.from_bytes(payload['htlc_minimum_msat'], 'big'), # TODO validate next_per_commitment_point=payload['first_per_commitment_point'], t@@ -1142,11 +1139,14 @@ class Peer(Logger): processed_onion = process_onion_packet(onion_packet, associated_data=payment_hash, our_onion_private_key=self.privkey) chan = self.channels[channel_id] assert chan.get_state() == "OPEN" - assert htlc_id == chan.config[REMOTE].next_htlc_id, (htlc_id, chan.config[REMOTE].next_htlc_id) # TODO fail channel instead if cltv_expiry >= 500_000_000: pass # TODO fail the channel # add htlc - htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc, payment_hash=payment_hash, cltv_expiry=cltv_expiry, timestamp=int(time.time())) + htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc, + payment_hash=payment_hash, + cltv_expiry=cltv_expiry, + timestamp=int(time.time()), + htlc_id=htlc_id) htlc = chan.receive_htlc(htlc) local_ctn = chan.get_current_ctn(LOCAL) remote_ctn = chan.get_current_ctn(REMOTE) DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py t@@ -35,7 +35,6 @@ OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"]) class LocalConfig(NamedTuple): # shared channel config fields (DUPLICATED code!!) ctn: int - next_htlc_id: int payment_basepoint: 'Keypair' multisig_key: 'Keypair' htlc_basepoint: 'Keypair' t@@ -59,7 +58,6 @@ class LocalConfig(NamedTuple): class RemoteConfig(NamedTuple): # shared channel config fields (DUPLICATED code!!) ctn: int - next_htlc_id: int payment_basepoint: 'Keypair' multisig_key: 'Keypair' htlc_basepoint: 'Keypair' DIR diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py t@@ -59,7 +59,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator, max_accepted_htlcs=5, initial_msat=remote_amount, ctn = -1, - next_htlc_id = 0, reserve_sat=0, htlc_minimum_msat=1, t@@ -79,7 +78,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator, max_accepted_htlcs=5, initial_msat=local_amount, ctn = 0, - next_htlc_id = 0, reserve_sat=0, per_commitment_secret_seed=seed,