From 45b089ce939b14716a8fec18076d90f0759db13d Mon Sep 17 00:00:00 2001 From: Jonathan Zernik Date: Sun, 11 Oct 2020 04:21:07 -0700 Subject: [PATCH] Add open channel close channel (#282) * Add open channel and close channel rpc * Use different context managers for open channel and connect peer * Add test for opening channel rpc --- itests/tests/test_squeak_node.py | 50 ++++++++++++++++++- itests/tests/util.py | 22 ++++---- proto/squeak_admin.proto | 12 +++++ .../admin/squeak_admin_server_handler.py | 23 +++++++++ .../admin/squeak_admin_server_servicer.py | 21 ++++++++ squeakserver/common/lnd_lightning_client.py | 7 +++ 6 files changed, 122 insertions(+), 13 deletions(-) diff --git a/itests/tests/test_squeak_node.py b/itests/tests/test_squeak_node.py index 221b4f6f..5c678003 100644 --- a/itests/tests/test_squeak_node.py +++ b/itests/tests/test_squeak_node.py @@ -20,6 +20,7 @@ from tests.util import ( squeak_from_msg, string_to_hex, open_channel, + connect_peer, ) @@ -162,7 +163,8 @@ def test_sell_squeak(server_stub, admin_stub, lightning_client, saved_squeak_has ) destination = decode_pay_req_response.destination - with open_channel(lightning_client, buy_response.offer.host, destination, 1000000): + with connect_peer(lightning_client, buy_response.offer.host, destination), \ + open_channel(lightning_client, destination, 1000000): # List peers list_peers_response = lightning_client.list_peers() @@ -631,7 +633,8 @@ def test_list_channels(server_stub, admin_stub, lightning_client, saved_squeak_h ) destination = decode_pay_req_response.destination - with open_channel(lightning_client, buy_response.offer.host, destination, 1000000): + with connect_peer(lightning_client, buy_response.offer.host, destination), \ + open_channel(lightning_client, destination, 1000000): # List channels get_info_response = lightning_client.get_info() list_channels_response = admin_stub.LndListChannels(ln.ListChannelsRequest()) @@ -710,3 +713,46 @@ def test_list_peers(server_stub, admin_stub, lightning_client, saved_squeak_hash peer.pub_key == get_info_response.identity_pubkey for peer in list_peers_response.peers ]) + +def test_open_channel(server_stub, admin_stub, lightning_client, saved_squeak_hash): + # Get the squeak from the server + get_response = server_stub.GetSqueak( + squeak_server_pb2.GetSqueakRequest(hash=saved_squeak_hash) + ) + get_response_squeak = squeak_from_msg(get_response.squeak) + CheckSqueak(get_response_squeak, skipDecryptionCheck=True) + + # Generate a challenge to verify the offer + expected_proof = generate_challenge_proof() + encryption_key = get_response_squeak.GetEncryptionKey() + challenge = get_challenge(encryption_key, expected_proof) + + # Buy the squeak data key + buy_response = server_stub.BuySqueak( + squeak_server_pb2.BuySqueakRequest( + hash=saved_squeak_hash, + challenge=challenge, + ) + ) + assert buy_response.offer.payment_request.startswith("ln") + + # Decode the payment request string + decode_pay_req_response = lightning_client.decode_pay_req( + buy_response.offer.payment_request + ) + destination = decode_pay_req_response.destination + + with connect_peer(lightning_client, buy_response.offer.host, destination): + # List pending channels + get_info_response = lightning_client.get_info() + pending_channels_response = admin_stub.LndPendingChannels(ln.PendingChannelsRequest()) + assert len(pending_channels_response.pending_open_channels) == 0 + + # Open the new channel + open_channel_response = admin_stub.LndOpenChannelSync(ln.OpenChannelRequest( + node_pubkey_string=get_info_response.identity_pubkey, + local_funding_amount=1000000, + )) + + pending_channels_response = admin_stub.LndPendingChannels(ln.PendingChannelsRequest()) + assert len(pending_channels_response.pending_open_channels) == 1 diff --git a/itests/tests/util.py b/itests/tests/util.py index a8bf6929..62db12d6 100644 --- a/itests/tests/util.py +++ b/itests/tests/util.py @@ -97,15 +97,20 @@ def string_to_hex(s): @contextmanager -def open_channel(lightning_client, lightning_host, remote_pubkey, amount): - # Connect to the server lightning node +def connect_peer(lightning_client, lightning_host, remote_pubkey): + connect_peer_response = lightning_client.connect_peer( + remote_pubkey, lightning_host + ) try: - connect_peer_response = lightning_client.connect_peer( - remote_pubkey, lightning_host + yield + finally: + # Disconnect the peer + disconnect_peer_response = lightning_client.disconnect_peer( + remote_pubkey, ) - except Exception as e: - print("Failed to connect to peer: {}".format(e)) +@contextmanager +def open_channel(lightning_client, remote_pubkey, amount): # Open channel to the server lightning node pubkey_bytes = string_to_hex(remote_pubkey) open_channel_response = lightning_client.open_channel(pubkey_bytes, amount) @@ -125,8 +130,3 @@ def open_channel(lightning_client, lightning_host, remote_pubkey, amount): if update.HasField("chan_close"): print("Channel closed.") break - - # Disconnect the peer - disconnect_peer_response = lightning_client.disconnect_peer( - remote_pubkey, - ) diff --git a/proto/squeak_admin.proto b/proto/squeak_admin.proto index 2ab19310..e70e160e 100644 --- a/proto/squeak_admin.proto +++ b/proto/squeak_admin.proto @@ -28,6 +28,10 @@ service SqueakAdmin { */ rpc LndListChannels (lnrpc.ListChannelsRequest) returns (lnrpc.ListChannelsResponse) {} + /** sqkadmin: `lndpendingchannels` + */ + rpc LndPendingChannels (lnrpc.PendingChannelsRequest) returns (lnrpc.PendingChannelsResponse) {} + /** sqkadmin: `lndgettransactions` */ rpc LndGetTransactions (lnrpc.GetTransactionsRequest) returns (lnrpc.TransactionDetails) {} @@ -44,6 +48,14 @@ service SqueakAdmin { */ rpc LndDisconnectPeer (lnrpc.DisconnectPeerRequest) returns (lnrpc.DisconnectPeerResponse) {} + /** sqkadmin: `lndopenchannelsync` + */ + rpc LndOpenChannelSync (lnrpc.OpenChannelRequest) returns (lnrpc.ChannelPoint) {} + + /** sqkadmin: `lndclosechannel` + */ + rpc LndCloseChannel (lnrpc.CloseChannelRequest) returns (stream lnrpc.CloseStatusUpdate) {} + /** sqkadmin: `createsigningprofile` */ rpc CreateSigningProfile (CreateSigningProfileRequest) returns (CreateSigningProfileReply) {} diff --git a/squeakserver/admin/squeak_admin_server_handler.py b/squeakserver/admin/squeak_admin_server_handler.py index 0c672b89..c8c42967 100644 --- a/squeakserver/admin/squeak_admin_server_handler.py +++ b/squeakserver/admin/squeak_admin_server_handler.py @@ -33,6 +33,10 @@ class SqueakAdminServerHandler(object): logger.info("Handle lnd list channels") return self.lightning_client.list_channels() + def handle_lnd_pending_channels(self): + logger.info("Handle lnd pending channels") + return self.lightning_client.pending_channels() + def handle_lnd_get_transactions(self): logger.info("Handle lnd get transactions") return self.lightning_client.get_transactions() @@ -51,6 +55,25 @@ class SqueakAdminServerHandler(object): logger.info("Handle disconnect peer with pubkey: {}".format(pubkey)) return self.lightning_client.disconnect_peer(pubkey) + def handle_lnd_open_channel_sync(self, node_pubkey_string, local_funding_amount, sat_per_byte): + logger.info("Handle open channel to peer with pubkey: {}, amount: {}".format( + node_pubkey_string, + local_funding_amount, + )) + return self.lightning_client.open_channel_sync( + node_pubkey_string, + local_funding_amount, + ) + + def handle_lnd_close_channel(self, channel_point, sat_per_byte): + logger.info("Handle close channel with channel_point: {}".format( + channel_point, + sat_per_byte, + )) + return self.lightning_client.close_channel( + channel_point, + ) + def handle_create_signing_profile(self, profile_name): logger.info("Handle create signing profile with name: {}".format(profile_name)) profile_id = self.squeak_node.create_signing_profile(profile_name) diff --git a/squeakserver/admin/squeak_admin_server_servicer.py b/squeakserver/admin/squeak_admin_server_servicer.py index d4716423..2a65ab9a 100644 --- a/squeakserver/admin/squeak_admin_server_servicer.py +++ b/squeakserver/admin/squeak_admin_server_servicer.py @@ -31,6 +31,9 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer): def LndListChannels(self, request, context): return self.handler.handle_lnd_list_channels() + def LndPendingChannels(self, request, context): + return self.handler.handle_lnd_pending_channels() + def LndGetTransactions(self, request, context): return self.handler.handle_lnd_get_transactions() @@ -45,6 +48,24 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer): pubkey = request.pub_key return self.handler.handle_lnd_disconnect_peer(pubkey) + def LndOpenChannelSync(self, request, context): + node_pubkey_string = request.node_pubkey_string + local_funding_amount = request.local_funding_amount + sat_per_byte = request.sat_per_byte + return self.handler.handle_lnd_open_channel_sync( + node_pubkey_string, + local_funding_amount, + sat_per_byte, + ) + + def LndCloseChannel(self, request, context): + channel_point = request.channel_point + sat_per_byte = request.sat_per_byte + return self.handler.handle_lnd_close_channel( + channel_point, + sat_per_byte, + ) + def CreateSigningProfile(self, request, context): profile_name = request.profile_name profile_id = self.handler.handle_create_signing_profile(profile_name) diff --git a/squeakserver/common/lnd_lightning_client.py b/squeakserver/common/lnd_lightning_client.py index 95666d34..23e75976 100644 --- a/squeakserver/common/lnd_lightning_client.py +++ b/squeakserver/common/lnd_lightning_client.py @@ -134,6 +134,13 @@ class LNDLightningClient: list_channels_request, metadata=[("macaroon", self.macaroon)] ) + def pending_channels(self): + """List the pending channels""" + pending_channels_request = lnd_pb2.PendingChannelsRequest() + return self.stub.PendingChannels( + pending_channels_request, metadata=[("macaroon", self.macaroon)] + ) + def list_peers(self): """List the peers""" list_peers_request = lnd_pb2.ListPeersRequest()