commit c046f2cc1c7741ff8e0b8da50cc1365120c20ba7
parent c8b19aec2ac45eb6464454a35413ad0baf79cb44
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:
5 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
@@ -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:
@@ -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):
diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
@@ -18,6 +18,7 @@ class HTLCManager:
'fails': {},
'fee_updates': [],
'revack_pending': False,
+ 'next_htlc_id': 0,
}
log = {LOCAL: deepcopy(initial), REMOTE: deepcopy(initial)}
else:
@@ -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):
@@ -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}
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
@@ -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,
@@ -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,
@@ -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'],
@@ -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)
diff --git a/electrum/lnutil.py b/electrum/lnutil.py
@@ -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'
@@ -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'
diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py
@@ -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,
@@ -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,