URI: 
       tlightning: add payment methods to lnworker - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 0552c61b66298c10267195bb5e1b76e4f7886172
   DIR parent c621ae8f6e24fa8fff303cd442ba2ca6212cb872
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon, 28 May 2018 10:43:50 +0200
       
       lightning: add payment methods to lnworker
       
       Diffstat:
         M electrum/ecc.py                     |       7 +++++++
         M electrum/keystore.py                |       2 +-
         M lib/lnbase.py                       |      14 ++++++++------
         M lib/lnworker.py                     |      87 +++++++++++++++++--------------
       
       4 files changed, 64 insertions(+), 46 deletions(-)
       ---
   DIR diff --git a/electrum/ecc.py b/electrum/ecc.py
       t@@ -315,6 +315,13 @@ def msg_magic(message: bytes) -> bytes:
            return b"\x18Bitcoin Signed Message:\n" + length + message
        
        
       +def verify_signature(pubkey, sig, h):
       +    try:
       +        ECPubkey(pubkey).verify_message_hash(sig, h)
       +    except:
       +        return False
       +    return True
       +
        def verify_message_with_address(address: str, sig65: bytes, message: bytes, *, net=None):
            from .bitcoin import pubkey_to_address
            assert_bytes(sig65, message)
   DIR diff --git a/electrum/keystore.py b/electrum/keystore.py
       t@@ -385,7 +385,7 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
        
            def get_keypair(self, sequence, password):
                k, _ = self.get_private_key(sequence, password)
       -        K, cK = get_pubkeys_from_secret(k)
       +        cK = ecc.ECPrivkey(k).get_public_key_bytes()
                return cK, k
        
        class Old_KeyStore(Deterministic_KeyStore):
   DIR diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -712,8 +712,10 @@ class Peer(PrintError):
        
            def on_channel_reestablish(self, payload):
                chan_id = int.from_bytes(payload["channel_id"], 'big')
       -        if chan_id not in self.channel_reestablish: raise Exception("Got unknown channel_reestablish")
       -        self.channel_reestablish[chan_id].set_result(payload)
       +        if chan_id in self.channel_reestablish:
       +            self.channel_reestablish[chan_id].set_result(payload)
       +        else:
       +            print("Warning: received unknown channel_reestablish")
        
            def on_accept_channel(self, payload):
                temp_chan_id = payload["temporary_channel_id"]
       t@@ -734,7 +736,7 @@ class Peer(PrintError):
                pubkey = payload['node_id']
                signature = payload['signature']
                h = bitcoin.Hash(payload['raw'][66:])
       -        if not bitcoin.verify_signature(pubkey, signature, h):
       +        if not ecc.verify_signature(pubkey, signature, h):
                    return False
                self.s = payload['addresses']
                def read(n):
       t@@ -923,7 +925,7 @@ class Peer(PrintError):
                    funding_txid, funding_index, funding_sat,
                    local_amount, remote_amount, local_config.dust_limit_sat, local_feerate, True, htlcs=[])
                pre_hash = bitcoin.Hash(bfh(local_ctx.serialize_preimage(0)))
       -        if not bitcoin.verify_signature(remote_config.multisig_key.pubkey, remote_sig, pre_hash):
       +        if not ecc.verify_signature(remote_config.multisig_key.pubkey, remote_sig, pre_hash):
                    raise Exception('verifying remote signature failed.')
                # broadcast funding tx
                success, _txid = self.network.broadcast(funding_tx)
       t@@ -1237,7 +1239,7 @@ class Peer(PrintError):
        
                preimage_hex = new_commitment.serialize_preimage(0)
                pre_hash = bitcoin.Hash(bfh(preimage_hex))
       -        if not bitcoin.verify_signature(chan.remote_config.multisig_key.pubkey, commitment_signed_msg["signature"], pre_hash):
       +        if not ecc.verify_signature(chan.remote_config.multisig_key.pubkey, commitment_signed_msg["signature"], pre_hash):
                    raise Exception('failed verifying signature of our updated commitment transaction')
        
                htlc_sigs_len = len(commitment_signed_msg["htlc_signature"])
       t@@ -1247,7 +1249,7 @@ class Peer(PrintError):
                htlc_tx = make_htlc_tx_with_open_channel(chan, this_point, True, True, amount_msat, cltv_expiry, payment_hash, new_commitment, 0)
                pre_hash = bitcoin.Hash(bfh(htlc_tx.serialize_preimage(0)))
                remote_htlc_pubkey = derive_pubkey(chan.remote_config.htlc_basepoint.pubkey, this_point)
       -        if not bitcoin.verify_signature(remote_htlc_pubkey, commitment_signed_msg["htlc_signature"], pre_hash):
       +        if not ecc.verify_signature(remote_htlc_pubkey, commitment_signed_msg["htlc_signature"], pre_hash):
                    raise Exception("failed verifying signature an HTLC tx spending from one of our commit tx'es HTLC outputs")
        
                their_revstore.add_next_entry(last_secret)
   DIR diff --git a/lib/lnworker.py b/lib/lnworker.py
       t@@ -18,7 +18,7 @@ from .simple_config import SimpleConfig
        from .network import Network
        from .storage import WalletStorage
        from .wallet import Wallet
       -from .lnbase import Peer, Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, OpenChannel, ChannelConstraints, RevocationStore
       +from .lnbase import Peer, Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, OpenChannel, ChannelConstraints, RevocationStore, aiosafe
        from .lightning_payencode.lnaddr import lnencode, LnAddr, lndecode
        
        
       t@@ -93,9 +93,8 @@ class LNWorker:
                self.privkey = H256(b"0123456789")
                self.config = network.config
                self.peers = {}
       -        self.channels = {}
       +        self.channels = wallet.storage.get("channels", {})
                peer_list = network.config.get('lightning_peers', node_list)
       -        print("Adding", len(peer_list), "peers")
                for host, port, pubkey in peer_list:
                    self.add_peer(host, port, pubkey)
        
       t@@ -104,9 +103,46 @@ class LNWorker:
                self.network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), asyncio.get_event_loop()))
                self.peers[pubkey] = peer
        
       -    def open_channel(self, peer, amount, push_msat, password):
       -        coro = peer.channel_establishment_flow(self.wallet, self.config, password, amount, push_msat, temp_channel_id=os.urandom(32))
       -        return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
       +    def save_channel(self, openchannel):
       +        dumped = serialize_channels([openchannel])
       +        self.wallet.storage.put("channels", dumped)
       +        self.wallet.storage.write()
       +
       +    @aiosafe
       +    async def open_channel(self, peer, amount, push_msat, password):
       +        openingchannel = await peer.channel_establishment_flow(self.wallet, self.config, password, amount, push_msat, temp_channel_id=os.urandom(32))
       +        self.save_channel(openingchannel)
       +        openchannel = await peer.wait_for_funding_locked(openingchannel, self.wallet)
       +        self.save_channel(openchannel)
       +
       +    @aiosafe
       +    async def reestablish_channel(self):
       +        if self.channels is None or len(self.channels) < 1:
       +            raise Exception("Can't reestablish: No channel saved")
       +        openchannel = self.channels[0]
       +        openchannel = reconstruct_namedtuples(openchannel)
       +        openchannel = await peer.reestablish_channel(openchannel)
       +        self.save_channel(openchannel)
       +
       +    @aiosafe
       +    async def pay(self):
       +        addr = lndecode(sys.argv[6], expected_hrp="sb" if sys.argv[2] == "simnet" else "tb")
       +        payment_hash = addr.paymenthash
       +        pubkey = addr.pubkey.serialize()
       +        msat_amt = int(addr.amount * COIN * 1000)
       +        openchannel = await peer.pay(wallet, openchannel, msat_amt, payment_hash, pubkey, addr.min_final_cltv_expiry)
       +        self.save_channel(openchannel)
       +
       +    @aiosafe
       +    async def get_paid(self):
       +        payment_preimage = os.urandom(32)
       +        RHASH = sha256(payment_preimage)
       +        expected_received_sat = 200000
       +        expected_received_msat = expected_received_sat * 1000
       +        pay_req = lnencode(LnAddr(RHASH, amount=1/Decimal(COIN)*expected_received_sat, tags=[('d', 'one cup of coffee')]), peer.privkey[:32])
       +        print("payment request", pay_req)
       +        openchannel = await peer.receive_commitment_revoke_ack(openchannel, expected_received_msat, payment_preimage)
       +        self.save_channel(openchannel)
        
            def open_channel_from_other_thread(self, node_id, local_amt, push_amt, emit_function, pw):
                # TODO this could race on peers
       t@@ -116,7 +152,8 @@ class LNWorker:
                        print("Peer not found, and peer list is empty or has multiple peers.")
                        return
                    peer = next(iter(self.peers.values()))
       -        fut = self.open_channel(peer, local_amt, push_amt, None if pw == "" else pw)
       +        coro = self.open_channel(peer, local_amt, push_amt, None if pw == "" else pw)
       +        fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
                chan = fut.result()
                # https://api.lightning.community/#listchannels
                std_chan = {"chan_id": chan.channel_id}
       t@@ -179,44 +216,16 @@ if __name__ == "__main__":
            peer = Peer(host, port, pubkey, privkey, network, request_initial_sync=True)
            network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), network.asyncio_loop))
        
       -    funding_satoshis = 2000000
       -    push_msat = 1000000000
       -
            # run blocking test
            async def async_test():
       -        payment_preimage = os.urandom(32)
       -        RHASH = sha256(payment_preimage)
       -        channels = wallet.storage.get("channels", None)
       -
                if "new_channel" in sys.argv[1]:
       -            openingchannel = await peer.channel_establishment_flow(wallet, config, None, funding_satoshis, push_msat, temp_channel_id=os.urandom(32))
       -            openchannel = await peer.wait_for_funding_locked(openingchannel, wallet)
       -            dumped = serialize_channels([openchannel])
       -            wallet.storage.put("channels", dumped)
       -            wallet.storage.write()
       +            await wallet.lnworker.open_channel()
                elif "reestablish_channel" in sys.argv[1]:
       -            if channels is None or len(channels) < 1:
       -                raise Exception("Can't reestablish: No channel saved")
       -            openchannel = channels[0]
       -            openchannel = reconstruct_namedtuples(openchannel)
       -            openchannel = await peer.reestablish_channel(openchannel)
       -
       +            await wallet.lnworker.reestablish_channel()
                if "pay" in sys.argv[1]:
       -            addr = lndecode(sys.argv[6], expected_hrp="sb" if sys.argv[2] == "simnet" else "tb")
       -            payment_hash = addr.paymenthash
       -            pubkey = addr.pubkey.serialize()
       -            msat_amt = int(addr.amount * COIN * 1000)
       -            openchannel = await peer.pay(wallet, openchannel, msat_amt, payment_hash, pubkey, addr.min_final_cltv_expiry)
       +            await lnworker.pay()
                elif "get_paid" in sys.argv[1]:
       -            expected_received_sat = 200000
       -            expected_received_msat = expected_received_sat * 1000
       -            pay_req = lnencode(LnAddr(RHASH, amount=1/Decimal(COIN)*expected_received_sat, tags=[('d', 'one cup of coffee')]), peer.privkey[:32])
       -            print("payment request", pay_req)
       -            openchannel = await peer.receive_commitment_revoke_ack(openchannel, expected_received_msat, payment_preimage)
       -
       -        dumped = serialize_channels([openchannel])
       -        wallet.storage.put("channels", dumped)
       -        wallet.storage.write()
       +            await lnworker.get_paid()
            fut = asyncio.run_coroutine_threadsafe(async_test(), network.asyncio_loop)
            while not fut.done():
                time.sleep(1)