From cf605c81abd10a66eef29380c7ae14ceee764f86 Mon Sep 17 00:00:00 2001 From: afederigo Date: Tue, 2 May 2017 22:31:35 +0300 Subject: [PATCH] lnd: add server calls for disconnecting peers Issue: 139 This commit contains client-side and server-side functionality for disconnecting peers. rpc-client calls server side method and sends message with pubKey. --- rpcserver.go | 16 +++++++++--- server.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 5fe881ea..40b72bb4 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -240,6 +240,16 @@ func (r *rpcServer) ConnectPeer(ctx context.Context, return &lnrpc.ConnectPeerResponse{}, nil } +// DisconnectPeer attempts to disconnect one peer from another identified by a given pubKey. +func (r *rpcServer) DisconnectPeer(ctx context.Context, in *lnrpc.DisconnectPeerRequest) (*lnrpc.DisconnectPeerResponse, error) { + if err := r.server.DisconnectFromPeer(in.PubKey); err != nil { + return nil, fmt.Errorf("unable to disconnect peer: %v", err) + } + rpcsLog.Debugf("[disconnectpeer] from peer(%s)", in.PubKey) + + return &lnrpc.DisconnectPeerResponse{}, nil +} + // OpenChannel attempts to open a singly funded channel specified in the // request to a remote peer. func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest, @@ -644,19 +654,19 @@ func (r *rpcServer) GetInfo(ctx context.Context, pendingChannels, err := r.server.fundingMgr.NumPendingChannels() if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get number of pending channels: %v", err) } idPub := r.server.identityPriv.PubKey().SerializeCompressed() bestHash, bestHeight, err := r.server.bio.GetBestBlock() if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get best block info: %v", err) } isSynced, err := r.server.lnwallet.IsSynced() if err != nil { - return nil, err + return nil, fmt.Errorf("unable to sync PoV of the wallet with current best block in the main chain: %v", err) } activeChains := make([]string, registeredChains.NumActiveChains()) diff --git a/server.go b/server.go index 6dec4054..9c1679df 100644 --- a/server.go +++ b/server.go @@ -434,6 +434,7 @@ func (s *server) establishPersistentConnections() error { } } pubStr := string(node.IdentityPub.SerializeCompressed()) + nodeAddrs := &nodeAddresses{ pubKey: node.IdentityPub, addresses: node.Addresses, @@ -947,6 +948,12 @@ type connectPeerMsg struct { err chan error } +type disconnectPeerMsg struct { + pubKey string + + err chan error +} + // listPeersMsg is a message sent to the server in order to obtain a listing // of all currently active channels. type listPeersMsg struct { @@ -1057,6 +1064,8 @@ out: }() case query := <-s.queries: switch msg := query.(type) { + case *disconnectPeerMsg: + s.handleDisconnectPeer(msg) case *connectPeerMsg: s.handleConnectPeer(msg) case *listPeersMsg: @@ -1157,6 +1166,57 @@ func (s *server) handleConnectPeer(msg *connectPeerMsg) { } } +// handleDisconnectPeer attempts to disconnect one peer from another +func (s *server) handleDisconnectPeer(msg *disconnectPeerMsg) { + pubKey, err := hex.DecodeString(msg.pubKey) + if err != nil { + msg.err <- fmt.Errorf("unable to DecodeString public key: %v", err) + return + } + + // Ensure we're already connected to this peer. + s.peersMtx.RLock() + peer, ok := s.peersByPub[string(pubKey)] + s.peersMtx.RUnlock() + if !ok { + msg.err <- fmt.Errorf("unable to find peer(%v) by public key(%v)", peer, msg.pubKey) + return + } + + // Get all pending and active channels corresponding with current node. + allChannels, err := s.chanDB.FetchAllChannels() + if err != nil { + msg.err <- fmt.Errorf("unable to get opened channels: %v", err) + return + } + + // Filter by public key all channels corresponding with the detached node. + var nodeChannels []*channeldb.OpenChannel + + for _, channel := range allChannels { + if hex.EncodeToString(channel.IdentityPub.SerializeCompressed()) == msg.pubKey { + nodeChannels = append(nodeChannels, channel) + } + } + + // Send server info logs containing channels id's and raise error about + // primary closing channels before start disconnecting peer. + if len(nodeChannels) > 0 { + for _, channel := range nodeChannels { + srvrLog.Infof("Before disconnect peer(%v) close channel: %v", + msg.pubKey, channel.ChanID) + } + msg.err <- fmt.Errorf("before disconnect peer(%v) you have to close "+ + "active and pending channels corresponding to that peer; %v", + msg.pubKey, nodeChannels) + return + } + + srvrLog.Infof("Disconnecting from %v", peer) + peer.Disconnect() + msg.err <- nil +} + // handleOpenChanReq first locates the target peer, and if found hands off the // request to the funding manager allowing it to initiate the channel funding // workflow. @@ -1214,6 +1274,20 @@ func (s *server) ConnectToPeer(addr *lnwire.NetAddress, return <-errChan } +// DisconnectFromPeer sends the request to server to close the connection +// with peer identified by public key. +func (s *server) DisconnectFromPeer(pubkey string) error { + + errChan := make(chan error, 1) + + s.queries <- &disconnectPeerMsg{ + pubKey: pubkey, + err: errChan, + } + + return <-errChan +} + // OpenChannel sends a request to the server to open a channel to the specified // peer identified by ID with the passed channel funding paramters. func (s *server) OpenChannel(peerID int32, nodeKey *btcec.PublicKey,