tlnbase: receiving invoice payment works - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 9f8d6625ecc6e957f5b02ffce5db7b139b454158
 (DIR) parent 6d87599964f33dabf314ee98c344f86a2a007835
 (HTM) Author: Janus <ysangkok@gmail.com>
       Date:   Fri, 27 Apr 2018 20:09:32 +0200
       
       lnbase: receiving invoice payment works
       
       Diffstat:
         M lib/lnbase.py                       |      64 +++++++++++++++++++++++++++----
         M lib/tests/test_lnbase_online.py     |       4 ----
       
       2 files changed, 56 insertions(+), 12 deletions(-)
       ---
 (DIR) diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -879,14 +879,16 @@ class Peer(PrintError):
                    local_next_per_commitment_secret,
                    byteorder="big"))
        
       -        remote_revocation_pubkey = derive_blinded_pubkey(remote_revocation_basepoint, local_next_per_commitment_point)
                remote_htlc_pubkey = derive_pubkey(remote_htlc_basepoint, local_next_per_commitment_point)
                local_htlc_pubkey = derive_pubkey(local_htlc_basepoint, local_next_per_commitment_point)
       +        htlc_id = int.from_bytes(self.unfulfilled_htlcs[0]["id"], "big")
       +        assert htlc_id == 0, htlc_id
                payment_hash = self.unfulfilled_htlcs[0]["payment_hash"]
                cltv_expiry = int.from_bytes(self.unfulfilled_htlcs[0]["cltv_expiry"],"big")
                # TODO verify sanity of their cltv expiry
                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)
       t@@ -910,6 +912,8 @@ class Peer(PrintError):
                if htlc_sigs_len != 64:
                    raise Exception("unexpected number of htlc signatures: " + str(htlc_sigs_len))
        
       +        # TODO verify htlc_signature
       +
                pubkeys = sorted([bh2u(local_ctx_args.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)
       t@@ -939,19 +943,19 @@ class Peer(PrintError):
                        local_feerate = local_ctx_args.local_feerate,
                        revocationpubkey=revocation_pubkey,
                        local_delayedpubkey=remote_delayedpubkey,
       -                success = False)
       +                success = False) # timeout for the one offering an HTLC
                preimage_script = htlcs_in_remote[0][0]
                htlc_output_txid = remote_ctx.txid()
                htlc_tx_inputs = make_htlc_tx_inputs(
                        htlc_output_txid=htlc_output_txid,
       -                htlc_output_index=1, # TODO find index of htlc output in new_commitment
       +                htlc_output_index=1, # TODO find index of htlc output in remote_ctx
                        revocationpubkey=revocation_pubkey,
                        local_delayedpubkey=remote_delayedpubkey,
                        amount_msat=amount_msat,
                        witness_script=bh2u(preimage_script))
                htlc_tx = make_htlc_tx(cltv_expiry, inputs=htlc_tx_inputs, output=htlc_tx_output)
        
       -        #htlc_sig signs the HTLC transaction that spends from OUR commitment transaction's received_htlc output
       +        # htlc_sig signs the HTLC transaction that spends from THEIR commitment transaction's received_htlc output
                sig = bfh(htlc_tx.sign_txin(0, their_remote_htlc_privkey))
                r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order())
                htlc_sig = sigencode_string_canonize(r, s, SECP256k1.generator.order())
       t@@ -964,10 +968,54 @@ class Peer(PrintError):
                finally:
                    del self.revoke_and_ack[channel_id]
        
       -        #TODO check revoke_and_ack_msg contents
       +        # TODO check revoke_and_ack_msg contents
       +
       +        self.send_message(gen_msg("update_fulfill_htlc", channel_id=channel_id, id=0, payment_preimage=payment_preimage))
       +
       +        remote_next_commitment_point = revoke_and_ack_msg["next_per_commitment_point"]
       +
       +        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
       +        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,
       +            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=[])
       +
       +        bare_ctx.sign({bh2u(local_ctx_args.funding_pubkey): (funding_privkey, True)})
       +        sig_index = pubkeys.index(bh2u(local_ctx_args.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())
       +
       +        self.revoke_and_ack[channel_id] = asyncio.Future()
       +        self.commitment_signed[channel_id] = asyncio.Future() # we will also receive a new commitment transaction shortly after sending ours
       +        self.send_message(gen_msg("commitment_signed", channel_id=channel_id, signature=sig_64, num_htlcs=0))
       +        try:
       +            revoke_and_ack_msg = await self.revoke_and_ack[channel_id]
       +        finally:
       +            del self.revoke_and_ack[channel_id]
       +
       +        # TODO check revoke_and_ack results
       +
       +        try:
       +            commitment_signed_msg = await self.commitment_signed[channel_id]
       +        finally:
       +            del self.commitment_signed[channel_id]
       +
       +        local_last_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_last_pcs_index - 2)
       +        local_next_per_commitment_point = secret_to_pubkey(int.from_bytes(
       +            local_next_per_commitment_secret,
       +            byteorder="big"))
       +
       +        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))
        
       -    async def fulfill_htlc(self, channel_id, htlc_id, payment_preimage):
       -        self.send_message(gen_msg("update_fulfill_htlc", channel_id=channel_id, id=htlc_id, payment_preimage=payment_preimage))
        
            def on_commitment_signed(self, payload):
                self.print_error("commitment_signed", payload)
       t@@ -982,7 +1030,7 @@ class Peer(PrintError):
        
            def on_revoke_and_ack(self, payload):
                channel_id = int.from_bytes(payload["channel_id"], "big")
       -        self.revoke_and_ack[channel_id].set_result(channel_id)
       +        self.revoke_and_ack[channel_id].set_result(payload)
        
        
        
 (DIR) diff --git a/lib/tests/test_lnbase_online.py b/lib/tests/test_lnbase_online.py
       t@@ -56,10 +56,6 @@ if __name__ == "__main__":
                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)
       -        htlc_id = 0 # TODO should correspond with received htlc (when handling more than just one update)
       -        await peer.fulfill_htlc(channel_id, htlc_id, payment_preimage)
       -        while True:
       -            await asyncio.sleep(1)
            fut = asyncio.run_coroutine_threadsafe(async_test(), network.asyncio_loop)
            while not fut.done():
                time.sleep(1)