commit b26dc66567fe40f5623d274a47b131893e368ee9
parent e8471e483b303e6b65f9a2979b9eb9ea530b0490
Author: Janus <ysangkok@gmail.com>
Date: Thu, 11 Oct 2018 17:06:37 +0200
lnhtlc: only store feerate once, don't store heights since we do not roll back
Diffstat:
4 files changed, 43 insertions(+), 63 deletions(-)
diff --git a/electrum/lnbase.py b/electrum/lnbase.py
@@ -530,7 +530,7 @@ class Peer(PrintError):
chan.set_state('DISCONNECTED')
self.network.trigger_callback('channel', chan)
- def make_local_config(self, funding_sat, push_msat, initiator: HTLCOwner, feerate):
+ def make_local_config(self, funding_sat, push_msat, initiator: HTLCOwner):
# key derivation
channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
keypair_generator = lambda family: generate_keypair(self.lnworker.ln_keystore, family, channel_counter)
@@ -552,7 +552,6 @@ class Peer(PrintError):
ctn=-1,
next_htlc_id=0,
amount_msat=initial_msat,
- feerate=feerate,
)
per_commitment_secret_seed = keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey
return local_config, per_commitment_secret_seed
@@ -561,7 +560,7 @@ class Peer(PrintError):
async def channel_establishment_flow(self, password, funding_sat, push_msat, temp_channel_id):
await self.initialized
feerate = self.current_feerate_per_kw()
- local_config, per_commitment_secret_seed = self.make_local_config(funding_sat, push_msat, LOCAL, feerate)
+ local_config, per_commitment_secret_seed = self.make_local_config(funding_sat, push_msat, LOCAL)
# for the first commitment transaction
per_commitment_secret_first = get_per_commitment_secret_from_seed(per_commitment_secret_seed, RevocationStore.START_INDEX)
per_commitment_point_first = secret_to_pubkey(int.from_bytes(per_commitment_secret_first, 'big'))
@@ -611,7 +610,6 @@ class Peer(PrintError):
ctn = -1,
amount_msat=push_msat,
next_htlc_id = 0,
- feerate=feerate,
next_per_commitment_point=remote_per_commitment_point,
current_per_commitment_point=None,
@@ -640,7 +638,7 @@ class Peer(PrintError):
current_commitment_signature = None,
current_htlc_signatures = None,
),
- "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth),
+ "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth, feerate=feerate),
"remote_commitment_to_be_revoked": None,
}
m = HTLCStateMachine(chan)
@@ -675,7 +673,7 @@ class Peer(PrintError):
feerate = int.from_bytes(payload['feerate_per_kw'], 'big')
temp_chan_id = payload['temporary_channel_id']
- local_config, per_commitment_secret_seed = self.make_local_config(funding_sat * 1000, push_msat, REMOTE, feerate)
+ local_config, per_commitment_secret_seed = self.make_local_config(funding_sat * 1000, push_msat, REMOTE)
# for the first commitment transaction
per_commitment_secret_first = get_per_commitment_secret_from_seed(per_commitment_secret_seed, RevocationStore.START_INDEX)
@@ -723,7 +721,6 @@ class Peer(PrintError):
ctn = -1,
amount_msat=remote_balance_sat,
next_htlc_id = 0,
- feerate=feerate,
next_per_commitment_point=payload['first_per_commitment_point'],
current_per_commitment_point=None,
@@ -737,7 +734,7 @@ class Peer(PrintError):
current_commitment_signature = None,
current_htlc_signatures = None,
),
- "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth),
+ "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth, feerate=feerate),
"remote_commitment_to_be_revoked": None,
}
m = HTLCStateMachine(chan)
diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
@@ -1,5 +1,5 @@
# ported from lnd 42de4400bff5105352d0552155f73589166d162b
-from collections import namedtuple
+from collections import namedtuple, defaultdict
import binascii
import json
from enum import Enum, auto
@@ -34,26 +34,14 @@ FUNDEE_SIGNED = FeeUpdateProgress.FUNDEE_SIGNED
FUNDEE_ACKED = FeeUpdateProgress.FUNDEE_ACKED
FUNDER_SIGNED = FeeUpdateProgress.FUNDER_SIGNED
-from collections import namedtuple
-
-class FeeUpdate:
+class FeeUpdate(defaultdict):
def __init__(self, chan, rate):
+ super().__init__(lambda: False)
self.rate = rate
- self.progress = {FUNDEE_SIGNED: None, FUNDEE_ACKED: None, FUNDER_SIGNED: None}
self.chan = chan
- def set(self, field):
- self.progress[field] = self.chan.current_height[LOCAL if self.chan.constraints.is_initiator else REMOTE]
-
- def had(self, field):
- """
- returns true when the progress field given has been
- set at the current commitment number of the funder
- """
- return self.progress[field] is not None
-
def pending_feerate(self, subject):
- if self.had(FUNDEE_ACKED):
+ if self[FUNDEE_ACKED]:
return self.rate
if subject == REMOTE and self.chan.constraints.is_initiator:
return self.rate
@@ -230,9 +218,9 @@ class HTLCStateMachine(PrintError):
for pending_fee in self.fee_mgr:
if not self.constraints.is_initiator:
- pending_fee.set(FUNDEE_SIGNED)
- if self.constraints.is_initiator and pending_fee.had(FUNDEE_ACKED):
- pending_fee.set(FUNDER_SIGNED)
+ pending_fee[FUNDEE_SIGNED] = True
+ if self.constraints.is_initiator and pending_fee[FUNDEE_ACKED]:
+ pending_fee[FUNDER_SIGNED] = True
self.process_new_offchain_ctx(pending_remote_commitment, ours=False)
@@ -283,9 +271,9 @@ class HTLCStateMachine(PrintError):
for pending_fee in self.fee_mgr:
if not self.constraints.is_initiator:
- pending_fee.set(FUNDEE_SIGNED)
- if self.constraints.is_initiator and pending_fee.had(FUNDEE_ACKED):
- pending_fee.set(FUNDER_SIGNED)
+ pending_fee[FUNDEE_SIGNED] = True
+ if self.constraints.is_initiator and pending_fee[FUNDEE_ACKED]:
+ pending_fee[FUNDER_SIGNED] = True
self.process_new_offchain_ctx(pending_local_commitment, ours=True)
@@ -305,25 +293,23 @@ class HTLCStateMachine(PrintError):
last_secret, this_point, next_point = self.points
- new_local_feerate = self.config[LOCAL].feerate
- new_remote_feerate = self.config[REMOTE].feerate
+ new_feerate = self.constraints.feerate
for pending_fee in self.fee_mgr[:]:
- if not self.constraints.is_initiator and pending_fee.had(FUNDEE_SIGNED):
- new_local_feerate = new_remote_feerate = pending_fee.rate
+ if not self.constraints.is_initiator and pending_fee[FUNDEE_SIGNED]:
+ new_feerate = pending_fee.rate
self.fee_mgr.remove(pending_fee)
print("FEERATE CHANGE COMPLETE (non-initiator)")
- if self.constraints.is_initiator and pending_fee.had(FUNDER_SIGNED):
- new_local_feerate = new_remote_feerate = pending_fee.rate
+ if self.constraints.is_initiator and pending_fee[FUNDER_SIGNED]:
+ new_feerate = pending_fee.rate
self.fee_mgr.remove(pending_fee)
print("FEERATE CHANGE COMPLETE (initiator)")
self.config[LOCAL]=self.config[LOCAL]._replace(
ctn=self.config[LOCAL].ctn + 1,
- feerate=new_local_feerate
)
- self.config[REMOTE]=self.config[REMOTE]._replace(
- feerate=new_remote_feerate
+ self.constraints=self.constraints._replace(
+ feerate=new_feerate
)
self.local_commitment = self.pending_local_commitment
@@ -427,7 +413,7 @@ class HTLCStateMachine(PrintError):
for pending_fee in self.fee_mgr:
if self.constraints.is_initiator:
- pending_fee.set(FUNDEE_ACKED)
+ pending_fee[FUNDEE_ACKED] = True
self.local_commitment = self.pending_local_commitment
self.remote_commitment = self.pending_remote_commitment
@@ -471,18 +457,13 @@ class HTLCStateMachine(PrintError):
return self.make_commitment(REMOTE, this_point)
def pending_feerate(self, subject):
- candidate = None
+ candidate = self.constraints.feerate
for pending_fee in self.fee_mgr:
x = pending_fee.pending_feerate(subject)
if x is not None:
candidate = x
- feerate = candidate if candidate is not None else self._committed_feerate[subject]
- return feerate
-
- @property
- def _committed_feerate(self):
- return {LOCAL: self.config[LOCAL].feerate, REMOTE: self.config[REMOTE].feerate}
+ return candidate
@property
def pending_local_commitment(self):
diff --git a/electrum/lnutil.py b/electrum/lnutil.py
@@ -26,7 +26,6 @@ common = [
('ctn' , int),
('amount_msat' , int),
('next_htlc_id' , int),
- ('feerate' , int),
('payment_basepoint' , Keypair),
('multisig_key' , Keypair),
('htlc_basepoint' , Keypair),
@@ -49,7 +48,7 @@ LocalConfig = NamedTuple('LocalConfig', common + [
('current_htlc_signatures', List[bytes]),
])
-ChannelConstraints = namedtuple("ChannelConstraints", ["capacity", "is_initiator", "funding_txn_minimum_depth"])
+ChannelConstraints = namedtuple("ChannelConstraints", ["capacity", "is_initiator", "funding_txn_minimum_depth", "feerate"])
ScriptHtlc = namedtuple('ScriptHtlc', ['redeem_script', 'htlc'])
diff --git a/electrum/tests/test_lnhtlc.py b/electrum/tests/test_lnhtlc.py
@@ -34,7 +34,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
initial_msat=remote_amount,
ctn = 0,
next_htlc_id = 0,
- feerate=local_feerate,
amount_msat=remote_amount,
next_per_commitment_point=nex,
@@ -54,7 +53,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
initial_msat=local_amount,
ctn = 0,
next_htlc_id = 0,
- feerate=local_feerate,
amount_msat=local_amount,
per_commitment_secret_seed=seed,
@@ -63,7 +61,12 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
current_commitment_signature=None,
current_htlc_signatures=None,
),
- "constraints":lnbase.ChannelConstraints(capacity=funding_sat, is_initiator=is_initiator, funding_txn_minimum_depth=3),
+ "constraints":lnbase.ChannelConstraints(
+ capacity=funding_sat,
+ is_initiator=is_initiator,
+ funding_txn_minimum_depth=3,
+ feerate=local_feerate,
+ ),
"node_id":other_node_id,
"remote_commitment_to_be_revoked": None,
'onion_keys': {},
@@ -271,20 +274,20 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
bob_channel.receive_new_commitment(alice_sig, alice_htlc_sigs)
- self.assertNotEqual(fee, bob_channel.config[LOCAL].feerate)
+ self.assertNotEqual(fee, bob_channel.constraints.feerate)
rev, _ = bob_channel.revoke_current_commitment()
- self.assertEqual(fee, bob_channel.config[LOCAL].feerate)
+ self.assertEqual(fee, bob_channel.constraints.feerate)
bob_sig, bob_htlc_sigs = bob_channel.sign_next_commitment()
alice_channel.receive_revocation(rev)
alice_channel.receive_new_commitment(bob_sig, bob_htlc_sigs)
- self.assertNotEqual(fee, alice_channel.config[LOCAL].feerate)
+ self.assertNotEqual(fee, alice_channel.constraints.feerate)
rev, _ = alice_channel.revoke_current_commitment()
- self.assertEqual(fee, alice_channel.config[LOCAL].feerate)
+ self.assertEqual(fee, alice_channel.constraints.feerate)
bob_channel.receive_revocation(rev)
- self.assertEqual(fee, bob_channel.config[REMOTE].feerate)
+ self.assertEqual(fee, bob_channel.constraints.feerate)
def test_UpdateFeeReceiverCommits(self):
@@ -300,20 +303,20 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
alice_sig, alice_htlc_sigs = alice_channel.sign_next_commitment()
bob_channel.receive_new_commitment(alice_sig, alice_htlc_sigs)
- self.assertNotEqual(fee, bob_channel.config[LOCAL].feerate)
+ self.assertNotEqual(fee, bob_channel.constraints.feerate)
bob_revocation, _ = bob_channel.revoke_current_commitment()
- self.assertEqual(fee, bob_channel.config[LOCAL].feerate)
+ self.assertEqual(fee, bob_channel.constraints.feerate)
bob_sig, bob_htlc_sigs = bob_channel.sign_next_commitment()
alice_channel.receive_revocation(bob_revocation)
alice_channel.receive_new_commitment(bob_sig, bob_htlc_sigs)
- self.assertNotEqual(fee, alice_channel.config[LOCAL].feerate)
+ self.assertNotEqual(fee, alice_channel.constraints.feerate)
alice_revocation, _ = alice_channel.revoke_current_commitment()
- self.assertEqual(fee, alice_channel.config[LOCAL].feerate)
+ self.assertEqual(fee, alice_channel.constraints.feerate)
bob_channel.receive_revocation(alice_revocation)
- self.assertEqual(fee, bob_channel.config[REMOTE].feerate)
+ self.assertEqual(fee, bob_channel.constraints.feerate)
@@ -323,7 +326,7 @@ class TestLNHTLCDust(unittest.TestCase):
paymentPreimage = b"\x01" * 32
paymentHash = bitcoin.sha256(paymentPreimage)
- fee_per_kw = alice_channel.config[LOCAL].feerate
+ fee_per_kw = alice_channel.constraints.feerate
self.assertEqual(fee_per_kw, 6000)
htlcAmt = 500 + lnutil.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
self.assertEqual(htlcAmt, 4478)