Browse Source

lightning: add payment methods to lnworker

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
ThomasV 7 years ago
parent
commit
0552c61b66
  1. 7
      electrum/ecc.py
  2. 2
      electrum/keystore.py
  3. 14
      lib/lnbase.py
  4. 87
      lib/lnworker.py

7
electrum/ecc.py

@ -315,6 +315,13 @@ def msg_magic(message: bytes) -> bytes:
return b"\x18Bitcoin Signed Message:\n" + length + message 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): def verify_message_with_address(address: str, sig65: bytes, message: bytes, *, net=None):
from .bitcoin import pubkey_to_address from .bitcoin import pubkey_to_address
assert_bytes(sig65, message) assert_bytes(sig65, message)

2
electrum/keystore.py

@ -385,7 +385,7 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
def get_keypair(self, sequence, password): def get_keypair(self, sequence, password):
k, _ = self.get_private_key(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 return cK, k
class Old_KeyStore(Deterministic_KeyStore): class Old_KeyStore(Deterministic_KeyStore):

14
lib/lnbase.py

@ -712,8 +712,10 @@ class Peer(PrintError):
def on_channel_reestablish(self, payload): def on_channel_reestablish(self, payload):
chan_id = int.from_bytes(payload["channel_id"], 'big') chan_id = int.from_bytes(payload["channel_id"], 'big')
if chan_id not in self.channel_reestablish: raise Exception("Got unknown channel_reestablish") if chan_id in self.channel_reestablish:
self.channel_reestablish[chan_id].set_result(payload) self.channel_reestablish[chan_id].set_result(payload)
else:
print("Warning: received unknown channel_reestablish")
def on_accept_channel(self, payload): def on_accept_channel(self, payload):
temp_chan_id = payload["temporary_channel_id"] temp_chan_id = payload["temporary_channel_id"]
@ -734,7 +736,7 @@ class Peer(PrintError):
pubkey = payload['node_id'] pubkey = payload['node_id']
signature = payload['signature'] signature = payload['signature']
h = bitcoin.Hash(payload['raw'][66:]) h = bitcoin.Hash(payload['raw'][66:])
if not bitcoin.verify_signature(pubkey, signature, h): if not ecc.verify_signature(pubkey, signature, h):
return False return False
self.s = payload['addresses'] self.s = payload['addresses']
def read(n): def read(n):
@ -923,7 +925,7 @@ class Peer(PrintError):
funding_txid, funding_index, funding_sat, funding_txid, funding_index, funding_sat,
local_amount, remote_amount, local_config.dust_limit_sat, local_feerate, True, htlcs=[]) local_amount, remote_amount, local_config.dust_limit_sat, local_feerate, True, htlcs=[])
pre_hash = bitcoin.Hash(bfh(local_ctx.serialize_preimage(0))) 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.') raise Exception('verifying remote signature failed.')
# broadcast funding tx # broadcast funding tx
success, _txid = self.network.broadcast(funding_tx) success, _txid = self.network.broadcast(funding_tx)
@ -1237,7 +1239,7 @@ class Peer(PrintError):
preimage_hex = new_commitment.serialize_preimage(0) preimage_hex = new_commitment.serialize_preimage(0)
pre_hash = bitcoin.Hash(bfh(preimage_hex)) 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') raise Exception('failed verifying signature of our updated commitment transaction')
htlc_sigs_len = len(commitment_signed_msg["htlc_signature"]) 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) 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))) pre_hash = bitcoin.Hash(bfh(htlc_tx.serialize_preimage(0)))
remote_htlc_pubkey = derive_pubkey(chan.remote_config.htlc_basepoint.pubkey, this_point) 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") 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) their_revstore.add_next_entry(last_secret)

87
lib/lnworker.py

@ -18,7 +18,7 @@ from .simple_config import SimpleConfig
from .network import Network from .network import Network
from .storage import WalletStorage from .storage import WalletStorage
from .wallet import Wallet 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 from .lightning_payencode.lnaddr import lnencode, LnAddr, lndecode
@ -93,9 +93,8 @@ class LNWorker:
self.privkey = H256(b"0123456789") self.privkey = H256(b"0123456789")
self.config = network.config self.config = network.config
self.peers = {} self.peers = {}
self.channels = {} self.channels = wallet.storage.get("channels", {})
peer_list = network.config.get('lightning_peers', node_list) peer_list = network.config.get('lightning_peers', node_list)
print("Adding", len(peer_list), "peers")
for host, port, pubkey in peer_list: for host, port, pubkey in peer_list:
self.add_peer(host, port, pubkey) 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.network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), asyncio.get_event_loop()))
self.peers[pubkey] = peer self.peers[pubkey] = peer
def open_channel(self, peer, amount, push_msat, password): def save_channel(self, openchannel):
coro = peer.channel_establishment_flow(self.wallet, self.config, password, amount, push_msat, temp_channel_id=os.urandom(32)) dumped = serialize_channels([openchannel])
return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) 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): def open_channel_from_other_thread(self, node_id, local_amt, push_amt, emit_function, pw):
# TODO this could race on peers # 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.") print("Peer not found, and peer list is empty or has multiple peers.")
return return
peer = next(iter(self.peers.values())) 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() chan = fut.result()
# https://api.lightning.community/#listchannels # https://api.lightning.community/#listchannels
std_chan = {"chan_id": chan.channel_id} 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) peer = Peer(host, port, pubkey, privkey, network, request_initial_sync=True)
network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), network.asyncio_loop)) network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), network.asyncio_loop))
funding_satoshis = 2000000
push_msat = 1000000000
# run blocking test # run blocking test
async def async_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]: 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)) await wallet.lnworker.open_channel()
openchannel = await peer.wait_for_funding_locked(openingchannel, wallet)
dumped = serialize_channels([openchannel])
wallet.storage.put("channels", dumped)
wallet.storage.write()
elif "reestablish_channel" in sys.argv[1]: elif "reestablish_channel" in sys.argv[1]:
if channels is None or len(channels) < 1: await wallet.lnworker.reestablish_channel()
raise Exception("Can't reestablish: No channel saved")
openchannel = channels[0]
openchannel = reconstruct_namedtuples(openchannel)
openchannel = await peer.reestablish_channel(openchannel)
if "pay" in sys.argv[1]: if "pay" in sys.argv[1]:
addr = lndecode(sys.argv[6], expected_hrp="sb" if sys.argv[2] == "simnet" else "tb") await lnworker.pay()
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)
elif "get_paid" in sys.argv[1]: elif "get_paid" in sys.argv[1]:
expected_received_sat = 200000 await lnworker.get_paid()
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()
fut = asyncio.run_coroutine_threadsafe(async_test(), network.asyncio_loop) fut = asyncio.run_coroutine_threadsafe(async_test(), network.asyncio_loop)
while not fut.done(): while not fut.done():
time.sleep(1) time.sleep(1)

Loading…
Cancel
Save