electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 39dcc2413303addae2fb5dac5c334c31abc06f3a
parent c2bbc1ec6050963db654b18013ce39616729a0f9
Author: Janus <ysangkok@gmail.com>
Date:   Mon, 30 Apr 2018 23:34:33 +0200

lnbase: organize channel data

Diffstat:
Mlib/lnbase.py | 250+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mlib/tests/test_lnbase_online.py | 5+++--
2 files changed, 164 insertions(+), 91 deletions(-)

diff --git a/lib/lnbase.py b/lib/lnbase.py @@ -32,14 +32,6 @@ from .util import PrintError, bh2u, print_error, bfh, profiler from .transaction import opcodes, Transaction from collections import namedtuple, defaultdict -LocalCtxArgs = namedtuple("LocalCtxArgs", - ["ctn", - "funding_pubkey", "remote_funding_pubkey", "remotepubkey", - "base_point", "remote_payment_basepoint", - "remote_revocation_pubkey", "local_delayedpubkey", "to_self_delay", - "funding_txid", "funding_index", "funding_satoshis", - "local_amount", "remote_amount", "dust_limit_satoshis", "local_feerate", - "commitment_owner"]) # hardcoded nodes node_list = [ @@ -289,6 +281,17 @@ def create_ephemeral_key(privkey): pub = privkey_to_pubkey(privkey) return (privkey[:32], pub) +Keypair = namedtuple("Keypair", ["pubkey", "privkey"]) +Outpoint = namedtuple("Outpoint", ["txid", "output_index"]) +ChannelConfig = namedtuple("ChannelConfig", [ + "payment_key", "multisig_key", "htlc_key", "delayed_key", "revocation_key", + "to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"]) +OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"]) +RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_sat"]) +LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_sat"]) +ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator"]) +OpenChannel = namedtuple("OpenChannel", ["channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints"]) + class KeypairGenerator: def __init__(self, seed): self.xprv, xpub = bitcoin.bip32_root(seed, "p2wpkh") @@ -297,7 +300,7 @@ class KeypairGenerator: _, _, _, _, child_c, child_cK = bitcoin.deserialize_xpub(childxpub) _, _, _, _, _, k = bitcoin.deserialize_xprv(childxprv) assert len(k) == 32 - return child_cK, k + return Keypair(pubkey=child_cK, privkey=k) def aiosafe(f): async def f2(*args, **kwargs): @@ -446,12 +449,12 @@ def make_received_htlc(revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, p + bytes([opcodes.OP_CLTV, opcodes.OP_DROP, opcodes.OP_CHECKSIG, opcodes.OP_ENDIF, opcodes.OP_ENDIF]) -def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey, remotepubkey, +def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey, remote_payment_pubkey, payment_basepoint, remote_payment_basepoint, revocation_pubkey, delayed_pubkey, to_self_delay, - funding_txid, funding_pos, funding_satoshis, + funding_txid, funding_pos, funding_sat, local_amount, remote_amount, - dust_limit_satoshis, local_feerate, for_us, htlcs): + dust_limit_sat, local_feerate, for_us, htlcs): pubkeys = sorted([bh2u(local_funding_pubkey), bh2u(remote_funding_pubkey)]) obs = get_obscured_ctn(ctn, payment_basepoint, remote_payment_basepoint) @@ -466,7 +469,7 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey, remotepubk 'num_sig': 2, 'prevout_n': funding_pos, 'prevout_hash': funding_txid, - 'value': funding_satoshis, + 'value': funding_sat, 'coinbase': False, 'sequence':sequence }] @@ -474,7 +477,7 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey, remotepubk local_script = bytes([opcodes.OP_IF]) + bfh(push_script(bh2u(revocation_pubkey))) + bytes([opcodes.OP_ELSE]) + add_number_to_script(to_self_delay) \ + bytes([opcodes.OP_CSV, opcodes.OP_DROP]) + bfh(push_script(bh2u(delayed_pubkey))) + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG]) local_address = bitcoin.redeem_script_to_address('p2wsh', bh2u(local_script)) - remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remotepubkey)) + remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remote_payment_pubkey)) # TODO trim htlc outputs here while also considering 2nd stage htlc transactions fee = local_feerate * overall_weight(len(htlcs)) // 1000 # TODO incorrect if anything is trimmed to_local = (bitcoin.TYPE_ADDRESS, local_address, local_amount - (fee if for_us else 0)) @@ -483,7 +486,8 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey, remotepubk for script, msat_amount in htlcs: c_outputs += [(bitcoin.TYPE_ADDRESS, bitcoin.redeem_script_to_address('p2wsh', bh2u(script)), msat_amount // 1000)] # trim outputs - c_outputs = list(filter(lambda x:x[2]>= dust_limit_satoshis, c_outputs)) + c_outputs = list(filter(lambda x:x[2]>= dust_limit_sat, c_outputs)) + assert sum(x[2] for x in c_outputs) <= funding_sat # create commitment tx tx = Transaction.from_io(c_inputs, c_outputs, locktime=locktime, version=2) @@ -687,7 +691,7 @@ class Peer(PrintError): self.channel_db.on_channel_announcement(payload) #def open_channel(self, funding_sat, push_msat): - # self.send_message(gen_msg('open_channel', funding_satoshis=funding_sat, push_msat=push_msat)) + # self.send_message(gen_msg('open_channel', funding_sat=funding_sat, push_msat=push_msat)) @aiosafe async def main_loop(self): @@ -710,7 +714,7 @@ class Peer(PrintError): self.writer.close() @aiosafe - async def channel_establishment_flow(self, wallet, config, funding_satoshis, push_msat, temp_channel_id, keypair_generator=None): + async def channel_establishment_flow(self, wallet, config, funding_sat, push_msat, temp_channel_id, keypair_generator=None): await self.initialized if keypair_generator is None: @@ -725,40 +729,41 @@ class Peer(PrintError): keyfamilyrevocationroot = 5 keyfamilynodekey = 6 # TODO currently unused - funding_pubkey, funding_privkey = keypair_generator.get(keyfamilymultisig, 0) - revocation_basepoint, _ = keypair_generator.get(keyfamilyrevocationbase, 0) - htlc_basepoint, htlc_privkey = keypair_generator.get(keyfamilyhtlcbase, 0) - delayed_payment_basepoint, delayed_privkey = keypair_generator.get(keyfamilydelaybase, 0) - base_point, _ = keypair_generator.get(keyfamilypaymentbase, 0) + funding_key = keypair_generator.get(keyfamilymultisig, 0) + revocation_key = keypair_generator.get(keyfamilyrevocationbase, 0) + htlc_key = keypair_generator.get(keyfamilyhtlcbase, 0) + delayed_key = keypair_generator.get(keyfamilydelaybase, 0) + base_point = keypair_generator.get(keyfamilypaymentbase, 0) per_commitment_secret_seed = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100.to_bytes(32, "big") per_commitment_secret_index = 2**48 - 1 # amounts local_feerate = 20000 - dust_limit_satoshis = 10 to_self_delay = 144 - ctn = 0 + dust_limit_sat = 10 # per_commitment_secret_first = get_per_commitment_secret_from_seed(per_commitment_secret_seed, per_commitment_secret_index) per_commitment_point_first = secret_to_pubkey(int.from_bytes( per_commitment_secret_first, byteorder="big")) + local_max_htlc_value_in_flight_msat = 500000 * 1000 + local_max_accepted_htlcs = 5 msg = gen_msg( "open_channel", temporary_channel_id=temp_channel_id, chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)), - funding_satoshis=funding_satoshis, + funding_satoshis=funding_sat, push_msat=push_msat, - dust_limit_satoshis=dust_limit_satoshis, + dust_limit_satoshis=dust_limit_sat, feerate_per_kw=local_feerate, - max_accepted_htlcs=5, - funding_pubkey=funding_pubkey, - revocation_basepoint=revocation_basepoint, - htlc_basepoint=htlc_basepoint, - payment_basepoint=base_point, - delayed_payment_basepoint=delayed_payment_basepoint, + max_accepted_htlcs=local_max_accepted_htlcs, + funding_pubkey=funding_key.pubkey, + revocation_basepoint=revocation_key.pubkey, + htlc_basepoint=htlc_key.pubkey, + payment_basepoint=base_point.pubkey, + delayed_payment_basepoint=delayed_key.pubkey, first_per_commitment_point=per_commitment_point_first, to_self_delay=to_self_delay, - max_htlc_value_in_flight_msat=500000 * 1000 + max_htlc_value_in_flight_msat=local_max_htlc_value_in_flight_msat ) #self.channel_accepted[temp_channel_id] = asyncio.Future() self.send_message(msg) @@ -766,10 +771,11 @@ class Peer(PrintError): payload = await self.channel_accepted[temp_channel_id] finally: del self.channel_accepted[temp_channel_id] + remote_max_accepted_htlcs = payload["max_accepted_htlcs"] remote_per_commitment_point = payload['first_per_commitment_point'] remote_funding_pubkey = payload["funding_pubkey"] remote_delay = int.from_bytes(payload['to_self_delay'], byteorder="big") - remote_dust_limit_satoshis = int.from_bytes(payload['dust_limit_satoshis'], byteorder="big") + remote_dust_limit_sat = int.from_bytes(payload['dust_limit_satoshis'], byteorder="big") remote_revocation_basepoint = payload['revocation_basepoint'] remote_payment_basepoint = payload['payment_basepoint'] remote_delayed_payment_basepoint = payload['delayed_payment_basepoint'] @@ -777,44 +783,44 @@ class Peer(PrintError): remote_htlc_minimum_msat = int.from_bytes(payload['htlc_minimum_msat'], "big") remote_max_htlc_value_in_flight_msat = int.from_bytes(payload['max_htlc_value_in_flight_msat'], "big") funding_txn_minimum_depth = int.from_bytes(payload['minimum_depth'], byteorder="big") - print('remote dust limit', remote_dust_limit_satoshis) - assert remote_dust_limit_satoshis < 600 + print('remote dust limit', remote_dust_limit_sat) + assert remote_dust_limit_sat < 600 assert remote_htlc_minimum_msat < 600 * 1000 assert remote_max_htlc_value_in_flight_msat >= 500 * 1000 * 1000, remote_max_htlc_value_in_flight_msat self.print_error('remote delay', remote_delay) self.print_error('funding_txn_minimum_depth', funding_txn_minimum_depth) # create funding tx - pubkeys = sorted([bh2u(funding_pubkey), bh2u(remote_funding_pubkey)]) + pubkeys = sorted([bh2u(funding_key.pubkey), bh2u(remote_funding_pubkey)]) redeem_script = transaction.multisig_script(pubkeys, 2) funding_address = bitcoin.redeem_script_to_address('p2wsh', redeem_script) - funding_output = (bitcoin.TYPE_ADDRESS, funding_address, funding_satoshis) + funding_output = (bitcoin.TYPE_ADDRESS, funding_address, funding_sat) funding_tx = wallet.mktx([funding_output], None, config, 1000) funding_txid = funding_tx.txid() funding_index = funding_tx.outputs().index(funding_output) # derive keys - localpubkey = derive_pubkey(base_point, remote_per_commitment_point) #local_payment_pubkey - #localprivkey = derive_privkey(base_secret, remote_per_commitment_point) - remotepubkey = derive_pubkey(remote_payment_basepoint, per_commitment_point_first) - revocation_pubkey = derive_blinded_pubkey(revocation_basepoint, remote_per_commitment_point) + local_payment_pubkey = derive_pubkey(base_point.pubkey, remote_per_commitment_point) + #local_payment_privkey = derive_privkey(base_secret, remote_per_commitment_point) + remote_payment_pubkey = derive_pubkey(remote_payment_basepoint, per_commitment_point_first) + revocation_pubkey = derive_blinded_pubkey(revocation_key.pubkey, remote_per_commitment_point) remote_revocation_pubkey = derive_blinded_pubkey(remote_revocation_basepoint, per_commitment_point_first) - local_delayedpubkey = derive_pubkey(delayed_payment_basepoint, per_commitment_point_first) + local_delayedpubkey = derive_pubkey(delayed_key.pubkey, per_commitment_point_first) remote_delayedpubkey = derive_pubkey(remote_delayed_payment_basepoint, remote_per_commitment_point) # compute amounts htlcs = [] - to_local_msat = funding_satoshis*1000 - push_msat + to_local_msat = funding_sat*1000 - push_msat to_remote_msat = push_msat local_amount = to_local_msat // 1000 remote_amount = to_remote_msat // 1000 # remote commitment transaction remote_ctx = make_commitment( - ctn, - remote_funding_pubkey, funding_pubkey, localpubkey, - base_point, remote_payment_basepoint, + 0, + remote_funding_pubkey, funding_key.pubkey, local_payment_pubkey, + base_point.pubkey, remote_payment_basepoint, revocation_pubkey, remote_delayedpubkey, remote_delay, - funding_txid, funding_index, funding_satoshis, - remote_amount, local_amount, remote_dust_limit_satoshis, local_feerate, False, htlcs=[]) - remote_ctx.sign({bh2u(funding_pubkey): (funding_privkey, True)}) - sig_index = pubkeys.index(bh2u(funding_pubkey)) + funding_txid, funding_index, funding_sat, + remote_amount, local_amount, remote_dust_limit_sat, local_feerate, False, htlcs=[]) + remote_ctx.sign({bh2u(funding_key.pubkey): (funding_key.privkey, True)}) + sig_index = pubkeys.index(bh2u(funding_key.pubkey)) sig = bytes.fromhex(remote_ctx.inputs()[0]["signatures"][sig_index]) r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order()) sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order()) @@ -829,14 +835,13 @@ class Peer(PrintError): self.print_error('received funding_signed') remote_sig = payload['signature'] # verify remote signature - local_ctx_args = LocalCtxArgs( - ctn, - funding_pubkey, remote_funding_pubkey, remotepubkey, - base_point, remote_payment_basepoint, + local_ctx = make_commitment( + 0, + funding_key.pubkey, remote_funding_pubkey, remote_payment_pubkey, + base_point.pubkey, remote_payment_basepoint, remote_revocation_pubkey, local_delayedpubkey, to_self_delay, - funding_txid, funding_index, funding_satoshis, - local_amount, remote_amount, dust_limit_satoshis, local_feerate, True) - local_ctx = make_commitment(*local_ctx_args, htlcs=[]) + funding_txid, funding_index, funding_sat, + local_amount, remote_amount, dust_limit_sat, local_feerate, True, htlcs=[]) pre_hash = bitcoin.Hash(bfh(local_ctx.serialize_preimage(0))) if not bitcoin.verify_signature(remote_funding_pubkey, remote_sig, pre_hash): raise Exception('verifying remote signature failed.') @@ -876,18 +881,68 @@ class Peer(PrintError): del self.remote_funding_locked[channel_id] self.print_error('Done waiting for remote_funding_locked', remote_funding_locked_msg) #self.commitment_signed[channel_id] = asyncio.Future() - return channel_id, per_commitment_secret_seed, local_ctx_args, remote_funding_pubkey, remote_funding_locked_msg, remote_revocation_basepoint, remote_htlc_basepoint, htlc_basepoint, delayed_payment_basepoint, revocation_basepoint, remote_delayed_payment_basepoint, remote_delay, remote_dust_limit_satoshis, funding_privkey, htlc_privkey - async def receive_commitment_revoke_ack(self, channel_id, local_per_commitment_secret_seed, local_last_pcs_index, local_ctx_args, expected_received_sat, remote_funding_pubkey, local_next_commitment_number, remote_next_commitment_point, remote_revocation_basepoint, remote_htlc_basepoint, local_htlc_basepoint, delayed_payment_basepoint, revocation_basepoint, remote_delayed_payment_basepoint, remote_delay, remote_dust_limit_satoshis, funding_privkey, payment_preimage, htlc_privkey): + return OpenChannel( + channel_id=channel_id, + funding_outpoint=Outpoint(funding_txid, funding_index), + local_config=ChannelConfig( + payment_key=base_point, + multisig_key=funding_key, + htlc_key=htlc_key, + delayed_key=delayed_key, + revocation_key=revocation_key, + to_self_delay=to_self_delay, + dust_limit_sat=dust_limit_sat, + max_htlc_value_in_flight_msat=local_max_htlc_value_in_flight_msat, + max_accepted_htlcs=local_max_accepted_htlcs + ), + remote_config=ChannelConfig( + payment_key=OnlyPubkeyKeypair(remote_payment_basepoint), + multisig_key=OnlyPubkeyKeypair(remote_funding_pubkey), + htlc_key=OnlyPubkeyKeypair(remote_htlc_basepoint), + delayed_key=OnlyPubkeyKeypair(remote_delayed_payment_basepoint), + revocation_key=OnlyPubkeyKeypair(remote_revocation_basepoint), + to_self_delay=remote_delay, + dust_limit_sat=remote_dust_limit_sat, + max_htlc_value_in_flight_msat=remote_max_htlc_value_in_flight_msat, + max_accepted_htlcs=remote_max_accepted_htlcs + ), + remote_state=RemoteState( + ctn = 0, + next_per_commitment_point=remote_funding_locked_msg["next_per_commitment_point"], + amount_sat=remote_amount + ), + local_state=LocalState( + ctn = 0, + per_commitment_secret_seed=per_commitment_secret_seed, + amount_sat=local_amount + ), + constraints=ChannelConstraints(capacity=funding_sat, feerate=local_feerate, is_initiator=True) + ) + + async def receive_commitment_revoke_ack(self, openchannel, expected_received_sat, payment_preimage): + channel_id = openchannel.channel_id + local_per_commitment_secret_seed = openchannel.local_state.per_commitment_secret_seed + assert openchannel.local_state.ctn == 0 + local_next_pcs_index = 2**48 - 2 + remote_funding_pubkey = openchannel.remote_config.multisig_key.pubkey + remote_next_commitment_point = openchannel.remote_state.next_per_commitment_point + remote_revocation_basepoint = openchannel.remote_config.revocation_key.pubkey + remote_htlc_basepoint = openchannel.remote_config.htlc_key.pubkey + local_htlc_basepoint = openchannel.local_config.htlc_key.pubkey + delayed_payment_basepoint = openchannel.local_config.delayed_key.pubkey + revocation_basepoint = openchannel.local_config.revocation_key.pubkey + remote_delayed_payment_basepoint = openchannel.remote_config.delayed_key.pubkey + remote_delay = openchannel.remote_config.to_self_delay + remote_dust_limit_sat = openchannel.remote_config.dust_limit_sat + funding_privkey = openchannel.local_config.multisig_key.privkey + htlc_privkey = openchannel.local_config.htlc_key.privkey try: commitment_signed_msg = await self.commitment_signed[channel_id] finally: del self.commitment_signed[channel_id] - # TODO make new future? (there could be more updates) - - local_last_per_commitment_secret = get_per_commitment_secret_from_seed(local_per_commitment_secret_seed, local_last_pcs_index) - local_next_per_commitment_secret = get_per_commitment_secret_from_seed(local_per_commitment_secret_seed, local_last_pcs_index - 1) + local_next_per_commitment_secret = get_per_commitment_secret_from_seed(local_per_commitment_secret_seed, local_next_pcs_index) local_next_per_commitment_point = secret_to_pubkey(int.from_bytes( local_next_per_commitment_secret, byteorder="big")) @@ -902,11 +957,6 @@ class Peer(PrintError): amount_msat = int.from_bytes(self.unfulfilled_htlcs[0]["amount_msat"], "big") remote_revocation_pubkey = derive_blinded_pubkey(remote_revocation_basepoint, local_next_per_commitment_point) - local_ctx_args = local_ctx_args._replace(remote_amount = local_ctx_args.remote_amount - expected_received_sat) - local_ctx_args = local_ctx_args._replace(ctn = local_next_commitment_number) - local_ctx_args = local_ctx_args._replace(remote_revocation_pubkey = remote_revocation_pubkey) - local_ctx_args = local_ctx_args._replace(remotepubkey = derive_pubkey(local_ctx_args.remote_payment_basepoint, local_next_per_commitment_point)) - local_ctx_args = local_ctx_args._replace(local_delayedpubkey = derive_pubkey(delayed_payment_basepoint, local_next_per_commitment_point)) htlcs_in_local = [ ( @@ -915,7 +965,23 @@ class Peer(PrintError): ) ] - new_commitment = make_commitment(*local_ctx_args, htlcs=htlcs_in_local) + new_commitment = make_commitment( + 1, + openchannel.local_config.multisig_key.pubkey, + openchannel.remote_config.multisig_key.pubkey, + derive_pubkey(openchannel.remote_config.payment_key.pubkey, local_next_per_commitment_point), + openchannel.local_config.payment_key.pubkey, + openchannel.remote_config.payment_key.pubkey, + remote_revocation_pubkey, + derive_pubkey(delayed_payment_basepoint, local_next_per_commitment_point), + openchannel.local_config.to_self_delay, + *openchannel.funding_outpoint, + openchannel.constraints.capacity, + openchannel.local_state.amount_sat, + openchannel.remote_state.amount_sat - expected_received_sat, + openchannel.local_config.dust_limit_sat, + openchannel.constraints.feerate, + True, htlcs=htlcs_in_local) preimage_hex = new_commitment.serialize_preimage(0) pre_hash = bitcoin.Hash(bfh(preimage_hex)) if not bitcoin.verify_signature(remote_funding_pubkey, commitment_signed_msg["signature"], pre_hash): @@ -927,7 +993,13 @@ class Peer(PrintError): # TODO verify htlc_signature - pubkeys = sorted([bh2u(local_ctx_args.funding_pubkey), bh2u(remote_funding_pubkey)]) + local_last_pcs_index = 2**48 - openchannel.local_state.ctn - 1 + local_last_per_commitment_secret = get_per_commitment_secret_from_seed(local_per_commitment_secret_seed, local_last_pcs_index) + + self.send_message(gen_msg("revoke_and_ack", channel_id=channel_id, per_commitment_secret=local_last_per_commitment_secret, next_per_commitment_point=local_next_per_commitment_point)) + + funding_pubkey = openchannel.local_config.multisig_key.pubkey + pubkeys = sorted([bh2u(funding_pubkey), bh2u(remote_funding_pubkey)]) revocation_pubkey = derive_blinded_pubkey(revocation_basepoint, remote_next_commitment_point) remote_delayedpubkey = derive_pubkey(remote_delayed_payment_basepoint, remote_next_commitment_point) their_local_htlc_pubkey = derive_pubkey(remote_htlc_basepoint, remote_next_commitment_point) @@ -936,25 +1008,24 @@ class Peer(PrintError): their_remote_htlc_privkey = their_remote_htlc_privkey_number.to_bytes(32, "big") # TODO check payment_hash htlcs_in_remote = [(make_offered_htlc(revocation_pubkey, their_remote_htlc_pubkey, their_local_htlc_pubkey, payment_hash), amount_msat)] - local_payment_pubkey = derive_pubkey(local_ctx_args.base_point, remote_next_commitment_point) + local_payment_pubkey = derive_pubkey(openchannel.local_config.payment_key.pubkey, remote_next_commitment_point) remote_ctx = make_commitment( 1, - remote_funding_pubkey, local_ctx_args.funding_pubkey, local_payment_pubkey, - local_ctx_args.base_point, local_ctx_args.remote_payment_basepoint, + remote_funding_pubkey, funding_pubkey, local_payment_pubkey, + openchannel.local_config.payment_key.pubkey, openchannel.remote_config.payment_key.pubkey, revocation_pubkey, remote_delayedpubkey, remote_delay, - local_ctx_args.funding_txid, local_ctx_args.funding_index, local_ctx_args.funding_satoshis, - local_ctx_args.remote_amount, local_ctx_args.local_amount, remote_dust_limit_satoshis, local_ctx_args.local_feerate, False, htlcs=htlcs_in_remote) - remote_ctx.sign({bh2u(local_ctx_args.funding_pubkey): (funding_privkey, True)}) - sig_index = pubkeys.index(bh2u(local_ctx_args.funding_pubkey)) + *openchannel.funding_outpoint, openchannel.constraints.capacity, + openchannel.remote_state.amount_sat - expected_received_sat, openchannel.local_state.amount_sat, remote_dust_limit_sat, + openchannel.constraints.feerate, False, htlcs=htlcs_in_remote) + remote_ctx.sign({bh2u(funding_pubkey): (funding_privkey, True)}) + sig_index = pubkeys.index(bh2u(funding_pubkey)) sig = bytes.fromhex(remote_ctx.inputs()[0]["signatures"][sig_index]) r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order()) sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order()) - self.send_message(gen_msg("revoke_and_ack", channel_id=channel_id, per_commitment_secret=local_last_per_commitment_secret, next_per_commitment_point=local_next_per_commitment_point)) - htlc_tx_output = make_htlc_tx_output( amount_msat = amount_msat, - local_feerate = local_ctx_args.local_feerate, + local_feerate = openchannel.constraints.feerate, revocationpubkey=revocation_pubkey, local_delayedpubkey=remote_delayedpubkey, success = False) # timeout for the one offering an HTLC @@ -990,18 +1061,19 @@ class Peer(PrintError): revocation_pubkey = derive_blinded_pubkey(revocation_basepoint, remote_next_commitment_point) remote_delayedpubkey = derive_pubkey(remote_delayed_payment_basepoint, remote_next_commitment_point) - local_payment_pubkey = derive_pubkey(local_ctx_args.base_point, remote_next_commitment_point) - # local commitment transaction without htlcs + local_payment_pubkey = derive_pubkey(openchannel.local_config.payment_key.pubkey, remote_next_commitment_point) + # remote commitment transaction without htlcs bare_ctx = make_commitment( 2, - remote_funding_pubkey, local_ctx_args.funding_pubkey, local_payment_pubkey, - local_ctx_args.base_point, local_ctx_args.remote_payment_basepoint, + remote_funding_pubkey, funding_pubkey, local_payment_pubkey, + openchannel.local_config.payment_key.pubkey, openchannel.remote_config.payment_key.pubkey, revocation_pubkey, remote_delayedpubkey, remote_delay, - local_ctx_args.funding_txid, local_ctx_args.funding_index, local_ctx_args.funding_satoshis, - local_ctx_args.remote_amount, local_ctx_args.local_amount + expected_received_sat, remote_dust_limit_satoshis, local_ctx_args.local_feerate, False, htlcs=[]) + *openchannel.funding_outpoint, openchannel.constraints.capacity, + openchannel.remote_state.amount_sat - expected_received_sat, openchannel.local_state.amount_sat + expected_received_sat, + remote_dust_limit_sat, openchannel.constraints.feerate, False, htlcs=[]) - bare_ctx.sign({bh2u(local_ctx_args.funding_pubkey): (funding_privkey, True)}) - sig_index = pubkeys.index(bh2u(local_ctx_args.funding_pubkey)) + bare_ctx.sign({bh2u(funding_pubkey): (funding_privkey, True)}) + sig_index = pubkeys.index(bh2u(funding_pubkey)) sig = bytes.fromhex(bare_ctx.inputs()[0]["signatures"][sig_index]) r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order()) sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order()) diff --git a/lib/tests/test_lnbase_online.py b/lib/tests/test_lnbase_online.py @@ -4,6 +4,7 @@ import json import binascii import asyncio import time +import os from lib.bitcoin import sha256 from decimal import Decimal @@ -50,12 +51,12 @@ if __name__ == "__main__": async def async_test(): payment_preimage = bytes.fromhex("01"*32) RHASH = sha256(payment_preimage) - channel_id, per_commitment_secret_seed, local_ctx_args, remote_funding_pubkey, remote_funding_locked_msg, remote_revocation_basepoint, remote_htlc_basepoint, local_htlc_basepoint, delayed_payment_basepoint, revocation_basepoint, remote_delayed_payment_basepoint, remote_delay, remote_dust_limit_satoshis, funding_privkey, htlc_privkey = await peer.channel_establishment_flow(wallet, config, funding_satoshis, push_msat) + openchannel = await peer.channel_establishment_flow(wallet, config, funding_satoshis, push_msat, temp_channel_id=os.urandom(32)) expected_received_sat = 400000 pay_req = lnencode(LnAddr(RHASH, amount=Decimal("0.00000001")*expected_received_sat, tags=[('d', 'one cup of coffee')]), peer.privkey[:32]) print("payment request", pay_req) last_pcs_index = 2**48 - 1 - await peer.receive_commitment_revoke_ack(channel_id, per_commitment_secret_seed, last_pcs_index, local_ctx_args, expected_received_sat, remote_funding_pubkey, local_next_commitment_number=1, remote_next_commitment_point=remote_funding_locked_msg["next_per_commitment_point"], remote_revocation_basepoint=remote_revocation_basepoint, remote_htlc_basepoint=remote_htlc_basepoint, local_htlc_basepoint=local_htlc_basepoint, delayed_payment_basepoint=delayed_payment_basepoint, revocation_basepoint=revocation_basepoint, remote_delayed_payment_basepoint=remote_delayed_payment_basepoint, remote_delay=remote_delay, remote_dust_limit_satoshis=remote_dust_limit_satoshis, funding_privkey=funding_privkey, htlc_privkey=htlc_privkey, payment_preimage=payment_preimage) + await peer.receive_commitment_revoke_ack(openchannel, expected_received_sat, payment_preimage) fut = asyncio.run_coroutine_threadsafe(async_test(), network.asyncio_loop) while not fut.done(): time.sleep(1)