mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-28 16:01:30 +00:00
lnchannel: add more type hints
This commit is contained in:
parent
db84de5493
commit
79d57784c1
5 changed files with 160 additions and 103 deletions
|
@ -23,7 +23,8 @@ from collections import namedtuple, defaultdict
|
||||||
import binascii
|
import binascii
|
||||||
import json
|
import json
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Optional, Dict, List, Tuple, NamedTuple, Set, Callable, Iterable, Sequence, TYPE_CHECKING, Iterator
|
from typing import (Optional, Dict, List, Tuple, NamedTuple, Set, Callable,
|
||||||
|
Iterable, Sequence, TYPE_CHECKING, Iterator, Union)
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ if TYPE_CHECKING:
|
||||||
# lightning channel states
|
# lightning channel states
|
||||||
# Note: these states are persisted by name (for a given channel) in the wallet file,
|
# Note: these states are persisted by name (for a given channel) in the wallet file,
|
||||||
# so consider doing a wallet db upgrade when changing them.
|
# so consider doing a wallet db upgrade when changing them.
|
||||||
class channel_states(IntEnum):
|
class channel_states(IntEnum): # TODO rename to use CamelCase
|
||||||
PREOPENING = 0 # Initial negotiation. Channel will not be reestablished
|
PREOPENING = 0 # Initial negotiation. Channel will not be reestablished
|
||||||
OPENING = 1 # Channel will be reestablished. (per BOLT2)
|
OPENING = 1 # Channel will be reestablished. (per BOLT2)
|
||||||
# - Funding node: has received funding_signed (can broadcast the funding tx)
|
# - Funding node: has received funding_signed (can broadcast the funding tx)
|
||||||
|
@ -75,7 +76,7 @@ class channel_states(IntEnum):
|
||||||
CLOSED = 6 # closing tx has been mined
|
CLOSED = 6 # closing tx has been mined
|
||||||
REDEEMED = 7 # we can stop watching
|
REDEEMED = 7 # we can stop watching
|
||||||
|
|
||||||
class peer_states(IntEnum):
|
class peer_states(IntEnum): # TODO rename to use CamelCase
|
||||||
DISCONNECTED = 0
|
DISCONNECTED = 0
|
||||||
REESTABLISHING = 1
|
REESTABLISHING = 1
|
||||||
GOOD = 2
|
GOOD = 2
|
||||||
|
@ -138,15 +139,15 @@ class Channel(Logger):
|
||||||
self.sweep_address = sweep_address
|
self.sweep_address = sweep_address
|
||||||
self.storage = state
|
self.storage = state
|
||||||
self.db_lock = self.storage.db.lock if self.storage.db else threading.RLock()
|
self.db_lock = self.storage.db.lock if self.storage.db else threading.RLock()
|
||||||
self.config = {} # type: Dict[HTLCOwner, lnutil.Config]
|
self.config = {} # type: Dict[HTLCOwner, Union[LocalConfig, RemoteConfig]]
|
||||||
self.config[LOCAL] = state["local_config"]
|
self.config[LOCAL] = state["local_config"]
|
||||||
self.config[REMOTE] = state["remote_config"]
|
self.config[REMOTE] = state["remote_config"]
|
||||||
self.channel_id = bfh(state["channel_id"])
|
self.channel_id = bfh(state["channel_id"])
|
||||||
self.constraints = state["constraints"]
|
self.constraints = state["constraints"] # type: ChannelConstraints
|
||||||
self.funding_outpoint = state["funding_outpoint"]
|
self.funding_outpoint = state["funding_outpoint"] # type: Outpoint
|
||||||
self.node_id = bfh(state["node_id"])
|
self.node_id = bfh(state["node_id"])
|
||||||
self.short_channel_id = ShortChannelID.normalize(state["short_channel_id"])
|
self.short_channel_id = ShortChannelID.normalize(state["short_channel_id"])
|
||||||
self.onion_keys = state['onion_keys']
|
self.onion_keys = state['onion_keys'] # type: Dict[int, bytes]
|
||||||
self.data_loss_protect_remote_pcp = state['data_loss_protect_remote_pcp']
|
self.data_loss_protect_remote_pcp = state['data_loss_protect_remote_pcp']
|
||||||
self.hm = HTLCManager(log=state['log'], initial_feerate=initial_feerate)
|
self.hm = HTLCManager(log=state['log'], initial_feerate=initial_feerate)
|
||||||
self._state = channel_states[state['state']]
|
self._state = channel_states[state['state']]
|
||||||
|
@ -165,10 +166,10 @@ class Channel(Logger):
|
||||||
return str(scid)
|
return str(scid)
|
||||||
return self.channel_id.hex()
|
return self.channel_id.hex()
|
||||||
|
|
||||||
def set_onion_key(self, key, value):
|
def set_onion_key(self, key: int, value: bytes):
|
||||||
self.onion_keys[key] = value
|
self.onion_keys[key] = value
|
||||||
|
|
||||||
def get_onion_key(self, key):
|
def get_onion_key(self, key: int) -> bytes:
|
||||||
return self.onion_keys.get(key)
|
return self.onion_keys.get(key)
|
||||||
|
|
||||||
def set_data_loss_protect_remote_pcp(self, key, value):
|
def set_data_loss_protect_remote_pcp(self, key, value):
|
||||||
|
@ -262,23 +263,24 @@ class Channel(Logger):
|
||||||
self._chan_ann_without_sigs = chan_ann
|
self._chan_ann_without_sigs = chan_ann
|
||||||
return chan_ann
|
return chan_ann
|
||||||
|
|
||||||
def is_static_remotekey_enabled(self):
|
def is_static_remotekey_enabled(self) -> bool:
|
||||||
return self.storage.get('static_remotekey_enabled')
|
return bool(self.storage.get('static_remotekey_enabled'))
|
||||||
|
|
||||||
def set_short_channel_id(self, short_id):
|
def set_short_channel_id(self, short_id: ShortChannelID) -> None:
|
||||||
self.short_channel_id = short_id
|
self.short_channel_id = short_id
|
||||||
self.storage["short_channel_id"] = short_id
|
self.storage["short_channel_id"] = short_id
|
||||||
|
|
||||||
def get_feerate(self, subject, ctn):
|
def get_feerate(self, subject: HTLCOwner, *, ctn: int) -> int:
|
||||||
|
# returns feerate in sat/kw
|
||||||
return self.hm.get_feerate(subject, ctn)
|
return self.hm.get_feerate(subject, ctn)
|
||||||
|
|
||||||
def get_oldest_unrevoked_feerate(self, subject):
|
def get_oldest_unrevoked_feerate(self, subject: HTLCOwner) -> int:
|
||||||
return self.hm.get_feerate_in_oldest_unrevoked_ctx(subject)
|
return self.hm.get_feerate_in_oldest_unrevoked_ctx(subject)
|
||||||
|
|
||||||
def get_latest_feerate(self, subject):
|
def get_latest_feerate(self, subject: HTLCOwner) -> int:
|
||||||
return self.hm.get_feerate_in_latest_ctx(subject)
|
return self.hm.get_feerate_in_latest_ctx(subject)
|
||||||
|
|
||||||
def get_next_feerate(self, subject):
|
def get_next_feerate(self, subject: HTLCOwner) -> int:
|
||||||
return self.hm.get_feerate_in_next_ctx(subject)
|
return self.hm.get_feerate_in_next_ctx(subject)
|
||||||
|
|
||||||
def get_payments(self):
|
def get_payments(self):
|
||||||
|
@ -316,7 +318,7 @@ class Channel(Logger):
|
||||||
self.hm.channel_open_finished()
|
self.hm.channel_open_finished()
|
||||||
self.peer_state = peer_states.GOOD
|
self.peer_state = peer_states.GOOD
|
||||||
|
|
||||||
def set_state(self, state):
|
def set_state(self, state: channel_states) -> None:
|
||||||
""" set on-chain state """
|
""" set on-chain state """
|
||||||
old_state = self._state
|
old_state = self._state
|
||||||
if (old_state, state) not in state_transitions:
|
if (old_state, state) not in state_transitions:
|
||||||
|
@ -329,7 +331,7 @@ class Channel(Logger):
|
||||||
self.lnworker.save_channel(self)
|
self.lnworker.save_channel(self)
|
||||||
self.lnworker.network.trigger_callback('channel', self)
|
self.lnworker.network.trigger_callback('channel', self)
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self) -> channel_states:
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
def get_state_for_GUI(self):
|
def get_state_for_GUI(self):
|
||||||
|
@ -767,7 +769,7 @@ class Channel(Logger):
|
||||||
assert type(direction) is Direction
|
assert type(direction) is Direction
|
||||||
if ctn is None:
|
if ctn is None:
|
||||||
ctn = self.get_oldest_unrevoked_ctn(subject)
|
ctn = self.get_oldest_unrevoked_ctn(subject)
|
||||||
feerate = self.get_feerate(subject, ctn)
|
feerate = self.get_feerate(subject, ctn=ctn)
|
||||||
conf = self.config[subject]
|
conf = self.config[subject]
|
||||||
if direction == RECEIVED:
|
if direction == RECEIVED:
|
||||||
threshold_sat = received_htlc_trim_threshold_sat(dust_limit_sat=conf.dust_limit_sat, feerate=feerate)
|
threshold_sat = received_htlc_trim_threshold_sat(dust_limit_sat=conf.dust_limit_sat, feerate=feerate)
|
||||||
|
@ -798,30 +800,30 @@ class Channel(Logger):
|
||||||
point = secret_to_pubkey(int.from_bytes(secret, 'big'))
|
point = secret_to_pubkey(int.from_bytes(secret, 'big'))
|
||||||
return secret, point
|
return secret, point
|
||||||
|
|
||||||
def get_secret_and_commitment(self, subject, ctn):
|
def get_secret_and_commitment(self, subject: HTLCOwner, *, ctn: int) -> Tuple[Optional[bytes], PartialTransaction]:
|
||||||
secret, point = self.get_secret_and_point(subject, ctn)
|
secret, point = self.get_secret_and_point(subject, ctn)
|
||||||
ctx = self.make_commitment(subject, point, ctn)
|
ctx = self.make_commitment(subject, point, ctn)
|
||||||
return secret, ctx
|
return secret, ctx
|
||||||
|
|
||||||
def get_commitment(self, subject, ctn) -> PartialTransaction:
|
def get_commitment(self, subject: HTLCOwner, *, ctn: int) -> PartialTransaction:
|
||||||
secret, ctx = self.get_secret_and_commitment(subject, ctn)
|
secret, ctx = self.get_secret_and_commitment(subject, ctn=ctn)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
def get_next_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
def get_next_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
||||||
ctn = self.get_next_ctn(subject)
|
ctn = self.get_next_ctn(subject)
|
||||||
return self.get_commitment(subject, ctn)
|
return self.get_commitment(subject, ctn=ctn)
|
||||||
|
|
||||||
def get_latest_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
def get_latest_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
||||||
ctn = self.get_latest_ctn(subject)
|
ctn = self.get_latest_ctn(subject)
|
||||||
return self.get_commitment(subject, ctn)
|
return self.get_commitment(subject, ctn=ctn)
|
||||||
|
|
||||||
def get_oldest_unrevoked_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
def get_oldest_unrevoked_commitment(self, subject: HTLCOwner) -> PartialTransaction:
|
||||||
ctn = self.get_oldest_unrevoked_ctn(subject)
|
ctn = self.get_oldest_unrevoked_ctn(subject)
|
||||||
return self.get_commitment(subject, ctn)
|
return self.get_commitment(subject, ctn=ctn)
|
||||||
|
|
||||||
def create_sweeptxs(self, ctn: int) -> List[Transaction]:
|
def create_sweeptxs(self, ctn: int) -> List[Transaction]:
|
||||||
from .lnsweep import create_sweeptxs_for_watchtower
|
from .lnsweep import create_sweeptxs_for_watchtower
|
||||||
secret, ctx = self.get_secret_and_commitment(REMOTE, ctn)
|
secret, ctx = self.get_secret_and_commitment(REMOTE, ctn=ctn)
|
||||||
return create_sweeptxs_for_watchtower(self, ctx, secret, self.sweep_address)
|
return create_sweeptxs_for_watchtower(self, ctx, secret, self.sweep_address)
|
||||||
|
|
||||||
def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
|
def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
|
||||||
|
@ -850,9 +852,9 @@ class Channel(Logger):
|
||||||
assert htlc_id not in log['settles']
|
assert htlc_id not in log['settles']
|
||||||
self.hm.send_settle(htlc_id)
|
self.hm.send_settle(htlc_id)
|
||||||
|
|
||||||
def get_payment_hash(self, htlc_id):
|
def get_payment_hash(self, htlc_id: int) -> bytes:
|
||||||
log = self.hm.log[LOCAL]
|
log = self.hm.log[LOCAL]
|
||||||
htlc = log['adds'][htlc_id]
|
htlc = log['adds'][htlc_id] # type: UpdateAddHtlc
|
||||||
return htlc.payment_hash
|
return htlc.payment_hash
|
||||||
|
|
||||||
def decode_onion_error(self, reason: bytes, route: Sequence['RouteEdge'],
|
def decode_onion_error(self, reason: bytes, route: Sequence['RouteEdge'],
|
||||||
|
@ -898,13 +900,13 @@ class Channel(Logger):
|
||||||
error_bytes=error_bytes,
|
error_bytes=error_bytes,
|
||||||
error_reason=reason)
|
error_reason=reason)
|
||||||
|
|
||||||
def pending_local_fee(self):
|
def get_next_fee(self, subject: HTLCOwner) -> int:
|
||||||
return self.constraints.capacity - sum(x.value for x in self.get_next_commitment(LOCAL).outputs())
|
return self.constraints.capacity - sum(x.value for x in self.get_next_commitment(subject).outputs())
|
||||||
|
|
||||||
def get_latest_fee(self, subject):
|
def get_latest_fee(self, subject: HTLCOwner) -> int:
|
||||||
return self.constraints.capacity - sum(x.value for x in self.get_latest_commitment(subject).outputs())
|
return self.constraints.capacity - sum(x.value for x in self.get_latest_commitment(subject).outputs())
|
||||||
|
|
||||||
def update_fee(self, feerate: int, from_us: bool):
|
def update_fee(self, feerate: int, from_us: bool) -> None:
|
||||||
# feerate uses sat/kw
|
# feerate uses sat/kw
|
||||||
if self.constraints.is_initiator != from_us:
|
if self.constraints.is_initiator != from_us:
|
||||||
raise Exception(f"Cannot update_fee: wrong initiator. us: {from_us}")
|
raise Exception(f"Cannot update_fee: wrong initiator. us: {from_us}")
|
||||||
|
@ -917,9 +919,9 @@ class Channel(Logger):
|
||||||
else:
|
else:
|
||||||
self.hm.recv_update_fee(feerate)
|
self.hm.recv_update_fee(feerate)
|
||||||
|
|
||||||
def make_commitment(self, subject, this_point, ctn) -> PartialTransaction:
|
def make_commitment(self, subject: HTLCOwner, this_point: bytes, ctn: int) -> PartialTransaction:
|
||||||
assert type(subject) is HTLCOwner
|
assert type(subject) is HTLCOwner
|
||||||
feerate = self.get_feerate(subject, ctn)
|
feerate = self.get_feerate(subject, ctn=ctn)
|
||||||
other = subject.inverted()
|
other = subject.inverted()
|
||||||
local_msat = self.balance(subject, ctx_owner=subject, ctn=ctn)
|
local_msat = self.balance(subject, ctx_owner=subject, ctn=ctn)
|
||||||
remote_msat = self.balance(other, ctx_owner=subject, ctn=ctn)
|
remote_msat = self.balance(other, ctx_owner=subject, ctn=ctn)
|
||||||
|
@ -969,23 +971,24 @@ class Channel(Logger):
|
||||||
payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
|
payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
|
||||||
|
|
||||||
return make_commitment(
|
return make_commitment(
|
||||||
ctn,
|
ctn=ctn,
|
||||||
this_config.multisig_key.pubkey,
|
local_funding_pubkey=this_config.multisig_key.pubkey,
|
||||||
other_config.multisig_key.pubkey,
|
remote_funding_pubkey=other_config.multisig_key.pubkey,
|
||||||
payment_pubkey,
|
remote_payment_pubkey=payment_pubkey,
|
||||||
self.config[LOCAL if self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
|
funder_payment_basepoint=self.config[LOCAL if self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
|
||||||
self.config[LOCAL if not self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
|
fundee_payment_basepoint=self.config[LOCAL if not self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
|
||||||
other_revocation_pubkey,
|
revocation_pubkey=other_revocation_pubkey,
|
||||||
derive_pubkey(this_config.delayed_basepoint.pubkey, this_point),
|
delayed_pubkey=derive_pubkey(this_config.delayed_basepoint.pubkey, this_point),
|
||||||
other_config.to_self_delay,
|
to_self_delay=other_config.to_self_delay,
|
||||||
self.funding_outpoint.txid,
|
funding_txid=self.funding_outpoint.txid,
|
||||||
self.funding_outpoint.output_index,
|
funding_pos=self.funding_outpoint.output_index,
|
||||||
self.constraints.capacity,
|
funding_sat=self.constraints.capacity,
|
||||||
local_msat,
|
local_amount=local_msat,
|
||||||
remote_msat,
|
remote_amount=remote_msat,
|
||||||
this_config.dust_limit_sat,
|
dust_limit_sat=this_config.dust_limit_sat,
|
||||||
onchain_fees,
|
fees_per_participant=onchain_fees,
|
||||||
htlcs=htlcs)
|
htlcs=htlcs,
|
||||||
|
)
|
||||||
|
|
||||||
def make_closing_tx(self, local_script: bytes, remote_script: bytes,
|
def make_closing_tx(self, local_script: bytes, remote_script: bytes,
|
||||||
fee_sat: int, *, drop_remote = False) -> Tuple[bytes, PartialTransaction]:
|
fee_sat: int, *, drop_remote = False) -> Tuple[bytes, PartialTransaction]:
|
||||||
|
@ -1013,7 +1016,7 @@ class Channel(Logger):
|
||||||
sig = ecc.sig_string_from_der_sig(der_sig[:-1])
|
sig = ecc.sig_string_from_der_sig(der_sig[:-1])
|
||||||
return sig, closing_tx
|
return sig, closing_tx
|
||||||
|
|
||||||
def signature_fits(self, tx: PartialTransaction):
|
def signature_fits(self, tx: PartialTransaction) -> bool:
|
||||||
remote_sig = self.config[LOCAL].current_commitment_signature
|
remote_sig = self.config[LOCAL].current_commitment_signature
|
||||||
preimage_hex = tx.serialize_preimage(0)
|
preimage_hex = tx.serialize_preimage(0)
|
||||||
msg_hash = sha256d(bfh(preimage_hex))
|
msg_hash = sha256d(bfh(preimage_hex))
|
||||||
|
@ -1021,7 +1024,7 @@ class Channel(Logger):
|
||||||
res = ecc.verify_signature(self.config[REMOTE].multisig_key.pubkey, remote_sig, msg_hash)
|
res = ecc.verify_signature(self.config[REMOTE].multisig_key.pubkey, remote_sig, msg_hash)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def force_close_tx(self):
|
def force_close_tx(self) -> PartialTransaction:
|
||||||
tx = self.get_latest_commitment(LOCAL)
|
tx = self.get_latest_commitment(LOCAL)
|
||||||
assert self.signature_fits(tx)
|
assert self.signature_fits(tx)
|
||||||
tx.sign({bh2u(self.config[LOCAL].multisig_key.pubkey): (self.config[LOCAL].multisig_key.privkey, True)})
|
tx.sign({bh2u(self.config[LOCAL].multisig_key.pubkey): (self.config[LOCAL].multisig_key.privkey, True)})
|
||||||
|
@ -1048,11 +1051,11 @@ class Channel(Logger):
|
||||||
self.sweep_info[txid] = {}
|
self.sweep_info[txid] = {}
|
||||||
return self.sweep_info[txid]
|
return self.sweep_info[txid]
|
||||||
|
|
||||||
def sweep_htlc(self, ctx:Transaction, htlc_tx: Transaction):
|
def sweep_htlc(self, ctx: Transaction, htlc_tx: Transaction) -> Optional[SweepInfo]:
|
||||||
# look at the output address, check if it matches
|
# look at the output address, check if it matches
|
||||||
return create_sweeptx_for_their_revoked_htlc(self, ctx, htlc_tx, self.sweep_address)
|
return create_sweeptx_for_their_revoked_htlc(self, ctx, htlc_tx, self.sweep_address)
|
||||||
|
|
||||||
def has_pending_changes(self, subject):
|
def has_pending_changes(self, subject: HTLCOwner) -> bool:
|
||||||
next_htlcs = self.hm.get_htlcs_in_next_ctx(subject)
|
next_htlcs = self.hm.get_htlcs_in_next_ctx(subject)
|
||||||
latest_htlcs = self.hm.get_htlcs_in_latest_ctx(subject)
|
latest_htlcs = self.hm.get_htlcs_in_latest_ctx(subject)
|
||||||
return not (next_htlcs == latest_htlcs and self.get_next_feerate(subject) == self.get_latest_feerate(subject))
|
return not (next_htlcs == latest_htlcs and self.get_next_feerate(subject) == self.get_latest_feerate(subject))
|
||||||
|
|
|
@ -599,13 +599,27 @@ def calc_fees_for_commitment_tx(*, num_htlcs: int, feerate: int,
|
||||||
REMOTE: fee if not is_local_initiator else 0,
|
REMOTE: fee if not is_local_initiator else 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
|
|
||||||
remote_payment_pubkey, funder_payment_basepoint,
|
def make_commitment(
|
||||||
fundee_payment_basepoint, revocation_pubkey,
|
*,
|
||||||
delayed_pubkey, to_self_delay, funding_txid,
|
ctn: int,
|
||||||
funding_pos, funding_sat, local_amount, remote_amount,
|
local_funding_pubkey: bytes,
|
||||||
dust_limit_sat, fees_per_participant,
|
remote_funding_pubkey: bytes,
|
||||||
htlcs: List[ScriptHtlc]) -> PartialTransaction:
|
remote_payment_pubkey: bytes,
|
||||||
|
funder_payment_basepoint: bytes,
|
||||||
|
fundee_payment_basepoint: bytes,
|
||||||
|
revocation_pubkey: bytes,
|
||||||
|
delayed_pubkey: bytes,
|
||||||
|
to_self_delay: int,
|
||||||
|
funding_txid: str,
|
||||||
|
funding_pos: int,
|
||||||
|
funding_sat: int,
|
||||||
|
local_amount: int,
|
||||||
|
remote_amount: int,
|
||||||
|
dust_limit_sat: int,
|
||||||
|
fees_per_participant: Mapping[HTLCOwner, int],
|
||||||
|
htlcs: List[ScriptHtlc]
|
||||||
|
) -> PartialTransaction:
|
||||||
c_input = make_funding_input(local_funding_pubkey, remote_funding_pubkey,
|
c_input = make_funding_input(local_funding_pubkey, remote_funding_pubkey,
|
||||||
funding_pos, funding_txid, funding_sat)
|
funding_pos, funding_txid, funding_sat)
|
||||||
obs = get_obscured_ctn(ctn, funder_payment_basepoint, fundee_payment_basepoint)
|
obs = get_obscured_ctn(ctn, funder_payment_basepoint, fundee_payment_basepoint)
|
||||||
|
@ -618,7 +632,7 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
|
||||||
# commitment tx outputs
|
# commitment tx outputs
|
||||||
local_address = make_commitment_output_to_local_address(revocation_pubkey, to_self_delay, delayed_pubkey)
|
local_address = make_commitment_output_to_local_address(revocation_pubkey, to_self_delay, delayed_pubkey)
|
||||||
remote_address = make_commitment_output_to_remote_address(remote_payment_pubkey)
|
remote_address = make_commitment_output_to_remote_address(remote_payment_pubkey)
|
||||||
# TODO trim htlc outputs here while also considering 2nd stage htlc transactions
|
# note: it is assumed that the given 'htlcs' are all non-dust (dust htlcs already trimmed)
|
||||||
|
|
||||||
# BOLT-03: "Transaction Input and Output Ordering
|
# BOLT-03: "Transaction Input and Output Ordering
|
||||||
# Lexicographic ordering: see BIP69. In the case of identical HTLC outputs,
|
# Lexicographic ordering: see BIP69. In the case of identical HTLC outputs,
|
||||||
|
|
|
@ -23,6 +23,7 @@ from .transaction import Transaction
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .network import Network
|
from .network import Network
|
||||||
from .lnsweep import SweepInfo
|
from .lnsweep import SweepInfo
|
||||||
|
from .lnworker import LNWallet
|
||||||
|
|
||||||
class ListenerItem(NamedTuple):
|
class ListenerItem(NamedTuple):
|
||||||
# this is triggered when the lnwatcher is all done with the outpoint used as index in LNWatcher.tx_progress
|
# this is triggered when the lnwatcher is all done with the outpoint used as index in LNWatcher.tx_progress
|
||||||
|
@ -332,7 +333,7 @@ CHANNEL_OPENING_TIMEOUT = 24*60*60
|
||||||
|
|
||||||
class LNWalletWatcher(LNWatcher):
|
class LNWalletWatcher(LNWatcher):
|
||||||
|
|
||||||
def __init__(self, lnworker, network):
|
def __init__(self, lnworker: 'LNWallet', network: 'Network'):
|
||||||
LNWatcher.__init__(self, network)
|
LNWatcher.__init__(self, network)
|
||||||
self.network = network
|
self.network = network
|
||||||
self.lnworker = lnworker
|
self.lnworker = lnworker
|
||||||
|
|
|
@ -786,14 +786,14 @@ class TestChanReserve(ElectrumTestCase):
|
||||||
alice_idx = self.alice_channel.add_htlc(htlc_dict).htlc_id
|
alice_idx = self.alice_channel.add_htlc(htlc_dict).htlc_id
|
||||||
bob_idx = self.bob_channel.receive_htlc(htlc_dict).htlc_id
|
bob_idx = self.bob_channel.receive_htlc(htlc_dict).htlc_id
|
||||||
force_state_transition(self.alice_channel, self.bob_channel)
|
force_state_transition(self.alice_channel, self.bob_channel)
|
||||||
self.check_bals(one_bitcoin_in_msat*3\
|
self.check_bals(one_bitcoin_in_msat * 3
|
||||||
- self.alice_channel.pending_local_fee(),
|
- self.alice_channel.get_next_fee(LOCAL),
|
||||||
one_bitcoin_in_msat * 5)
|
one_bitcoin_in_msat * 5)
|
||||||
self.bob_channel.settle_htlc(paymentPreimage, bob_idx)
|
self.bob_channel.settle_htlc(paymentPreimage, bob_idx)
|
||||||
self.alice_channel.receive_htlc_settle(paymentPreimage, alice_idx)
|
self.alice_channel.receive_htlc_settle(paymentPreimage, alice_idx)
|
||||||
force_state_transition(self.alice_channel, self.bob_channel)
|
force_state_transition(self.alice_channel, self.bob_channel)
|
||||||
self.check_bals(one_bitcoin_in_msat*3\
|
self.check_bals(one_bitcoin_in_msat * 3
|
||||||
- self.alice_channel.pending_local_fee(),
|
- self.alice_channel.get_next_fee(LOCAL),
|
||||||
one_bitcoin_in_msat * 7)
|
one_bitcoin_in_msat * 7)
|
||||||
# And now let Bob add an HTLC of 1 BTC. This will take Bob's balance
|
# And now let Bob add an HTLC of 1 BTC. This will take Bob's balance
|
||||||
# all the way down to his channel reserve, but since he is not paying
|
# all the way down to his channel reserve, but since he is not paying
|
||||||
|
@ -803,7 +803,7 @@ class TestChanReserve(ElectrumTestCase):
|
||||||
self.alice_channel.receive_htlc(htlc_dict)
|
self.alice_channel.receive_htlc(htlc_dict)
|
||||||
force_state_transition(self.alice_channel, self.bob_channel)
|
force_state_transition(self.alice_channel, self.bob_channel)
|
||||||
self.check_bals(one_bitcoin_in_msat * 3 \
|
self.check_bals(one_bitcoin_in_msat * 3 \
|
||||||
- self.alice_channel.pending_local_fee(),
|
- self.alice_channel.get_next_fee(LOCAL),
|
||||||
one_bitcoin_in_msat * 6)
|
one_bitcoin_in_msat * 6)
|
||||||
|
|
||||||
def check_bals(self, amt1, amt2):
|
def check_bals(self, amt1, amt2):
|
||||||
|
@ -840,7 +840,7 @@ class TestDust(ElectrumTestCase):
|
||||||
self.assertEqual(len(alice_ctx.outputs()), 3)
|
self.assertEqual(len(alice_ctx.outputs()), 3)
|
||||||
self.assertEqual(len(bob_ctx.outputs()), 2)
|
self.assertEqual(len(bob_ctx.outputs()), 2)
|
||||||
default_fee = calc_static_fee(0)
|
default_fee = calc_static_fee(0)
|
||||||
self.assertEqual(bob_channel.pending_local_fee(), default_fee + htlcAmt)
|
self.assertEqual(bob_channel.get_next_fee(LOCAL), default_fee + htlcAmt)
|
||||||
bob_channel.settle_htlc(paymentPreimage, bobHtlcIndex)
|
bob_channel.settle_htlc(paymentPreimage, bobHtlcIndex)
|
||||||
alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
|
alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
|
||||||
force_state_transition(bob_channel, alice_channel)
|
force_state_transition(bob_channel, alice_channel)
|
||||||
|
|
|
@ -510,13 +510,23 @@ class TestLNUtil(ElectrumTestCase):
|
||||||
htlcs = [ScriptHtlc(htlc[x], htlc_obj[x]) for x in range(5)]
|
htlcs = [ScriptHtlc(htlc[x], htlc_obj[x]) for x in range(5)]
|
||||||
|
|
||||||
our_commit_tx = make_commitment(
|
our_commit_tx = make_commitment(
|
||||||
commitment_number,
|
ctn=commitment_number,
|
||||||
local_funding_pubkey, remote_funding_pubkey, remotepubkey,
|
local_funding_pubkey=local_funding_pubkey,
|
||||||
local_payment_basepoint, remote_payment_basepoint,
|
remote_funding_pubkey=remote_funding_pubkey,
|
||||||
local_revocation_pubkey, local_delayedpubkey, local_delay,
|
remote_payment_pubkey=remotepubkey,
|
||||||
funding_tx_id, funding_output_index, funding_amount_satoshi,
|
funder_payment_basepoint=local_payment_basepoint,
|
||||||
to_local_msat, to_remote_msat, local_dust_limit_satoshi,
|
fundee_payment_basepoint=remote_payment_basepoint,
|
||||||
calc_fees_for_commitment_tx(num_htlcs=len(htlcs), feerate=local_feerate_per_kw, is_local_initiator=True), htlcs=htlcs)
|
revocation_pubkey=local_revocation_pubkey,
|
||||||
|
delayed_pubkey=local_delayedpubkey,
|
||||||
|
to_self_delay=local_delay,
|
||||||
|
funding_txid=funding_tx_id,
|
||||||
|
funding_pos=funding_output_index,
|
||||||
|
funding_sat=funding_amount_satoshi,
|
||||||
|
local_amount=to_local_msat,
|
||||||
|
remote_amount=to_remote_msat,
|
||||||
|
dust_limit_sat=local_dust_limit_satoshi,
|
||||||
|
fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=len(htlcs), feerate=local_feerate_per_kw, is_local_initiator=True),
|
||||||
|
htlcs=htlcs)
|
||||||
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
||||||
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
||||||
|
|
||||||
|
@ -587,13 +597,23 @@ class TestLNUtil(ElectrumTestCase):
|
||||||
output_commit_tx= "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
|
output_commit_tx= "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
|
||||||
|
|
||||||
our_commit_tx = make_commitment(
|
our_commit_tx = make_commitment(
|
||||||
commitment_number,
|
ctn=commitment_number,
|
||||||
local_funding_pubkey, remote_funding_pubkey, remotepubkey,
|
local_funding_pubkey=local_funding_pubkey,
|
||||||
local_payment_basepoint, remote_payment_basepoint,
|
remote_funding_pubkey=remote_funding_pubkey,
|
||||||
local_revocation_pubkey, local_delayedpubkey, local_delay,
|
remote_payment_pubkey=remotepubkey,
|
||||||
funding_tx_id, funding_output_index, funding_amount_satoshi,
|
funder_payment_basepoint=local_payment_basepoint,
|
||||||
to_local_msat, to_remote_msat, local_dust_limit_satoshi,
|
fundee_payment_basepoint=remote_payment_basepoint,
|
||||||
calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), htlcs=[])
|
revocation_pubkey=local_revocation_pubkey,
|
||||||
|
delayed_pubkey=local_delayedpubkey,
|
||||||
|
to_self_delay=local_delay,
|
||||||
|
funding_txid=funding_tx_id,
|
||||||
|
funding_pos=funding_output_index,
|
||||||
|
funding_sat=funding_amount_satoshi,
|
||||||
|
local_amount=to_local_msat,
|
||||||
|
remote_amount=to_remote_msat,
|
||||||
|
dust_limit_sat=local_dust_limit_satoshi,
|
||||||
|
fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True),
|
||||||
|
htlcs=[])
|
||||||
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
||||||
|
|
||||||
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
||||||
|
@ -606,13 +626,23 @@ class TestLNUtil(ElectrumTestCase):
|
||||||
output_commit_tx= "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
|
output_commit_tx= "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
|
||||||
|
|
||||||
our_commit_tx = make_commitment(
|
our_commit_tx = make_commitment(
|
||||||
commitment_number,
|
ctn=commitment_number,
|
||||||
local_funding_pubkey, remote_funding_pubkey, remotepubkey,
|
local_funding_pubkey=local_funding_pubkey,
|
||||||
local_payment_basepoint, remote_payment_basepoint,
|
remote_funding_pubkey=remote_funding_pubkey,
|
||||||
local_revocation_pubkey, local_delayedpubkey, local_delay,
|
remote_payment_pubkey=remotepubkey,
|
||||||
funding_tx_id, funding_output_index, funding_amount_satoshi,
|
funder_payment_basepoint=local_payment_basepoint,
|
||||||
to_local_msat, to_remote_msat, local_dust_limit_satoshi,
|
fundee_payment_basepoint=remote_payment_basepoint,
|
||||||
calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), htlcs=[])
|
revocation_pubkey=local_revocation_pubkey,
|
||||||
|
delayed_pubkey=local_delayedpubkey,
|
||||||
|
to_self_delay=local_delay,
|
||||||
|
funding_txid=funding_tx_id,
|
||||||
|
funding_pos=funding_output_index,
|
||||||
|
funding_sat=funding_amount_satoshi,
|
||||||
|
local_amount=to_local_msat,
|
||||||
|
remote_amount=to_remote_msat,
|
||||||
|
dust_limit_sat=local_dust_limit_satoshi,
|
||||||
|
fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True),
|
||||||
|
htlcs=[])
|
||||||
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
||||||
|
|
||||||
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
self.assertEqual(str(our_commit_tx), output_commit_tx)
|
||||||
|
@ -662,15 +692,24 @@ class TestLNUtil(ElectrumTestCase):
|
||||||
# to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
|
# to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
|
||||||
remote_signature = "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0"
|
remote_signature = "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0"
|
||||||
# local_signature = 3044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c3836939
|
# local_signature = 3044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c3836939
|
||||||
htlcs=[]
|
|
||||||
our_commit_tx = make_commitment(
|
our_commit_tx = make_commitment(
|
||||||
commitment_number,
|
ctn=commitment_number,
|
||||||
local_funding_pubkey, remote_funding_pubkey, remotepubkey,
|
local_funding_pubkey=local_funding_pubkey,
|
||||||
local_payment_basepoint, remote_payment_basepoint,
|
remote_funding_pubkey=remote_funding_pubkey,
|
||||||
local_revocation_pubkey, local_delayedpubkey, local_delay,
|
remote_payment_pubkey=remotepubkey,
|
||||||
funding_tx_id, funding_output_index, funding_amount_satoshi,
|
funder_payment_basepoint=local_payment_basepoint,
|
||||||
to_local_msat, to_remote_msat, local_dust_limit_satoshi,
|
fundee_payment_basepoint=remote_payment_basepoint,
|
||||||
calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), htlcs=[])
|
revocation_pubkey=local_revocation_pubkey,
|
||||||
|
delayed_pubkey=local_delayedpubkey,
|
||||||
|
to_self_delay=local_delay,
|
||||||
|
funding_txid=funding_tx_id,
|
||||||
|
funding_pos=funding_output_index,
|
||||||
|
funding_sat=funding_amount_satoshi,
|
||||||
|
local_amount=to_local_msat,
|
||||||
|
remote_amount=to_remote_msat,
|
||||||
|
dust_limit_sat=local_dust_limit_satoshi,
|
||||||
|
fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True),
|
||||||
|
htlcs=[])
|
||||||
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
|
||||||
ref_commit_tx_str = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'
|
ref_commit_tx_str = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'
|
||||||
self.assertEqual(str(our_commit_tx), ref_commit_tx_str)
|
self.assertEqual(str(our_commit_tx), ref_commit_tx_str)
|
||||||
|
|
Loading…
Add table
Reference in a new issue