tlnbase: channel establishment flow, avoid using Wallet instance - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 78119f9733c1ec7620b6c0677d71310bb9abb5d6
 (DIR) parent 1f5852bd155709f4dfb7e51586dae6150db712aa
 (HTM) Author: Janus <ysangkok@gmail.com>
       Date:   Thu, 12 Apr 2018 11:01:05 +0200
       
       lnbase: channel establishment flow, avoid using Wallet instance
       
       Diffstat:
         M lib/lnbase.py                       |      60 ++++++++++++++++++--------------
       
       1 file changed, 34 insertions(+), 26 deletions(-)
       ---
 (DIR) diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -4,6 +4,7 @@
          Derived from https://gist.github.com/AdamISZ/046d05c156aaeb56cc897f85eecb3eb8
        """
        
       +import itertools
        import json
        from collections import OrderedDict
        import asyncio
       t@@ -16,6 +17,7 @@ import hmac
        import cryptography.hazmat.primitives.ciphers.aead as AEAD
        
        from .bitcoin import public_key_from_private_key, ser_to_point, point_to_ser, string_to_number, deserialize_privkey, EC_KEY, rev_hex
       +from . import bitcoin
        from .constants import set_testnet, set_simnet
        from . import constants
        from .util import PrintError
       t@@ -213,16 +215,11 @@ def create_ephemeral_key(privkey):
            return (privkey[:32], pub)
        
        def get_unused_public_keys():
       -    path = os.environ["HOME"] + "/.electrum/" + ("testnet" if constants.net is constants.BitcoinTestnet else "simnet") + "/wallets/default_wallet"
       -    os.stat(path)
       -    WALLET = Wallet(WalletStorage(path))
       -    for str_address in WALLET.get_unused_addresses():
       -        pri, redeem_script = WALLET.export_private_key(str_address, None)
       -
       -        typ, pri, compressed = deserialize_privkey(pri)
       -        pubk = binascii.unhexlify(EC_KEY(pri).get_public_key(True))
       -        yield pubk
       -
       +    xprv, xpub = bitcoin.bip32_root(b"testseed", "p2wpkh")
       +    for i in itertools.count():
       +        childxpub = bitcoin.bip32_public_derivation(xpub, "m/", "m/42/"+str(i))
       +        _, _, _, _, child_c, child_cK = bitcoin.deserialize_xpub(childxpub)
       +        yield child_cK
        
        class Peer(PrintError):
        
       t@@ -233,6 +230,7 @@ class Peer(PrintError):
                self.pubkey = pubkey
                self.read_buffer = b''
                self.ping_time = 0
       +        self.temporary_channel_id_to_incoming_accept_channel = {}
        
            def diagnostic_name(self):
                return self.host
       t@@ -314,13 +312,7 @@ class Peer(PrintError):
                self.send_message(gen_msg('pong', byteslen=l))
        
            def on_accept_channel(self, payload):
       -        # check that it is in my pending requests
       -        # I need to attach a wallet to each request
       -        if ok:
       -            tx = wallet.create_funding_tx()
       -            wallet.sign(tx)
       -            m = gen_msg('funding created', signature)
       -            self.send_message(m)
       +        self.temporary_channel_id_to_incoming_accept_channel[payload["temporary_channel_id"]].set_result(payload)
        
            def on_funding_signed(self, payload):
                sig = payload['signature']
       t@@ -331,10 +323,10 @@ class Peer(PrintError):
            def on_funding_locked(self, payload):
                pass
        
       -    def open_channel(self, funding_sat, push_msat):
       -        self.send_message(gen_msg('open_channel', funding_satoshis=funding_sat, push_msat=push_msat))
       +    #def open_channel(self, funding_sat, push_msat):
       +    #    self.send_message(gen_msg('open_channel', funding_satoshis=funding_sat, push_msat=push_msat))
        
       -    async def main_loop(self, loop):
       +    async def initialize(self, loop):
                self.reader, self.writer = await asyncio.open_connection(self.host, self.port, loop=loop)
                await self.handshake()
                # read init
       t@@ -343,11 +335,7 @@ class Peer(PrintError):
                # send init
                self.send_message(gen_msg("init", gflen=0, lflen=0))
        
       -        pubkeys = get_unused_public_keys()
       -
       -        msg = gen_msg("open_channel", chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)), funding_satoshis=20000, max_accepted_htlcs=5, funding_pubkey=next(pubkeys), revocation_basepoint=next(pubkeys), htlc_basepoint=next(pubkeys), payment_basepoint=next(pubkeys), delayed_payment_basepoint=next(pubkeys), first_per_commitment_point=next(pubkeys))
       -        self.send_message(msg)
       -
       +    async def main_loop(self, loop):
                # loop
                while True:
                    self.ping_if_required()
       t@@ -357,6 +345,23 @@ class Peer(PrintError):
                self.print_error('closing lnbase')
                self.writer.close()
        
       +    async def channel_establishment_flow(self):
       +        pubkeys = get_unused_public_keys()
       +
       +        temp_channel_id = os.urandom(32)
       +        msg = gen_msg("open_channel", temporary_channel_id=temp_channel_id, chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)), funding_satoshis=20000, max_accepted_htlcs=5, funding_pubkey=next(pubkeys), revocation_basepoint=next(pubkeys), htlc_basepoint=next(pubkeys), payment_basepoint=next(pubkeys), delayed_payment_basepoint=next(pubkeys), first_per_commitment_point=next(pubkeys))
       +        self.temporary_channel_id_to_incoming_accept_channel[temp_channel_id] = asyncio.Future()
       +        self.send_message(msg)
       +        accept_channel = await self.temporary_channel_id_to_incoming_accept_channel[temp_channel_id]
       +        del self.temporary_channel_id_to_incoming_accept_channel[temp_channel_id]
       +
       +        # check that it is in my pending requests
       +        # I need to attach a wallet to each request
       +        if ok:
       +            tx = wallet.create_funding_tx()
       +            wallet.sign(tx)
       +            m = gen_msg('funding created', signature)
       +            self.send_message(m)
        
        # replacement for lightningCall
        class LNWallet(Wallet):
       t@@ -391,5 +396,8 @@ if __name__ == "__main__":
            privkey = b"\x21"*32 + b"\x01"
            peer = Peer(privkey, host, port, pubkey)
            loop = asyncio.get_event_loop()
       -    loop.run_until_complete(peer.main_loop(loop))
       +    loop.run_until_complete(peer.initialize(loop))
       +    async def asynctest():
       +        await peer.channel_establishment_flow()
       +    loop.run_until_complete(asyncio.gather(asynctest(), peer.main_loop(loop)))
            loop.close()