mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-31 01:11:35 +00:00
lnhtlc: save logs and feeupdates
This commit is contained in:
parent
eca5545004
commit
d5d9270d0c
5 changed files with 130 additions and 69 deletions
|
@ -6,6 +6,7 @@ from electrum.util import inv_dict, bh2u, bfh
|
|||
from electrum.i18n import _
|
||||
from electrum.lnhtlc import HTLCStateMachine
|
||||
from electrum.lnaddr import lndecode
|
||||
from electrum.lnutil import LOCAL, REMOTE
|
||||
|
||||
from .util import MyTreeWidget, SortableTreeWidgetItem, WindowModalDialog, Buttons, OkButton, CancelButton
|
||||
from .amountedit import BTCAmountEdit
|
||||
|
@ -24,8 +25,8 @@ class ChannelsList(MyTreeWidget):
|
|||
def format_fields(self, chan):
|
||||
return [
|
||||
bh2u(chan.node_id),
|
||||
self.parent.format_amount(chan.local_state.amount_msat//1000),
|
||||
self.parent.format_amount(chan.remote_state.amount_msat//1000),
|
||||
self.parent.format_amount(chan.balance(LOCAL)//1000),
|
||||
self.parent.format_amount(chan.balance(REMOTE)//1000),
|
||||
chan.get_state()
|
||||
]
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ from collections import namedtuple, defaultdict, OrderedDict, defaultdict
|
|||
from .lnutil import Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore
|
||||
from .lnutil import sign_and_get_sig_string, funding_output_script, get_ecdh, get_per_commitment_secret_from_seed
|
||||
from .lnutil import secret_to_pubkey, LNPeerAddr, PaymentFailure
|
||||
from .lnutil import LOCAL, REMOTE
|
||||
from .bitcoin import COIN
|
||||
|
||||
from ecdsa.util import sigdecode_der, sigencode_string_canonize, sigdecode_string
|
||||
|
@ -33,7 +34,7 @@ from .util import PrintError, bh2u, print_error, bfh, aiosafe
|
|||
from .transaction import opcodes, Transaction, TxOutput
|
||||
from .lnonion import new_onion_packet, OnionHopsDataSingle, OnionPerHop, decode_onion_error, ONION_FAILURE_CODE_MAP
|
||||
from .lnaddr import lndecode
|
||||
from .lnhtlc import UpdateAddHtlc, HTLCStateMachine, RevokeAndAck, SettleHtlc
|
||||
from .lnhtlc import HTLCStateMachine, RevokeAndAck
|
||||
|
||||
def channel_id_from_funding_tx(funding_txid, funding_index):
|
||||
funding_txid_bytes = bytes.fromhex(funding_txid)[::-1]
|
||||
|
@ -496,7 +497,8 @@ class Peer(PrintError):
|
|||
to_self_delay=143,
|
||||
dust_limit_sat=546,
|
||||
max_htlc_value_in_flight_msat=0xffffffffffffffff,
|
||||
max_accepted_htlcs=5
|
||||
max_accepted_htlcs=5,
|
||||
initial_msat=funding_sat * 1000 - push_msat,
|
||||
)
|
||||
# TODO derive this?
|
||||
per_commitment_secret_seed = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100.to_bytes(32, 'big')
|
||||
|
@ -536,7 +538,8 @@ class Peer(PrintError):
|
|||
to_self_delay=int.from_bytes(payload['to_self_delay'], byteorder='big'),
|
||||
dust_limit_sat=int.from_bytes(payload['dust_limit_satoshis'], byteorder='big'),
|
||||
max_htlc_value_in_flight_msat=int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big'),
|
||||
max_accepted_htlcs=int.from_bytes(payload["max_accepted_htlcs"], 'big')
|
||||
max_accepted_htlcs=int.from_bytes(payload["max_accepted_htlcs"], 'big'),
|
||||
initial_msat=push_msat
|
||||
)
|
||||
funding_txn_minimum_depth = int.from_bytes(payload['minimum_depth'], 'big')
|
||||
assert remote_config.dust_limit_sat < 600
|
||||
|
@ -844,9 +847,9 @@ class Peer(PrintError):
|
|||
onion = new_onion_packet([x.node_id for x in route], self.secret_key, hops_data, associated_data)
|
||||
amount_msat += total_fee
|
||||
# FIXME this below will probably break with multiple HTLCs
|
||||
msat_local = chan.local_state.amount_msat - amount_msat
|
||||
msat_remote = chan.remote_state.amount_msat + amount_msat
|
||||
htlc = UpdateAddHtlc(amount_msat, payment_hash, final_cltv_expiry_with_deltas)
|
||||
msat_local = chan.balance(LOCAL) - amount_msat
|
||||
msat_remote = chan.balance(REMOTE) + amount_msat
|
||||
htlc = {'amount_msat':amount_msat, 'payment_hash':payment_hash, 'cltv_expiry':final_cltv_expiry_with_deltas}
|
||||
|
||||
# FIXME if we raise here, this channel will not get blacklisted, and the payment can never succeed,
|
||||
# as we will just keep retrying this same path. using the current blacklisting is not a solution as
|
||||
|
@ -861,10 +864,10 @@ class Peer(PrintError):
|
|||
# FIXME what about channel_reserve_satoshis? will the remote fail the channel if we go below? test.
|
||||
raise PaymentFailure('not enough local balance')
|
||||
|
||||
self.send_message(gen_msg("update_add_htlc", channel_id=chan.channel_id, id=chan.local_state.next_htlc_id, cltv_expiry=final_cltv_expiry_with_deltas, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes()))
|
||||
htlc_id = chan.add_htlc(htlc)
|
||||
self.send_message(gen_msg("update_add_htlc", channel_id=chan.channel_id, id=htlc_id, cltv_expiry=final_cltv_expiry_with_deltas, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes()))
|
||||
|
||||
chan.add_htlc(htlc)
|
||||
self.attempted_route[(chan.channel_id, htlc.htlc_id)] = route
|
||||
self.attempted_route[(chan.channel_id, htlc_id)] = route
|
||||
|
||||
sig_64, htlc_sigs = chan.sign_next_commitment()
|
||||
self.send_message(gen_msg("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=len(htlc_sigs), htlc_signature=b"".join(htlc_sigs)))
|
||||
|
@ -947,7 +950,7 @@ class Peer(PrintError):
|
|||
assert amount_msat == expected_received_msat
|
||||
payment_hash = htlc["payment_hash"]
|
||||
|
||||
htlc = UpdateAddHtlc(amount_msat, payment_hash, cltv_expiry)
|
||||
htlc = {'amount_msat': amount_msat, 'payment_hash':payment_hash, 'cltv_expiry':cltv_expiry}
|
||||
|
||||
chan.receive_htlc(htlc)
|
||||
|
||||
|
@ -967,7 +970,7 @@ class Peer(PrintError):
|
|||
# remote commitment transaction without htlcs
|
||||
# FIXME why is this not using the HTLC state machine?
|
||||
bare_ctx = chan.make_commitment(chan.remote_state.ctn + 1, False, chan.remote_state.next_per_commitment_point,
|
||||
chan.remote_state.amount_msat - expected_received_msat, chan.local_state.amount_msat + expected_received_msat)
|
||||
chan.balance(REMOTE) - expected_received_msat, chan.balance(LOCAL) + expected_received_msat)
|
||||
self.lnwatcher.process_new_offchain_ctx(chan, bare_ctx, ours=False)
|
||||
sig_64 = sign_and_get_sig_string(bare_ctx, chan.local_config, chan.remote_config)
|
||||
self.send_message(gen_msg("commitment_signed", channel_id=channel_id, signature=sig_64, num_htlcs=0))
|
||||
|
|
|
@ -16,7 +16,7 @@ from .lnutil import sign_and_get_sig_string
|
|||
from .lnutil import make_htlc_tx_with_open_channel, make_commitment, make_received_htlc, make_offered_htlc
|
||||
from .lnutil import HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT
|
||||
from .lnutil import funding_output_script, extract_ctn_from_tx_and_chan
|
||||
from .lnutil import LOCAL, REMOTE, SENT, RECEIVED
|
||||
from .lnutil import LOCAL, REMOTE, SENT, RECEIVED, HTLCOwner
|
||||
from .transaction import Transaction
|
||||
|
||||
|
||||
|
@ -34,12 +34,22 @@ FUNDEE_ACKED = FeeUpdateProgress.FUNDEE_ACKED
|
|||
FUNDER_SIGNED = FeeUpdateProgress.FUNDER_SIGNED
|
||||
COMMITTED = FeeUpdateProgress.COMMITTED
|
||||
|
||||
class FeeUpdate:
|
||||
from collections import namedtuple
|
||||
|
||||
def __init__(self, chan, feerate):
|
||||
self.rate = feerate
|
||||
self.proposed = chan.remote_state.ctn if not chan.constraints.is_initiator else chan.local_state.ctn
|
||||
self.progress = {FUNDEE_SIGNED: None, FUNDEE_ACKED: None, FUNDER_SIGNED: None, COMMITTED: None}
|
||||
class FeeUpdate:
|
||||
def __init__(self, chan, **kwargs):
|
||||
if 'rate' in kwargs:
|
||||
self.rate = kwargs['rate']
|
||||
else:
|
||||
assert False
|
||||
if 'proposed' not in kwargs:
|
||||
self.proposed = chan.remote_state.ctn if not chan.constraints.is_initiator else chan.local_state.ctn
|
||||
else:
|
||||
self.proposed = kwargs['proposed']
|
||||
if 'progress' not in kwargs:
|
||||
self.progress = {FUNDEE_SIGNED: None, FUNDEE_ACKED: None, FUNDER_SIGNED: None, COMMITTED: None}
|
||||
else:
|
||||
self.progress = {FeeUpdateProgress[x.partition('.')[2]]: y for x,y in kwargs['progress'].items()}
|
||||
self.chan = chan
|
||||
|
||||
@property
|
||||
|
@ -65,30 +75,30 @@ class FeeUpdate:
|
|||
if subject == LOCAL and not self.chan.constraints.is_initiator:
|
||||
return self.rate
|
||||
|
||||
class UpdateAddHtlc:
|
||||
def __init__(self, amount_msat, payment_hash, cltv_expiry):
|
||||
self.amount_msat = amount_msat
|
||||
self.payment_hash = payment_hash
|
||||
self.cltv_expiry = cltv_expiry
|
||||
def to_save(self):
|
||||
return {'rate': self.rate, 'proposed': self.proposed, 'progress': self.progress}
|
||||
|
||||
# the height the htlc was locked in at, or None
|
||||
self.locked_in = {LOCAL: None, REMOTE: None}
|
||||
|
||||
self.settled = {LOCAL: None, REMOTE: None}
|
||||
|
||||
self.htlc_id = None
|
||||
|
||||
def as_tuple(self):
|
||||
return (self.htlc_id, self.amount_msat, self.payment_hash, self.cltv_expiry, self.locked_in[REMOTE], self.locked_in[LOCAL], self.settled)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.as_tuple())
|
||||
|
||||
def __eq__(self, o):
|
||||
return type(o) is UpdateAddHtlc and self.as_tuple() == o.as_tuple()
|
||||
|
||||
def __repr__(self):
|
||||
return "UpdateAddHtlc" + str(self.as_tuple())
|
||||
class UpdateAddHtlc(namedtuple('UpdateAddHtlc', ['amount_msat', 'payment_hash', 'cltv_expiry', 'settled', 'locked_in', 'htlc_id'])):
|
||||
__slots__ = ()
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if len(args) > 0:
|
||||
args = list(args)
|
||||
if type(args[1]) is str:
|
||||
args[1] = bfh(args[1])
|
||||
args[3] = {HTLCOwner(int(x)): y for x,y in args[3].items()}
|
||||
args[4] = {HTLCOwner(int(x)): y for x,y in args[4].items()}
|
||||
return super().__new__(cls, *args)
|
||||
if type(kwargs['payment_hash']) is str:
|
||||
kwargs['payment_hash'] = bfh(kwargs['payment_hash'])
|
||||
if 'locked_in' not in kwargs:
|
||||
kwargs['locked_in'] = {LOCAL: None, REMOTE: None}
|
||||
else:
|
||||
kwargs['locked_in'] = {HTLCOwner(int(x)): y for x,y in kwargs['locked_in']}
|
||||
if 'settled' not in kwargs:
|
||||
kwargs['settled'] = {LOCAL: None, REMOTE: None}
|
||||
else:
|
||||
kwargs['settled'] = {HTLCOwner(int(x)): y for x,y in kwargs['settled']}
|
||||
return super().__new__(cls, **kwargs)
|
||||
|
||||
is_key = lambda k: k.endswith("_basepoint") or k.endswith("_key")
|
||||
|
||||
|
@ -155,10 +165,22 @@ class HTLCStateMachine(PrintError):
|
|||
self.remote_commitment_to_be_revoked = Transaction(state["remote_commitment_to_be_revoked"])
|
||||
|
||||
self.log = {LOCAL: [], REMOTE: []}
|
||||
for strname, subject in [('remote_log', REMOTE), ('local_log', LOCAL)]:
|
||||
if strname not in state: continue
|
||||
for typ,y in state[strname]:
|
||||
if typ == "UpdateAddHtlc":
|
||||
self.log[subject].append(UpdateAddHtlc(*decodeAll(y)))
|
||||
elif typ == "SettleHtlc":
|
||||
self.log[subject].append(SettleHtlc(*decodeAll(y)))
|
||||
else:
|
||||
assert False
|
||||
|
||||
self.name = name
|
||||
|
||||
self.fee_mgr = []
|
||||
if 'fee_updates' in state:
|
||||
for y in state['fee_updates']:
|
||||
self.fee_mgr.append(FeeUpdate(self, **y))
|
||||
|
||||
self.local_commitment = self.pending_local_commitment
|
||||
self.remote_commitment = self.pending_remote_commitment
|
||||
|
@ -190,13 +212,12 @@ class HTLCStateMachine(PrintError):
|
|||
AddHTLC adds an HTLC to the state machine's local update log. This method
|
||||
should be called when preparing to send an outgoing HTLC.
|
||||
"""
|
||||
assert type(htlc) is UpdateAddHtlc
|
||||
assert type(htlc) is dict
|
||||
htlc = UpdateAddHtlc(**htlc, htlc_id=self.local_state.next_htlc_id)
|
||||
self.log[LOCAL].append(htlc)
|
||||
self.print_error("add_htlc")
|
||||
htlc_id = self.local_state.next_htlc_id
|
||||
self.local_state=self.local_state._replace(next_htlc_id=htlc_id + 1)
|
||||
htlc.htlc_id = htlc_id
|
||||
return htlc_id
|
||||
self.local_state=self.local_state._replace(next_htlc_id=htlc.htlc_id + 1)
|
||||
return htlc.htlc_id
|
||||
|
||||
def receive_htlc(self, htlc):
|
||||
"""
|
||||
|
@ -204,13 +225,12 @@ class HTLCStateMachine(PrintError):
|
|||
method should be called in response to receiving a new HTLC from the remote
|
||||
party.
|
||||
"""
|
||||
self.print_error("receive_htlc")
|
||||
assert type(htlc) is UpdateAddHtlc
|
||||
assert type(htlc) is dict
|
||||
htlc = UpdateAddHtlc(**htlc, htlc_id = self.remote_state.next_htlc_id)
|
||||
self.log[REMOTE].append(htlc)
|
||||
htlc_id = self.remote_state.next_htlc_id
|
||||
self.remote_state=self.remote_state._replace(next_htlc_id=htlc_id + 1)
|
||||
htlc.htlc_id = htlc_id
|
||||
return htlc_id
|
||||
self.print_error("receive_htlc")
|
||||
self.remote_state=self.remote_state._replace(next_htlc_id=htlc.htlc_id + 1)
|
||||
return htlc.htlc_id
|
||||
|
||||
def sign_next_commitment(self):
|
||||
"""
|
||||
|
@ -431,6 +451,9 @@ class HTLCStateMachine(PrintError):
|
|||
amount_msat = self.local_state.amount_msat + (received_this_batch - sent_this_batch)
|
||||
)
|
||||
|
||||
self.balance(LOCAL)
|
||||
self.balance(REMOTE)
|
||||
|
||||
for pending_fee in self.fee_mgr:
|
||||
if pending_fee.is_proposed():
|
||||
if self.constraints.is_initiator:
|
||||
|
@ -441,6 +464,26 @@ class HTLCStateMachine(PrintError):
|
|||
self.remote_commitment_to_be_revoked = prev_remote_commitment
|
||||
return received_this_batch, sent_this_batch
|
||||
|
||||
def balance(self, subject):
|
||||
initial = self.local_config.initial_msat if subject == LOCAL else self.remote_config.initial_msat
|
||||
|
||||
for x in self.log[-subject]:
|
||||
if type(x) is not SettleHtlc: continue
|
||||
htlc = self.lookup_htlc(self.log[subject], x.htlc_id)
|
||||
htlc_height = htlc.settled[subject]
|
||||
if htlc_height is not None and htlc_height <= self.current_height[subject]:
|
||||
initial -= htlc.amount_msat
|
||||
|
||||
for x in self.log[subject]:
|
||||
if type(x) is not SettleHtlc: continue
|
||||
htlc = self.lookup_htlc(self.log[-subject], x.htlc_id)
|
||||
htlc_height = htlc.settled[-subject]
|
||||
if htlc_height is not None and htlc_height <= self.current_height[-subject]:
|
||||
initial += htlc.amount_msat
|
||||
|
||||
assert initial == (self.local_state.amount_msat if subject == LOCAL else self.remote_state.amount_msat)
|
||||
return initial
|
||||
|
||||
@staticmethod
|
||||
def htlcsum(htlcs):
|
||||
amount_unsettled = 0
|
||||
|
@ -611,13 +654,13 @@ class HTLCStateMachine(PrintError):
|
|||
def update_fee(self, feerate):
|
||||
if not self.constraints.is_initiator:
|
||||
raise Exception("only initiator can update_fee, this counterparty is not initiator")
|
||||
pending_fee = FeeUpdate(self, feerate)
|
||||
pending_fee = FeeUpdate(self, rate=feerate)
|
||||
self.fee_mgr.append(pending_fee)
|
||||
|
||||
def receive_update_fee(self, feerate):
|
||||
if self.constraints.is_initiator:
|
||||
raise Exception("only the non-initiator can receive_update_fee, this counterparty is initiator")
|
||||
pending_fee = FeeUpdate(self, feerate)
|
||||
pending_fee = FeeUpdate(self, rate=feerate)
|
||||
self.fee_mgr.append(pending_fee)
|
||||
|
||||
def to_save(self):
|
||||
|
@ -632,6 +675,9 @@ class HTLCStateMachine(PrintError):
|
|||
"funding_outpoint": self.funding_outpoint,
|
||||
"node_id": self.node_id,
|
||||
"remote_commitment_to_be_revoked": str(self.remote_commitment_to_be_revoked),
|
||||
"remote_log": [(type(x).__name__, x) for x in self.log[REMOTE]],
|
||||
"local_log": [(type(x).__name__, x) for x in self.log[LOCAL]],
|
||||
"fee_updates": [x.to_save() for x in self.fee_mgr],
|
||||
}
|
||||
|
||||
def serialize(self):
|
||||
|
@ -643,7 +689,13 @@ class HTLCStateMachine(PrintError):
|
|||
return binascii.hexlify(o).decode("ascii")
|
||||
if isinstance(o, RevocationStore):
|
||||
return o.serialize()
|
||||
if isinstance(o, SettleHtlc):
|
||||
return json.dumps(('SettleHtlc', namedtuples_to_dict(o)))
|
||||
if isinstance(o, UpdateAddHtlc):
|
||||
return json.dumps(('UpdateAddHtlc', namedtuples_to_dict(o)))
|
||||
return super(MyJsonEncoder, self)
|
||||
for fee_upd in serialized_channel['fee_updates']:
|
||||
fee_upd['progress'] = {str(k): v for k,v in fee_upd['progress'].items()}
|
||||
dumped = MyJsonEncoder().encode(serialized_channel)
|
||||
roundtripped = json.loads(dumped)
|
||||
reconstructed = HTLCStateMachine(roundtripped)
|
||||
|
|
|
@ -18,7 +18,7 @@ HTLC_SUCCESS_WEIGHT = 703
|
|||
Keypair = namedtuple("Keypair", ["pubkey", "privkey"])
|
||||
ChannelConfig = namedtuple("ChannelConfig", [
|
||||
"payment_basepoint", "multisig_key", "htlc_basepoint", "delayed_basepoint", "revocation_basepoint",
|
||||
"to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
|
||||
"to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs", "initial_msat"])
|
||||
OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
|
||||
RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_msat", "revocation_store", "current_per_commitment_point", "next_htlc_id", "feerate"])
|
||||
LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_msat", "next_htlc_id", "funding_locked_received", "was_announced", "current_commitment_signature", "current_htlc_signatures", "feerate"])
|
||||
|
|
|
@ -25,7 +25,8 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
|
|||
to_self_delay=l_csv,
|
||||
dust_limit_sat=l_dust,
|
||||
max_htlc_value_in_flight_msat=500000 * 1000,
|
||||
max_accepted_htlcs=5
|
||||
max_accepted_htlcs=5,
|
||||
initial_msat=local_amount,
|
||||
)
|
||||
remote_config=lnbase.ChannelConfig(
|
||||
payment_basepoint=other_pubkeys[0],
|
||||
|
@ -36,7 +37,8 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
|
|||
to_self_delay=r_csv,
|
||||
dust_limit_sat=r_dust,
|
||||
max_htlc_value_in_flight_msat=500000 * 1000,
|
||||
max_accepted_htlcs=5
|
||||
max_accepted_htlcs=5,
|
||||
initial_msat=remote_amount,
|
||||
)
|
||||
|
||||
return {
|
||||
|
@ -132,11 +134,11 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
|
|||
|
||||
self.paymentPreimage = b"\x01" * 32
|
||||
paymentHash = bitcoin.sha256(self.paymentPreimage)
|
||||
self.htlc = lnhtlc.UpdateAddHtlc(
|
||||
payment_hash = paymentHash,
|
||||
amount_msat = one_bitcoin_in_msat,
|
||||
cltv_expiry = 5,
|
||||
)
|
||||
self.htlc = {
|
||||
'payment_hash' : paymentHash,
|
||||
'amount_msat' : one_bitcoin_in_msat,
|
||||
'cltv_expiry' : 5,
|
||||
}
|
||||
|
||||
# First Alice adds the outgoing HTLC to her local channel's state
|
||||
# update log. Then Alice sends this wire message over to Bob who adds
|
||||
|
@ -144,6 +146,7 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
|
|||
self.aliceHtlcIndex = self.alice_channel.add_htlc(self.htlc)
|
||||
|
||||
self.bobHtlcIndex = self.bob_channel.receive_htlc(self.htlc)
|
||||
self.htlc = self.bob_channel.log[lnutil.REMOTE][0]
|
||||
|
||||
def test_SimpleAddSettleWorkflow(self):
|
||||
alice_channel, bob_channel = self.alice_channel, self.bob_channel
|
||||
|
@ -250,6 +253,8 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
|
|||
# revocation.
|
||||
#self.assertEqual(alice_channel.local_update_log, [], "alice's local not updated, should be empty, has %s entries instead"% len(alice_channel.local_update_log))
|
||||
#self.assertEqual(alice_channel.remote_update_log, [], "alice's remote not updated, should be empty, has %s entries instead"% len(alice_channel.remote_update_log))
|
||||
alice_channel.update_fee(100000)
|
||||
alice_channel.serialize()
|
||||
|
||||
def alice_to_bob_fee_update(self):
|
||||
fee = 111
|
||||
|
@ -325,11 +330,11 @@ class TestLNHTLCDust(unittest.TestCase):
|
|||
self.assertEqual(fee_per_kw, 6000)
|
||||
htlcAmt = 500 + lnutil.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
|
||||
self.assertEqual(htlcAmt, 4478)
|
||||
htlc = lnhtlc.UpdateAddHtlc(
|
||||
payment_hash = paymentHash,
|
||||
amount_msat = 1000 * htlcAmt,
|
||||
cltv_expiry = 5, # also in create_test_channels
|
||||
)
|
||||
htlc = {
|
||||
'payment_hash' : paymentHash,
|
||||
'amount_msat' : 1000 * htlcAmt,
|
||||
'cltv_expiry' : 5, # also in create_test_channels
|
||||
}
|
||||
|
||||
aliceHtlcIndex = alice_channel.add_htlc(htlc)
|
||||
bobHtlcIndex = bob_channel.receive_htlc(htlc)
|
||||
|
@ -338,7 +343,7 @@ class TestLNHTLCDust(unittest.TestCase):
|
|||
self.assertEqual(len(bob_channel.local_commitment.outputs()), 2)
|
||||
default_fee = calc_static_fee(0)
|
||||
self.assertEqual(bob_channel.pending_local_fee, default_fee + htlcAmt)
|
||||
bob_channel.settle_htlc(paymentPreimage, htlc.htlc_id)
|
||||
bob_channel.settle_htlc(paymentPreimage, bobHtlcIndex)
|
||||
alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
|
||||
force_state_transition(bob_channel, alice_channel)
|
||||
self.assertEqual(len(alice_channel.local_commitment.outputs()), 2)
|
||||
|
|
Loading…
Add table
Reference in a new issue