electrum

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

commit 0552c61b66298c10267195bb5e1b76e4f7886172
parent c621ae8f6e24fa8fff303cd442ba2ca6212cb872
Author: ThomasV <thomasv@electrum.org>
Date:   Mon, 28 May 2018 10:43:50 +0200

lightning: add payment methods to lnworker

Diffstat:
Melectrum/ecc.py | 7+++++++
Melectrum/keystore.py | 2+-
Mlib/lnbase.py | 14++++++++------
Mlib/lnworker.py | 87++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
4 files changed, 64 insertions(+), 46 deletions(-)

diff --git a/electrum/ecc.py b/electrum/ecc.py @@ -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) diff --git a/electrum/keystore.py b/electrum/keystore.py @@ -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): diff --git a/lib/lnbase.py b/lib/lnbase.py @@ -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"] @@ -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): @@ -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) @@ -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"]) @@ -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) diff --git a/lib/lnworker.py b/lib/lnworker.py @@ -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 @@ -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) @@ -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 @@ -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} @@ -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)