2015-12-21 00:16:38 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2016-09-21 03:15:26 +03:00
|
|
|
"bytes"
|
2016-01-14 08:41:46 +03:00
|
|
|
"container/list"
|
2016-11-11 04:15:25 +03:00
|
|
|
"crypto/rand"
|
2017-03-16 04:56:25 +03:00
|
|
|
"crypto/sha256"
|
2016-11-11 04:15:25 +03:00
|
|
|
"encoding/binary"
|
2016-07-10 02:41:06 +03:00
|
|
|
"fmt"
|
2015-12-21 02:10:09 +03:00
|
|
|
"net"
|
2015-12-21 00:16:38 +03:00
|
|
|
"sync"
|
2016-01-14 08:41:46 +03:00
|
|
|
"sync/atomic"
|
2015-12-21 00:16:38 +03:00
|
|
|
"time"
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2017-02-23 01:49:04 +03:00
|
|
|
"github.com/go-errors/errors"
|
2016-09-21 03:15:26 +03:00
|
|
|
"github.com/lightningnetwork/lightning-onion"
|
2016-06-21 22:32:32 +03:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2016-08-31 02:52:53 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
2016-01-18 06:14:47 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2016-06-21 22:32:32 +03:00
|
|
|
"github.com/roasbeef/btcd/btcec"
|
2017-01-06 00:56:27 +03:00
|
|
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
2017-01-06 00:58:06 +03:00
|
|
|
"github.com/roasbeef/btcd/connmgr"
|
2016-06-21 22:32:32 +03:00
|
|
|
"github.com/roasbeef/btcd/txscript"
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/wire"
|
2016-08-26 02:30:22 +03:00
|
|
|
"github.com/roasbeef/btcutil"
|
2016-01-17 06:03:03 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
numNodes int32
|
2015-12-21 00:16:38 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2016-06-21 22:32:32 +03:00
|
|
|
// pingInterval is the interval at which ping messages are sent.
|
2017-01-23 01:35:26 +03:00
|
|
|
pingInterval = 1 * time.Minute
|
2016-01-17 06:03:03 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// outgoingQueueLen is the buffer size of the channel which houses
|
|
|
|
// messages to be sent across the wire, requested by objects outside
|
|
|
|
// this struct.
|
2016-01-17 06:03:03 +03:00
|
|
|
outgoingQueueLen = 50
|
2015-12-21 00:16:38 +03:00
|
|
|
)
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// outgoinMsg packages an lnwire.Message to be sent out on the wire, along with
|
|
|
|
// a buffered channel which will be sent upon once the write is complete. This
|
|
|
|
// buffered channel acts as a semaphore to be used for synchronization purposes.
|
2016-01-14 08:41:46 +03:00
|
|
|
type outgoinMsg struct {
|
|
|
|
msg lnwire.Message
|
2016-06-21 22:32:32 +03:00
|
|
|
sentChan chan struct{} // MUST be buffered.
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
|
2017-01-24 05:19:54 +03:00
|
|
|
// newChannelMsg packages a lnwallet.LightningChannel with a channel that
|
|
|
|
// allows the receiver of the request to report when the funding transaction
|
|
|
|
// has been confirmed and the channel creation process completed.
|
|
|
|
type newChannelMsg struct {
|
|
|
|
channel *lnwallet.LightningChannel
|
|
|
|
done chan struct{}
|
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// chanSnapshotReq is a message sent by outside subsystems to a peer in order
|
2016-06-23 08:22:06 +03:00
|
|
|
// to gain a snapshot of the peer's currently active channels.
|
|
|
|
type chanSnapshotReq struct {
|
|
|
|
resp chan []*channeldb.ChannelSnapshot
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// peer is an active peer on the Lightning Network. This struct is responsible
|
2016-11-11 04:15:25 +03:00
|
|
|
// for managing any channel state related to this peer. To do so, it has
|
|
|
|
// several helper goroutines to handle events such as HTLC timeouts, new
|
|
|
|
// funding workflow, and detecting an uncooperative closure of any active
|
|
|
|
// channels.
|
2016-09-26 20:39:47 +03:00
|
|
|
// TODO(roasbeef): proper reconnection logic
|
2015-12-21 00:16:38 +03:00
|
|
|
type peer struct {
|
2017-01-30 11:53:09 +03:00
|
|
|
// The following fields are only meant to be used *atomically*
|
|
|
|
bytesReceived uint64
|
|
|
|
bytesSent uint64
|
|
|
|
|
|
|
|
// pingTime is a rough estimate of the RTT (round-trip-time) between us
|
|
|
|
// and the connected peer. This time is expressed in micro seconds.
|
|
|
|
// TODO(roasbeef): also use a WMA or EMA?
|
|
|
|
pingTime int64
|
|
|
|
|
|
|
|
// pingLastSend is the Unix time expressed in nanoseconds when we sent
|
|
|
|
// our last ping message.
|
|
|
|
pingLastSend int64
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// MUST be used atomically.
|
2015-12-21 00:16:38 +03:00
|
|
|
started int32
|
2016-01-17 06:03:03 +03:00
|
|
|
disconnect int32
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2016-12-15 05:11:31 +03:00
|
|
|
connReq *connmgr.ConnReq
|
|
|
|
conn net.Conn
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2016-10-28 05:49:10 +03:00
|
|
|
addr *lnwire.NetAddress
|
2017-01-06 00:56:27 +03:00
|
|
|
lightningID chainhash.Hash
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-06-23 08:22:06 +03:00
|
|
|
inbound bool
|
|
|
|
id int32
|
2015-12-21 00:16:38 +03:00
|
|
|
|
|
|
|
// For purposes of detecting retransmits, etc.
|
2016-01-17 06:03:03 +03:00
|
|
|
lastNMessages map[lnwire.Message]struct{}
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// This mutex protects all the stats below it.
|
2016-01-17 06:03:03 +03:00
|
|
|
sync.RWMutex
|
2016-06-21 22:32:32 +03:00
|
|
|
timeConnected time.Time
|
|
|
|
lastSend time.Time
|
|
|
|
lastRecv time.Time
|
|
|
|
|
|
|
|
// sendQueue is the channel which is used to queue outgoing to be
|
|
|
|
// written onto the wire. Note that this channel is unbuffered.
|
|
|
|
sendQueue chan outgoinMsg
|
|
|
|
|
|
|
|
// outgoingQueue is a buffered channel which allows second/third party
|
|
|
|
// objects to queue messages to be sent out on the wire.
|
2016-01-14 08:41:46 +03:00
|
|
|
outgoingQueue chan outgoinMsg
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// sendQueueSync is used as a semaphore to synchronize writes between
|
|
|
|
// the writeHandler and the queueHandler.
|
|
|
|
sendQueueSync chan struct{}
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// activeChannels is a map which stores the state machines of all
|
|
|
|
// active channels. Channels are indexed into the map by the txid of
|
|
|
|
// the funding transaction which opened the channel.
|
2016-11-18 05:43:33 +03:00
|
|
|
activeChanMtx sync.RWMutex
|
2016-06-23 08:22:06 +03:00
|
|
|
activeChannels map[wire.OutPoint]*lnwallet.LightningChannel
|
|
|
|
chanSnapshotReqs chan *chanSnapshotReq
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-11-18 05:43:33 +03:00
|
|
|
htlcManMtx sync.RWMutex
|
2016-07-10 02:41:06 +03:00
|
|
|
htlcManagers map[wire.OutPoint]chan lnwire.Message
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// newChannels is used by the fundingManager to send fully opened
|
|
|
|
// channels to the source peer which handled the funding workflow.
|
2017-01-24 05:19:54 +03:00
|
|
|
newChannels chan *newChannelMsg
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-11-11 04:15:25 +03:00
|
|
|
// localCloseChanReqs is a channel in which any local requests to close
|
|
|
|
// a particular channel are sent over.
|
2016-07-10 02:41:06 +03:00
|
|
|
localCloseChanReqs chan *closeLinkReq
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
// remoteCloseChanReqs is a channel in which any remote requests
|
|
|
|
// (initiated by the remote peer) close a particular channel are sent
|
|
|
|
// over.
|
|
|
|
remoteCloseChanReqs chan *lnwire.CloseRequest
|
|
|
|
|
|
|
|
// nextPendingChannelID is an integer which represents the id of the
|
|
|
|
// next pending channel. Pending channels are tracked by this id
|
|
|
|
// throughout their lifetime until they become active channels, or are
|
|
|
|
// cancelled. Channels id's initiated by an outbound node start from 0,
|
2016-11-11 04:15:25 +03:00
|
|
|
// while channels initiated by an inbound node start from 2^63. In
|
2016-06-21 22:32:32 +03:00
|
|
|
// either case, this value is always monotonically increasing.
|
|
|
|
nextPendingChannelID uint64
|
|
|
|
pendingChannelMtx sync.RWMutex
|
|
|
|
|
|
|
|
server *server
|
2015-12-21 00:16:38 +03:00
|
|
|
|
2017-02-16 15:39:38 +03:00
|
|
|
// localSharedFeatures is a product of comparison of our and their
|
|
|
|
// local features vectors which consist of features which are present
|
|
|
|
// on both sides.
|
2017-02-23 01:49:04 +03:00
|
|
|
localSharedFeatures *lnwire.SharedFeatures
|
2017-02-16 15:39:38 +03:00
|
|
|
|
|
|
|
// globalSharedFeatures is a product of comparison of our and their
|
|
|
|
// global features vectors which consist of features which are present
|
|
|
|
// on both sides.
|
|
|
|
globalSharedFeatures *lnwire.SharedFeatures
|
|
|
|
|
2015-12-21 00:16:38 +03:00
|
|
|
queueQuit chan struct{}
|
|
|
|
quit chan struct{}
|
2016-01-14 08:41:46 +03:00
|
|
|
wg sync.WaitGroup
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// newPeer creates a new peer from an establish connection object, and a
|
|
|
|
// pointer to the main server.
|
2017-02-22 12:10:07 +03:00
|
|
|
func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
|
|
|
|
addr *lnwire.NetAddress, inbound bool) (*peer, error) {
|
2016-10-28 05:49:10 +03:00
|
|
|
|
|
|
|
nodePub := addr.IdentityKey
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
p := &peer{
|
|
|
|
conn: conn,
|
2017-03-16 04:56:25 +03:00
|
|
|
lightningID: chainhash.Hash(sha256.Sum256(nodePub.SerializeCompressed())),
|
2016-10-28 05:49:10 +03:00
|
|
|
addr: addr,
|
|
|
|
|
|
|
|
id: atomic.AddInt32(&numNodes, 1),
|
|
|
|
inbound: inbound,
|
2017-02-22 12:10:07 +03:00
|
|
|
connReq: connReq,
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
server: server,
|
2016-01-17 06:03:03 +03:00
|
|
|
|
|
|
|
lastNMessages: make(map[lnwire.Message]struct{}),
|
|
|
|
|
|
|
|
sendQueueSync: make(chan struct{}, 1),
|
|
|
|
sendQueue: make(chan outgoinMsg, 1),
|
|
|
|
outgoingQueue: make(chan outgoinMsg, outgoingQueueLen),
|
|
|
|
|
2016-06-23 08:22:06 +03:00
|
|
|
activeChannels: make(map[wire.OutPoint]*lnwallet.LightningChannel),
|
2016-07-10 02:41:06 +03:00
|
|
|
htlcManagers: make(map[wire.OutPoint]chan lnwire.Message),
|
2016-06-23 08:22:06 +03:00
|
|
|
chanSnapshotReqs: make(chan *chanSnapshotReq),
|
2017-01-24 05:19:54 +03:00
|
|
|
newChannels: make(chan *newChannelMsg, 1),
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
localCloseChanReqs: make(chan *closeLinkReq),
|
2016-06-21 22:32:32 +03:00
|
|
|
remoteCloseChanReqs: make(chan *lnwire.CloseRequest),
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
localSharedFeatures: nil,
|
|
|
|
globalSharedFeatures: nil,
|
2017-02-16 15:39:38 +03:00
|
|
|
|
2016-01-17 06:03:03 +03:00
|
|
|
queueQuit: make(chan struct{}),
|
|
|
|
quit: make(chan struct{}),
|
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
// Initiate the pending channel identifier properly depending on if this
|
|
|
|
// node is inbound or outbound. This value will be used in an increasing
|
|
|
|
// manner to track pending channels.
|
2017-02-22 12:10:07 +03:00
|
|
|
if p.inbound {
|
2016-06-21 22:32:32 +03:00
|
|
|
p.nextPendingChannelID = 1 << 63
|
|
|
|
} else {
|
|
|
|
p.nextPendingChannelID = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch and then load all the active channels we have with this
|
|
|
|
// remote peer from the database.
|
2016-10-28 05:49:10 +03:00
|
|
|
activeChans, err := server.chanDB.FetchOpenChannels(p.addr.IdentityKey)
|
2016-06-21 22:32:32 +03:00
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to fetch active chans "+
|
|
|
|
"for peer %v: %v", p, err)
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-06-23 08:19:24 +03:00
|
|
|
peerLog.Debugf("Loaded %v active channels from database with peerID(%v)",
|
|
|
|
len(activeChans), p.id)
|
2016-06-21 22:32:32 +03:00
|
|
|
if err := p.loadActiveChannels(activeChans); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadActiveChannels creates indexes within the peer for tracking all active
|
|
|
|
// channels returned by the database.
|
|
|
|
func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
|
|
|
|
for _, dbChan := range chans {
|
2017-02-25 03:19:10 +03:00
|
|
|
if dbChan.IsPending {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
chanID := dbChan.ChanID
|
2016-08-13 01:56:57 +03:00
|
|
|
lnChan, err := lnwallet.NewLightningChannel(p.server.lnwallet.Signer,
|
2017-02-03 04:05:25 +03:00
|
|
|
p.server.chainNotifier, dbChan)
|
2016-06-21 22:32:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
chanPoint := wire.OutPoint{
|
|
|
|
Hash: chanID.Hash,
|
|
|
|
Index: chanID.Index,
|
|
|
|
}
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.Lock()
|
2016-06-21 22:32:32 +03:00
|
|
|
p.activeChannels[chanPoint] = lnChan
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.Unlock()
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
peerLog.Infof("peerID(%v) loaded ChannelPoint(%v)", p.id, chanPoint)
|
|
|
|
|
2016-12-28 02:54:57 +03:00
|
|
|
p.server.breachArbiter.newContracts <- lnChan
|
2016-11-11 04:41:23 +03:00
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
// Register this new channel link with the HTLC Switch. This is
|
|
|
|
// necessary to properly route multi-hop payments, and forward
|
|
|
|
// new payments triggered by RPC clients.
|
2016-07-22 02:53:07 +03:00
|
|
|
downstreamLink := make(chan *htlcPacket, 10)
|
2016-07-13 03:45:29 +03:00
|
|
|
plexChan := p.server.htlcSwitch.RegisterLink(p,
|
|
|
|
dbChan.Snapshot(), downstreamLink)
|
2016-07-10 02:41:06 +03:00
|
|
|
|
2016-07-22 02:53:07 +03:00
|
|
|
upstreamLink := make(chan lnwire.Message, 10)
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Lock()
|
2016-07-10 02:41:06 +03:00
|
|
|
p.htlcManagers[chanPoint] = upstreamLink
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Unlock()
|
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
p.wg.Add(1)
|
2016-07-13 03:45:29 +03:00
|
|
|
go p.htlcManager(lnChan, plexChan, downstreamLink, upstreamLink)
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2016-01-17 06:03:03 +03:00
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// Start starts all helper goroutines the peer needs for normal operations.
|
2016-11-11 04:15:25 +03:00
|
|
|
// In the case this peer has already been started, then this function is a
|
2017-02-16 15:39:38 +03:00
|
|
|
// loop.
|
2016-01-17 06:03:03 +03:00
|
|
|
func (p *peer) Start() error {
|
|
|
|
if atomic.AddInt32(&p.started, 1) != 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
peerLog.Tracef("peer %v starting", p)
|
2016-01-17 06:03:03 +03:00
|
|
|
|
2017-02-16 15:39:38 +03:00
|
|
|
p.wg.Add(2)
|
2016-01-17 06:03:03 +03:00
|
|
|
go p.queueHandler()
|
2016-06-21 22:32:32 +03:00
|
|
|
go p.writeHandler()
|
2017-02-16 15:39:38 +03:00
|
|
|
|
|
|
|
// Exchange local and global features, the init message should be
|
|
|
|
// very first between two nodes.
|
|
|
|
if err := p.sendInitMsg(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should wait for peers to compare their feature vectors
|
|
|
|
// and only then start message exchanges.
|
|
|
|
msg, _, err := p.readNextMessage()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg, ok := msg.(*lnwire.Init); ok {
|
|
|
|
if err := p.handleInitMsg(msg); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return errors.New("very first message between nodes " +
|
|
|
|
"must be init message")
|
|
|
|
}
|
|
|
|
|
|
|
|
p.wg.Add(3)
|
|
|
|
go p.readHandler()
|
2016-06-21 22:32:32 +03:00
|
|
|
go p.channelManager()
|
2016-11-11 04:15:25 +03:00
|
|
|
go p.pingHandler()
|
2016-01-17 06:03:03 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// Stop signals the peer for a graceful shutdown. All active goroutines will be
|
|
|
|
// signaled to wrap up any final actions. This function will also block until
|
|
|
|
// all goroutines have exited.
|
2016-01-17 06:03:03 +03:00
|
|
|
func (p *peer) Stop() error {
|
|
|
|
// If we're already disconnecting, just exit.
|
2017-02-07 02:04:52 +03:00
|
|
|
if !atomic.CompareAndSwapInt32(&p.disconnect, 0, 1) {
|
2016-01-17 06:03:03 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-07 02:04:52 +03:00
|
|
|
// Ensure that the TCP connection is properly closed before continuing.
|
|
|
|
p.conn.Close()
|
2016-01-17 06:03:03 +03:00
|
|
|
|
|
|
|
// Signal all worker goroutines to gracefully exit.
|
|
|
|
close(p.quit)
|
2016-06-21 22:32:32 +03:00
|
|
|
p.wg.Wait()
|
2016-01-17 06:03:03 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-21 09:06:16 +03:00
|
|
|
// TODO(roasbeef): add WaitForShutdown method
|
|
|
|
|
2016-07-14 02:40:01 +03:00
|
|
|
// Disconnect terminates the connection with the remote peer. Additionally, a
|
|
|
|
// signal is sent to the server and htlcSwitch indicating the resources
|
|
|
|
// allocated to the peer can now be cleaned up.
|
|
|
|
func (p *peer) Disconnect() {
|
|
|
|
if !atomic.CompareAndSwapInt32(&p.disconnect, 0, 1) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
peerLog.Tracef("Disconnecting %s", p)
|
2017-02-07 02:04:52 +03:00
|
|
|
|
|
|
|
// Ensure that the TCP connection is properly closed before continuing.
|
|
|
|
p.conn.Close()
|
2016-07-14 02:40:01 +03:00
|
|
|
|
|
|
|
close(p.quit)
|
|
|
|
|
2017-02-07 02:04:52 +03:00
|
|
|
// If this connection was established persistently, then notify the
|
|
|
|
// connection manager that the peer has been disconnected.
|
2016-12-15 05:11:31 +03:00
|
|
|
if p.connReq != nil {
|
|
|
|
p.server.connMgr.Disconnect(p.connReq.ID())
|
|
|
|
}
|
|
|
|
|
2016-07-14 02:40:01 +03:00
|
|
|
// Launch a goroutine to clean up the remaining resources.
|
|
|
|
go func() {
|
|
|
|
// Tell the switch to unregister all links associated with this
|
2017-01-08 07:23:06 +03:00
|
|
|
// peer. Passing nil as the target link indicates that all
|
|
|
|
// links associated with this interface should be closed.
|
2016-10-28 05:49:10 +03:00
|
|
|
p.server.htlcSwitch.UnregisterLink(p.addr.IdentityKey, nil)
|
2016-07-14 02:40:01 +03:00
|
|
|
|
|
|
|
p.server.donePeers <- p
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// String returns the string representation of this peer.
|
|
|
|
func (p *peer) String() string {
|
|
|
|
return p.conn.RemoteAddr().String()
|
|
|
|
}
|
|
|
|
|
|
|
|
// readNextMessage reads, and returns the next message on the wire along with
|
|
|
|
// any additional raw payload.
|
2016-01-14 08:41:46 +03:00
|
|
|
func (p *peer) readNextMessage() (lnwire.Message, []byte, error) {
|
|
|
|
// TODO(roasbeef): use our own net magic?
|
2016-10-28 05:49:10 +03:00
|
|
|
n, nextMsg, rawPayload, err := lnwire.ReadMessage(p.conn, 0,
|
|
|
|
p.addr.ChainNet)
|
2016-06-21 22:32:32 +03:00
|
|
|
atomic.AddUint64(&p.bytesReceived, uint64(n))
|
2016-01-14 08:41:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// TODO(roasbeef): add message summaries
|
2017-01-15 04:52:05 +03:00
|
|
|
p.logWireMessage(nextMsg, true)
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-01-14 08:41:46 +03:00
|
|
|
return nextMsg, rawPayload, nil
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// readHandler is responsible for reading messages off the wire in series, then
|
2017-01-13 08:01:50 +03:00
|
|
|
// properly dispatching the handling of the message to the proper subsystem.
|
2016-06-21 22:32:32 +03:00
|
|
|
//
|
|
|
|
// NOTE: This method MUST be run as a goroutine.
|
|
|
|
func (p *peer) readHandler() {
|
2016-01-14 08:41:46 +03:00
|
|
|
out:
|
|
|
|
for atomic.LoadInt32(&p.disconnect) == 0 {
|
|
|
|
nextMsg, _, err := p.readNextMessage()
|
|
|
|
if err != nil {
|
2017-01-24 07:33:18 +03:00
|
|
|
peerLog.Infof("unable to read message from %v: %v",
|
|
|
|
p, err)
|
2017-01-17 05:03:34 +03:00
|
|
|
|
|
|
|
switch err.(type) {
|
|
|
|
// If this is just a message we don't yet recognize,
|
|
|
|
// we'll continue processing as normal as this allows
|
|
|
|
// us to introduce new messages in a forwards
|
|
|
|
// compatible manner.
|
|
|
|
case *lnwire.UnknownMessage:
|
|
|
|
continue
|
|
|
|
|
|
|
|
// If the error we encountered wasn't just a message we
|
|
|
|
// didn't recognize, then we'll stop all processing s
|
|
|
|
// this is a fatal error.
|
|
|
|
default:
|
|
|
|
break out
|
|
|
|
}
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
var (
|
|
|
|
isChanUpdate bool
|
|
|
|
targetChan wire.OutPoint
|
|
|
|
)
|
2016-07-13 03:45:29 +03:00
|
|
|
|
2016-01-14 08:41:46 +03:00
|
|
|
switch msg := nextMsg.(type) {
|
2017-01-26 05:20:55 +03:00
|
|
|
case *lnwire.Pong:
|
|
|
|
// When we receive a Pong message in response to our
|
|
|
|
// last ping message, we'll use the time in which we
|
|
|
|
// sent the ping message to measure a rough estimate of
|
|
|
|
// round trip time.
|
|
|
|
pingSendTime := atomic.LoadInt64(&p.pingLastSend)
|
|
|
|
delay := (time.Now().UnixNano() - pingSendTime) / 1000
|
|
|
|
atomic.StoreInt64(&p.pingTime, delay)
|
|
|
|
|
2016-11-11 04:15:25 +03:00
|
|
|
case *lnwire.Ping:
|
|
|
|
p.queueMsg(lnwire.NewPong(msg.Nonce), nil)
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
case *lnwire.SingleFundingRequest:
|
2017-01-13 06:40:38 +03:00
|
|
|
p.server.fundingMgr.processFundingRequest(msg, p.addr)
|
2016-06-21 22:32:32 +03:00
|
|
|
case *lnwire.SingleFundingResponse:
|
2017-01-13 06:40:38 +03:00
|
|
|
p.server.fundingMgr.processFundingResponse(msg, p.addr)
|
2016-06-21 22:32:32 +03:00
|
|
|
case *lnwire.SingleFundingComplete:
|
2017-01-13 06:40:38 +03:00
|
|
|
p.server.fundingMgr.processFundingComplete(msg, p.addr)
|
2016-06-21 22:32:32 +03:00
|
|
|
case *lnwire.SingleFundingSignComplete:
|
2017-01-13 06:40:38 +03:00
|
|
|
p.server.fundingMgr.processFundingSignComplete(msg, p.addr)
|
2017-01-31 05:45:28 +03:00
|
|
|
case *lnwire.FundingLocked:
|
|
|
|
p.server.fundingMgr.processFundingLocked(msg, p.addr)
|
2016-06-21 22:32:32 +03:00
|
|
|
case *lnwire.CloseRequest:
|
|
|
|
p.remoteCloseChanReqs <- msg
|
2016-10-15 16:24:56 +03:00
|
|
|
|
|
|
|
case *lnwire.ErrorGeneric:
|
2017-01-13 06:40:38 +03:00
|
|
|
p.server.fundingMgr.processErrorGeneric(msg, p.addr)
|
2016-12-27 08:42:23 +03:00
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// TODO(roasbeef): create ChanUpdater interface for the below
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateAddHTLC:
|
2016-10-15 16:18:38 +03:00
|
|
|
isChanUpdate = true
|
2016-07-13 03:45:29 +03:00
|
|
|
targetChan = msg.ChannelPoint
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateFufillHTLC:
|
2016-10-15 16:18:38 +03:00
|
|
|
isChanUpdate = true
|
2016-07-13 03:45:29 +03:00
|
|
|
targetChan = msg.ChannelPoint
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateFailHTLC:
|
2017-01-08 07:23:06 +03:00
|
|
|
isChanUpdate = true
|
|
|
|
targetChan = msg.ChannelPoint
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.RevokeAndAck:
|
2016-10-15 16:18:38 +03:00
|
|
|
isChanUpdate = true
|
2016-07-13 03:45:29 +03:00
|
|
|
targetChan = msg.ChannelPoint
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.CommitSig:
|
2016-10-15 16:18:38 +03:00
|
|
|
isChanUpdate = true
|
2016-07-13 03:45:29 +03:00
|
|
|
targetChan = msg.ChannelPoint
|
2016-12-27 08:42:23 +03:00
|
|
|
|
|
|
|
case *lnwire.NodeAnnouncement,
|
|
|
|
*lnwire.ChannelAnnouncement,
|
|
|
|
*lnwire.ChannelUpdateAnnouncement:
|
|
|
|
|
|
|
|
p.server.chanRouter.ProcessRoutingMessage(msg,
|
|
|
|
p.addr.IdentityKey)
|
2016-07-13 03:45:29 +03:00
|
|
|
}
|
|
|
|
|
2016-10-15 16:18:38 +03:00
|
|
|
if isChanUpdate {
|
2017-01-24 02:33:46 +03:00
|
|
|
p.server.fundingMgr.waitUntilChannelOpen(targetChan)
|
2016-07-13 03:45:29 +03:00
|
|
|
// Dispatch the commitment update message to the proper
|
|
|
|
// active goroutine dedicated to this channel.
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Lock()
|
2017-02-21 05:10:05 +03:00
|
|
|
channel, ok := p.htlcManagers[targetChan]
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Unlock()
|
2016-07-13 03:45:29 +03:00
|
|
|
if !ok {
|
2017-01-23 01:36:59 +03:00
|
|
|
peerLog.Errorf("recv'd update for unknown "+
|
|
|
|
"channel %v from %v", targetChan, p)
|
2016-07-13 03:45:29 +03:00
|
|
|
continue
|
|
|
|
}
|
2017-01-23 01:36:59 +03:00
|
|
|
channel <- nextMsg
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 02:40:01 +03:00
|
|
|
p.Disconnect()
|
|
|
|
|
2016-01-14 08:41:46 +03:00
|
|
|
p.wg.Done()
|
2016-07-14 02:40:01 +03:00
|
|
|
peerLog.Tracef("readHandler for peer %v done", p)
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
|
2017-01-15 04:52:05 +03:00
|
|
|
// logWireMessage logs the receipt or sending of particular wire message. This
|
|
|
|
// function is used rather than just logging the message in order to produce
|
|
|
|
// less spammy log messages in trace mode by setting the 'Curve" parameter to
|
|
|
|
// nil. Doing this avoids printing out each of the field elements in the curve
|
|
|
|
// parameters for secp256k1.
|
|
|
|
func (p *peer) logWireMessage(msg lnwire.Message, read bool) {
|
|
|
|
switch m := msg.(type) {
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.RevokeAndAck:
|
2017-01-15 04:52:05 +03:00
|
|
|
m.NextRevocationKey.Curve = nil
|
|
|
|
case *lnwire.NodeAnnouncement:
|
|
|
|
m.NodeID.Curve = nil
|
|
|
|
case *lnwire.ChannelAnnouncement:
|
|
|
|
m.FirstNodeID.Curve = nil
|
|
|
|
m.SecondNodeID.Curve = nil
|
|
|
|
m.FirstBitcoinKey.Curve = nil
|
|
|
|
m.SecondBitcoinKey.Curve = nil
|
|
|
|
case *lnwire.SingleFundingComplete:
|
|
|
|
m.RevocationKey.Curve = nil
|
|
|
|
case *lnwire.SingleFundingRequest:
|
|
|
|
m.CommitmentKey.Curve = nil
|
|
|
|
m.ChannelDerivationPoint.Curve = nil
|
|
|
|
case *lnwire.SingleFundingResponse:
|
|
|
|
m.ChannelDerivationPoint.Curve = nil
|
|
|
|
m.CommitmentKey.Curve = nil
|
|
|
|
m.RevocationKey.Curve = nil
|
2017-01-31 05:45:28 +03:00
|
|
|
case *lnwire.FundingLocked:
|
|
|
|
m.NextPerCommitmentPoint.Curve = nil
|
2017-01-15 04:52:05 +03:00
|
|
|
}
|
|
|
|
|
2017-01-25 04:43:38 +03:00
|
|
|
prefix := "readMessage from"
|
2017-01-15 04:52:05 +03:00
|
|
|
if !read {
|
2017-01-25 04:43:38 +03:00
|
|
|
prefix = "writeMessage to"
|
2017-01-15 04:52:05 +03:00
|
|
|
}
|
|
|
|
|
2017-01-25 04:43:38 +03:00
|
|
|
peerLog.Tracef(prefix+" %v: %v", p, newLogClosure(func() string {
|
2017-01-15 04:52:05 +03:00
|
|
|
return spew.Sdump(msg)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// writeMessage writes the target lnwire.Message to the remote peer.
|
2016-01-14 08:41:46 +03:00
|
|
|
func (p *peer) writeMessage(msg lnwire.Message) error {
|
|
|
|
// Simply exit if we're shutting down.
|
|
|
|
if atomic.LoadInt32(&p.disconnect) != 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// TODO(roasbeef): add message summaries
|
2017-01-15 04:52:05 +03:00
|
|
|
p.logWireMessage(msg, false)
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-10-28 05:49:10 +03:00
|
|
|
n, err := lnwire.WriteMessage(p.conn, msg, 0, p.addr.ChainNet)
|
2016-06-21 22:32:32 +03:00
|
|
|
atomic.AddUint64(&p.bytesSent, uint64(n))
|
2016-01-14 08:41:46 +03:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// writeHandler is a goroutine dedicated to reading messages off of an incoming
|
|
|
|
// queue, and writing them out to the wire. This goroutine coordinates with the
|
|
|
|
// queueHandler in order to ensure the incoming message queue is quickly drained.
|
|
|
|
//
|
|
|
|
// NOTE: This method MUST be run as a goroutine.
|
|
|
|
func (p *peer) writeHandler() {
|
2017-02-02 04:01:33 +03:00
|
|
|
defer func() {
|
|
|
|
p.wg.Done()
|
|
|
|
peerLog.Tracef("writeHandler for peer %v done", p)
|
|
|
|
}()
|
|
|
|
|
2016-01-14 08:41:46 +03:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case outMsg := <-p.sendQueue:
|
2017-01-26 05:20:55 +03:00
|
|
|
switch outMsg.msg.(type) {
|
2017-02-02 04:01:33 +03:00
|
|
|
// If we're about to send a ping message, then log the
|
|
|
|
// exact time in which we send the message so we can
|
|
|
|
// use the delay as a rough estimate of latency to the
|
|
|
|
// remote peer.
|
2017-01-26 05:20:55 +03:00
|
|
|
case *lnwire.Ping:
|
|
|
|
// TODO(roasbeef): do this before the write?
|
|
|
|
// possibly account for processing within func?
|
|
|
|
now := time.Now().UnixNano()
|
|
|
|
atomic.StoreInt64(&p.pingLastSend, now)
|
|
|
|
}
|
|
|
|
|
2017-02-02 04:01:33 +03:00
|
|
|
// Write out the message to the socket, closing the
|
|
|
|
// 'sentChan' if it's non-nil, The 'sentChan' allows
|
|
|
|
// callers to optionally synchronize sends with the
|
|
|
|
// writeHandler.
|
|
|
|
err := p.writeMessage(outMsg.msg)
|
|
|
|
if outMsg.sentChan != nil {
|
|
|
|
close(outMsg.sentChan)
|
|
|
|
}
|
2016-01-14 08:41:46 +03:00
|
|
|
|
2017-02-02 04:01:33 +03:00
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to write message: %v",
|
|
|
|
err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
2017-02-02 04:01:33 +03:00
|
|
|
|
|
|
|
case <-p.quit:
|
|
|
|
return
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// queueHandler is responsible for accepting messages from outside subsystems
|
2016-06-21 22:32:32 +03:00
|
|
|
// to be eventually sent out on the wire by the writeHandler.
|
|
|
|
//
|
|
|
|
// NOTE: This method MUST be run as a goroutine.
|
2016-01-14 08:41:46 +03:00
|
|
|
func (p *peer) queueHandler() {
|
2017-02-02 04:01:33 +03:00
|
|
|
defer p.wg.Done()
|
|
|
|
|
2016-01-14 08:41:46 +03:00
|
|
|
pendingMsgs := list.New()
|
|
|
|
for {
|
2017-02-02 04:01:33 +03:00
|
|
|
// Before add a queue'd message our pending message queue,
|
|
|
|
// we'll first try to aggressively empty out our pending list of
|
|
|
|
// messaging.
|
|
|
|
for {
|
|
|
|
// Examine the front of the queue. If this message is
|
|
|
|
// nil, then we've emptied out the queue and can accept
|
|
|
|
// new messages from outside sub-systems.
|
|
|
|
elem := pendingMsgs.Front()
|
|
|
|
if elem == nil {
|
|
|
|
break
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
2017-02-02 04:01:33 +03:00
|
|
|
|
|
|
|
select {
|
|
|
|
case p.sendQueue <- elem.Value.(outgoinMsg):
|
|
|
|
pendingMsgs.Remove(elem)
|
|
|
|
case <-p.quit:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
break
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
2017-02-02 04:01:33 +03:00
|
|
|
}
|
2016-01-14 08:41:46 +03:00
|
|
|
|
2017-02-02 04:01:33 +03:00
|
|
|
// If there weren't any messages to send, or the writehandler
|
|
|
|
// is still blocked, then we'll accept a new message into the
|
|
|
|
// queue from outside sub-systems.
|
|
|
|
select {
|
2016-01-14 08:41:46 +03:00
|
|
|
case <-p.quit:
|
2017-02-02 04:01:33 +03:00
|
|
|
return
|
|
|
|
case msg := <-p.outgoingQueue:
|
|
|
|
pendingMsgs.PushBack(msg)
|
2016-01-14 08:41:46 +03:00
|
|
|
}
|
|
|
|
|
2017-02-02 04:01:33 +03:00
|
|
|
}
|
2015-12-21 00:16:38 +03:00
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-11-11 04:15:25 +03:00
|
|
|
// pingHandler is responsible for periodically sending ping messages to the
|
|
|
|
// remote peer in order to keep the connection alive and/or determine if the
|
|
|
|
// connection is still active.
|
|
|
|
//
|
|
|
|
// NOTE: This method MUST be run as a goroutine.
|
|
|
|
func (p *peer) pingHandler() {
|
|
|
|
pingTicker := time.NewTicker(pingInterval)
|
|
|
|
defer pingTicker.Stop()
|
|
|
|
|
|
|
|
var pingBuf [8]byte
|
|
|
|
|
|
|
|
out:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-pingTicker.C:
|
|
|
|
// Fill the ping buffer with fresh randomness. If we're
|
|
|
|
// unable to read enough bytes, then we simply defer
|
|
|
|
// sending the ping to the next interval.
|
|
|
|
if _, err := rand.Read(pingBuf[:]); err != nil {
|
|
|
|
peerLog.Errorf("unable to send ping to %v: %v", p,
|
|
|
|
err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the bytes read into a uint64, and queue the
|
|
|
|
// message for sending.
|
|
|
|
nonce := binary.BigEndian.Uint64(pingBuf[:])
|
|
|
|
p.queueMsg(lnwire.NewPing(nonce), nil)
|
|
|
|
case <-p.quit:
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p.wg.Done()
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:55 +03:00
|
|
|
// PingTime returns the estimated ping time to the peer in microseconds.
|
|
|
|
func (p *peer) PingTime() int64 {
|
|
|
|
return atomic.LoadInt64(&p.pingTime)
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// queueMsg queues a new lnwire.Message to be eventually sent out on the
|
|
|
|
// wire.
|
|
|
|
func (p *peer) queueMsg(msg lnwire.Message, doneChan chan struct{}) {
|
2016-12-20 04:00:18 +03:00
|
|
|
select {
|
|
|
|
case p.outgoingQueue <- outgoinMsg{msg, doneChan}:
|
|
|
|
case <-p.quit:
|
|
|
|
return
|
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
|
|
|
|
2016-11-11 04:15:25 +03:00
|
|
|
// ChannelSnapshots returns a slice of channel snapshots detailing all
|
|
|
|
// currently active channels maintained with the remote peer.
|
2016-06-23 08:22:06 +03:00
|
|
|
func (p *peer) ChannelSnapshots() []*channeldb.ChannelSnapshot {
|
|
|
|
resp := make(chan []*channeldb.ChannelSnapshot, 1)
|
|
|
|
p.chanSnapshotReqs <- &chanSnapshotReq{resp}
|
|
|
|
return <-resp
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// channelManager is goroutine dedicated to handling all requests/signals
|
|
|
|
// pertaining to the opening, cooperative closing, and force closing of all
|
|
|
|
// channels maintained with the remote peer.
|
|
|
|
//
|
|
|
|
// NOTE: This method MUST be run as a goroutine.
|
|
|
|
func (p *peer) channelManager() {
|
|
|
|
out:
|
|
|
|
for {
|
|
|
|
select {
|
2016-06-23 08:22:06 +03:00
|
|
|
case req := <-p.chanSnapshotReqs:
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.RLock()
|
2016-06-23 08:22:06 +03:00
|
|
|
snapshots := make([]*channeldb.ChannelSnapshot, 0, len(p.activeChannels))
|
|
|
|
for _, activeChan := range p.activeChannels {
|
|
|
|
snapshot := activeChan.StateSnapshot()
|
|
|
|
snapshots = append(snapshots, snapshot)
|
|
|
|
}
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.RUnlock()
|
2016-06-23 08:22:06 +03:00
|
|
|
req.resp <- snapshots
|
2016-07-14 02:40:01 +03:00
|
|
|
|
2017-01-24 02:33:46 +03:00
|
|
|
case newChanReq := <-p.newChannels:
|
|
|
|
chanPoint := *newChanReq.channel.ChannelPoint()
|
2016-11-18 05:43:33 +03:00
|
|
|
|
|
|
|
p.activeChanMtx.Lock()
|
2017-01-24 02:33:46 +03:00
|
|
|
p.activeChannels[chanPoint] = newChanReq.channel
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.Unlock()
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
peerLog.Infof("New channel active ChannelPoint(%v) "+
|
|
|
|
"with peerId(%v)", chanPoint, p.id)
|
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
// Now that the channel is open, notify the Htlc
|
|
|
|
// Switch of a new active link.
|
2017-01-24 02:33:46 +03:00
|
|
|
chanSnapShot := newChanReq.channel.StateSnapshot()
|
2016-07-22 02:53:07 +03:00
|
|
|
downstreamLink := make(chan *htlcPacket, 10)
|
2016-07-13 03:38:09 +03:00
|
|
|
plexChan := p.server.htlcSwitch.RegisterLink(p,
|
|
|
|
chanSnapShot, downstreamLink)
|
2016-07-10 02:41:06 +03:00
|
|
|
|
2016-07-13 03:38:09 +03:00
|
|
|
// With the channel registered to the HtlcSwitch spawn
|
|
|
|
// a goroutine to handle commitment updates for this
|
|
|
|
// new channel.
|
2016-07-22 02:53:07 +03:00
|
|
|
upstreamLink := make(chan lnwire.Message, 10)
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Lock()
|
2016-07-10 02:41:06 +03:00
|
|
|
p.htlcManagers[chanPoint] = upstreamLink
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.Unlock()
|
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
p.wg.Add(1)
|
2017-01-24 02:33:46 +03:00
|
|
|
go p.htlcManager(newChanReq.channel, plexChan, downstreamLink, upstreamLink)
|
|
|
|
|
|
|
|
close(newChanReq.done)
|
2016-07-14 02:40:01 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
case req := <-p.localCloseChanReqs:
|
|
|
|
p.handleLocalClose(req)
|
2016-07-14 02:40:01 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
case req := <-p.remoteCloseChanReqs:
|
|
|
|
p.handleRemoteClose(req)
|
2016-07-14 02:40:01 +03:00
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
case <-p.quit:
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p.wg.Done()
|
|
|
|
}
|
|
|
|
|
2016-09-12 22:42:26 +03:00
|
|
|
// executeCooperativeClose executes the initial phase of a user-executed
|
|
|
|
// cooperative channel close. The channel state machine is transitioned to the
|
|
|
|
// closing phase, then our half of the closing witness is sent over to the
|
|
|
|
// remote peer.
|
2017-01-06 00:56:27 +03:00
|
|
|
func (p *peer) executeCooperativeClose(channel *lnwallet.LightningChannel) (*chainhash.Hash, error) {
|
2016-06-21 22:32:32 +03:00
|
|
|
// Shift the channel state machine into a 'closing' state. This
|
|
|
|
// generates a signature for the closing tx, as well as a txid of the
|
|
|
|
// closing tx itself, allowing us to watch the network to determine
|
2016-09-12 22:42:26 +03:00
|
|
|
// when the remote node broadcasts the fully signed closing
|
|
|
|
// transaction.
|
2016-06-21 22:32:32 +03:00
|
|
|
sig, txid, err := channel.InitCooperativeClose()
|
|
|
|
if err != nil {
|
2016-09-12 22:42:26 +03:00
|
|
|
return nil, err
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
2016-09-12 22:42:26 +03:00
|
|
|
|
|
|
|
chanPoint := channel.ChannelPoint()
|
2016-06-21 22:32:32 +03:00
|
|
|
peerLog.Infof("Executing cooperative closure of "+
|
2016-09-12 22:42:26 +03:00
|
|
|
"ChanPoint(%v) with peerID(%v), txid=%v", chanPoint, p.id, txid)
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-09-12 22:42:26 +03:00
|
|
|
// With our signature for the close tx generated, send the signature to
|
|
|
|
// the remote peer instructing it to close this particular channel
|
2016-06-21 22:32:32 +03:00
|
|
|
// point.
|
|
|
|
// TODO(roasbeef): remove encoding redundancy
|
|
|
|
closeSig, err := btcec.ParseSignature(sig, btcec.S256())
|
|
|
|
if err != nil {
|
2016-09-12 22:42:26 +03:00
|
|
|
return nil, err
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
closeReq := lnwire.NewCloseRequest(*chanPoint, closeSig)
|
2016-06-21 22:32:32 +03:00
|
|
|
p.queueMsg(closeReq, nil)
|
|
|
|
|
2016-09-12 22:42:26 +03:00
|
|
|
return txid, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleLocalClose kicks-off the workflow to execute a cooperative or forced
|
2017-01-13 08:01:50 +03:00
|
|
|
// unilateral closure of the channel initiated by a local subsystem.
|
2016-12-15 05:11:31 +03:00
|
|
|
// TODO(roasbeef): if no more active channels with peer call Remove on connMgr
|
|
|
|
// with peerID
|
2016-09-12 22:42:26 +03:00
|
|
|
func (p *peer) handleLocalClose(req *closeLinkReq) {
|
|
|
|
var (
|
|
|
|
err error
|
2017-01-06 00:56:27 +03:00
|
|
|
closingTxid *chainhash.Hash
|
2016-09-12 22:42:26 +03:00
|
|
|
)
|
|
|
|
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.RLock()
|
2016-09-12 22:42:26 +03:00
|
|
|
channel := p.activeChannels[*req.chanPoint]
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.RUnlock()
|
2016-09-12 22:42:26 +03:00
|
|
|
|
2016-11-29 05:44:14 +03:00
|
|
|
switch req.CloseType {
|
|
|
|
// A type of CloseRegular indicates that the user has opted to close
|
|
|
|
// out this channel on-chian, so we execute the cooperative channel
|
2017-02-03 04:05:25 +03:00
|
|
|
// closure workflow.
|
2016-11-29 05:44:14 +03:00
|
|
|
case CloseRegular:
|
2016-09-12 22:42:26 +03:00
|
|
|
closingTxid, err = p.executeCooperativeClose(channel)
|
|
|
|
peerLog.Infof("Attempting cooperative close of "+
|
|
|
|
"ChannelPoint(%v) with txid: %v", req.chanPoint,
|
|
|
|
closingTxid)
|
2016-11-29 05:44:14 +03:00
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// A type of CloseBreach indicates that the counterparty has breached
|
2017-02-03 04:05:25 +03:00
|
|
|
// the channel therefore we need to clean up our local state.
|
2016-11-29 05:44:14 +03:00
|
|
|
case CloseBreach:
|
|
|
|
peerLog.Infof("ChannelPoint(%v) has been breached, wiping "+
|
|
|
|
"channel", req.chanPoint)
|
|
|
|
if err := wipeChannel(p, channel); err != nil {
|
|
|
|
peerLog.Infof("Unable to wipe channel after detected "+
|
|
|
|
"breach: %v", err)
|
|
|
|
req.err <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
2016-09-12 22:42:26 +03:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
req.err <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-18 05:43:33 +03:00
|
|
|
// Update the caller with a new event detailing the current pending
|
|
|
|
// state of this request.
|
2016-08-31 02:52:53 +03:00
|
|
|
req.updates <- &lnrpc.CloseStatusUpdate{
|
|
|
|
Update: &lnrpc.CloseStatusUpdate_ClosePending{
|
|
|
|
ClosePending: &lnrpc.PendingUpdate{
|
2016-09-12 22:42:26 +03:00
|
|
|
Txid: closingTxid[:],
|
2016-08-31 02:52:53 +03:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// Finally, launch a goroutine which will request to be notified by the
|
|
|
|
// ChainNotifier once the closure transaction obtains a single
|
|
|
|
// confirmation.
|
|
|
|
go func() {
|
|
|
|
// TODO(roasbeef): add param for num needed confs
|
2016-09-12 22:42:26 +03:00
|
|
|
notifier := p.server.chainNotifier
|
|
|
|
confNtfn, err := notifier.RegisterConfirmationsNtfn(closingTxid, 1)
|
2016-08-31 02:52:53 +03:00
|
|
|
if err != nil {
|
|
|
|
req.err <- err
|
|
|
|
return
|
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
select {
|
|
|
|
case height, ok := <-confNtfn.Confirmed:
|
2016-11-29 05:44:14 +03:00
|
|
|
// In the case that the ChainNotifier is shutting down,
|
|
|
|
// all subscriber notification channels will be closed,
|
|
|
|
// generating a nil receive.
|
2016-06-21 22:32:32 +03:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// The channel has been closed, remove it from any
|
|
|
|
// active indexes, and the database state.
|
2017-02-21 09:06:16 +03:00
|
|
|
peerLog.Infof("ChannelPoint(%v) is now closed at "+
|
|
|
|
"height %v", req.chanPoint, height.BlockHeight)
|
2016-08-31 02:52:53 +03:00
|
|
|
if err := wipeChannel(p, channel); err != nil {
|
|
|
|
req.err <- err
|
|
|
|
return
|
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
case <-p.quit:
|
2016-07-08 01:30:55 +03:00
|
|
|
return
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// Respond to the local subsystem which requested the channel
|
2016-06-21 22:32:32 +03:00
|
|
|
// closure.
|
2016-08-31 02:52:53 +03:00
|
|
|
req.updates <- &lnrpc.CloseStatusUpdate{
|
|
|
|
Update: &lnrpc.CloseStatusUpdate_ChanClose{
|
|
|
|
ChanClose: &lnrpc.ChannelCloseUpdate{
|
2016-09-12 22:42:26 +03:00
|
|
|
ClosingTxid: closingTxid[:],
|
2016-08-31 02:52:53 +03:00
|
|
|
Success: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2016-11-29 06:43:57 +03:00
|
|
|
|
|
|
|
p.server.breachArbiter.settledContracts <- req.chanPoint
|
2016-06-21 22:32:32 +03:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleRemoteClose completes a request for cooperative channel closure
|
|
|
|
// initiated by the remote node.
|
|
|
|
func (p *peer) handleRemoteClose(req *lnwire.CloseRequest) {
|
|
|
|
chanPoint := req.ChannelPoint
|
|
|
|
key := wire.OutPoint{
|
|
|
|
Hash: chanPoint.Hash,
|
|
|
|
Index: chanPoint.Index,
|
|
|
|
}
|
2016-11-18 05:43:33 +03:00
|
|
|
|
|
|
|
p.activeChanMtx.RLock()
|
2017-02-08 03:47:59 +03:00
|
|
|
channel, ok := p.activeChannels[key]
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.RUnlock()
|
2017-02-08 03:47:59 +03:00
|
|
|
if !ok {
|
|
|
|
peerLog.Errorf("unable to close channel, ChannelPoint(%v) is "+
|
|
|
|
"unknown", key)
|
|
|
|
return
|
|
|
|
}
|
2016-06-21 22:32:32 +03:00
|
|
|
|
|
|
|
// Now that we have their signature for the closure transaction, we
|
|
|
|
// can assemble the final closure transaction, complete with our
|
|
|
|
// signature.
|
|
|
|
sig := req.RequesterCloseSig
|
|
|
|
closeSig := append(sig.Serialize(), byte(txscript.SigHashAll))
|
|
|
|
closeTx, err := channel.CompleteCooperativeClose(closeSig)
|
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to complete cooperative "+
|
|
|
|
"close for ChannelPoint(%v): %v",
|
|
|
|
chanPoint, err)
|
|
|
|
// TODO(roasbeef): send ErrorGeneric to other side
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-29 05:44:14 +03:00
|
|
|
peerLog.Infof("Broadcasting cooperative close tx: %v",
|
|
|
|
newLogClosure(func() string {
|
|
|
|
return spew.Sdump(closeTx)
|
|
|
|
}))
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// Finally, broadcast the closure transaction, to the network.
|
|
|
|
if err := p.server.lnwallet.PublishTransaction(closeTx); err != nil {
|
|
|
|
peerLog.Errorf("channel close tx from "+
|
|
|
|
"ChannelPoint(%v) rejected: %v",
|
|
|
|
chanPoint, err)
|
|
|
|
// TODO(roasbeef): send ErrorGeneric to other side
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): also wait for confs before removing state
|
|
|
|
peerLog.Infof("ChannelPoint(%v) is now "+
|
|
|
|
"closed", key)
|
2016-09-26 20:35:10 +03:00
|
|
|
if err := wipeChannel(p, channel); err != nil {
|
|
|
|
peerLog.Errorf("unable to wipe channel: %v", err)
|
|
|
|
}
|
2016-11-29 06:43:57 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
p.server.breachArbiter.settledContracts <- &req.ChannelPoint
|
2016-06-23 08:19:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// wipeChannel removes the passed channel from all indexes associated with the
|
|
|
|
// peer, and deletes the channel from the database.
|
2016-08-31 02:52:53 +03:00
|
|
|
func wipeChannel(p *peer, channel *lnwallet.LightningChannel) error {
|
2016-07-10 02:41:06 +03:00
|
|
|
chanID := channel.ChannelPoint()
|
2016-06-23 08:19:24 +03:00
|
|
|
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.Lock()
|
2016-07-10 02:41:06 +03:00
|
|
|
delete(p.activeChannels, *chanID)
|
2016-11-18 05:43:33 +03:00
|
|
|
p.activeChanMtx.Unlock()
|
2016-06-21 22:32:32 +03:00
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
// Instruct the Htlc Switch to close this link as the channel is no
|
|
|
|
// longer active.
|
2016-10-28 05:49:10 +03:00
|
|
|
p.server.htlcSwitch.UnregisterLink(p.addr.IdentityKey, chanID)
|
2016-11-18 05:43:33 +03:00
|
|
|
|
2016-11-29 05:44:14 +03:00
|
|
|
// Additionally, close up "down stream" link for the htlcManager which
|
|
|
|
// has been assigned to this channel. This servers the link between the
|
|
|
|
// htlcManager and the switch, signalling that the channel is no longer
|
|
|
|
// active.
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.RLock()
|
2016-11-29 05:44:14 +03:00
|
|
|
|
|
|
|
// If the channel can't be found in the map, then this channel has
|
|
|
|
// already been wiped.
|
2016-09-13 05:04:08 +03:00
|
|
|
htlcWireLink, ok := p.htlcManagers[*chanID]
|
|
|
|
if !ok {
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.RUnlock()
|
2016-09-13 05:04:08 +03:00
|
|
|
return nil
|
|
|
|
}
|
2016-11-29 05:44:14 +03:00
|
|
|
|
|
|
|
close(htlcWireLink)
|
|
|
|
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.RUnlock()
|
2016-09-13 05:04:08 +03:00
|
|
|
|
2016-11-29 05:44:14 +03:00
|
|
|
// Next, we remove the htlcManager from our internal map as the
|
|
|
|
// goroutine should have exited gracefully due to the channel closure
|
|
|
|
// above.
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.RLock()
|
2016-07-10 02:41:06 +03:00
|
|
|
delete(p.htlcManagers, *chanID)
|
2016-11-18 05:43:33 +03:00
|
|
|
p.htlcManMtx.RUnlock()
|
|
|
|
|
2016-11-29 05:44:14 +03:00
|
|
|
// Finally, we purge the channel's state from the database, leaving a
|
|
|
|
// small summary for historical records.
|
2016-06-23 08:19:24 +03:00
|
|
|
if err := channel.DeleteState(); err != nil {
|
|
|
|
peerLog.Errorf("Unable to delete ChannelPoint(%v) "+
|
2016-11-29 06:43:57 +03:00
|
|
|
"from db: %v", chanID, err)
|
2016-08-31 02:52:53 +03:00
|
|
|
return err
|
2016-06-23 08:19:24 +03:00
|
|
|
}
|
2016-08-31 02:52:53 +03:00
|
|
|
|
|
|
|
return nil
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
// pendingPayment represents a pending HTLC which has yet to be settled by the
|
|
|
|
// upstream peer. A pending payment encapsulates the initial HTLC add request
|
|
|
|
// additionally coupling the index of the HTLC within the log, and an error
|
|
|
|
// channel to signal the payment requester once the payment has been fully
|
|
|
|
// fufilled.
|
|
|
|
type pendingPayment struct {
|
2017-02-21 05:10:05 +03:00
|
|
|
htlc *lnwire.UpdateAddHTLC
|
|
|
|
index uint64
|
2016-07-17 04:20:13 +03:00
|
|
|
|
2017-02-21 10:57:43 +03:00
|
|
|
preImage chan [32]byte
|
|
|
|
err chan error
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
|
|
|
|
2016-07-13 03:45:29 +03:00
|
|
|
// commitmentState is the volatile+persistent state of an active channel's
|
|
|
|
// commitment update state-machine. This struct is used by htlcManager's to
|
|
|
|
// save meta-state required for proper functioning.
|
|
|
|
type commitmentState struct {
|
2016-07-17 04:20:13 +03:00
|
|
|
// htlcsToSettle is a list of preimages which allow us to settle one or
|
2017-01-13 08:01:50 +03:00
|
|
|
// many of the pending HTLCs we've received from the upstream peer.
|
2017-02-21 05:10:05 +03:00
|
|
|
htlcsToSettle map[uint64]*channeldb.Invoice
|
2016-07-17 04:20:13 +03:00
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// htlcsToCancel is a set of HTLCs identified by their log index which
|
2017-01-08 07:23:06 +03:00
|
|
|
// are to be cancelled upon the next state transition.
|
2017-02-21 05:10:05 +03:00
|
|
|
htlcsToCancel map[uint64]lnwire.FailCode
|
2017-01-08 07:23:06 +03:00
|
|
|
|
|
|
|
// cancelReasons stores the reason why a particular HTLC was cancelled.
|
|
|
|
// The index of the HTLC within the log is mapped to the cancellation
|
|
|
|
// reason. This value is used to thread the proper error through to the
|
2017-01-13 08:01:50 +03:00
|
|
|
// htlcSwitch, or subsystem that initiated the HTLC.
|
2017-02-21 05:10:05 +03:00
|
|
|
cancelReasons map[uint64]lnwire.FailCode
|
2017-01-08 07:23:06 +03:00
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
pendingBatch []*pendingPayment
|
2016-07-17 04:20:13 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
// pendingUpdate is a bool which indicates if we have a pending state
|
|
|
|
// update outstanding whch has not yet been ACK'd.
|
|
|
|
pendingUpdate bool
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// clearedHTCLs is a map of outgoing HTLCs we've committed to in our
|
2016-07-17 04:20:13 +03:00
|
|
|
// chain which have not yet been settled by the upstream peer.
|
2017-02-21 05:10:05 +03:00
|
|
|
clearedHTCLs map[uint64]*pendingPayment
|
2016-07-22 03:10:30 +03:00
|
|
|
|
|
|
|
// logCommitTimer is a timer which is sent upon if we go an interval
|
|
|
|
// without receiving/sending a commitment update. It's role is to
|
|
|
|
// ensure both chains converge to identical state in a timely manner.
|
|
|
|
// TODO(roasbeef): timer should be >> then RTT
|
2017-02-21 05:10:05 +03:00
|
|
|
logCommitTimer *time.Timer
|
|
|
|
logCommitTick <-chan time.Time
|
2016-07-22 03:10:30 +03:00
|
|
|
|
|
|
|
// switchChan is a channel used to send packets to the htlc switch for
|
2016-10-26 15:25:42 +03:00
|
|
|
// forwarding.
|
2016-07-22 03:10:30 +03:00
|
|
|
switchChan chan<- *htlcPacket
|
|
|
|
|
2016-09-21 03:15:26 +03:00
|
|
|
// sphinx is an instance of the Sphinx onion Router for this node. The
|
2017-01-08 07:23:06 +03:00
|
|
|
// router will be used to process all incoming Sphinx packets embedded
|
2016-09-21 03:15:26 +03:00
|
|
|
// within HTLC add messages.
|
|
|
|
sphinx *sphinx.Router
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// pendingCircuits tracks the remote log index of the incoming HTLCs,
|
2016-09-22 05:41:26 +03:00
|
|
|
// mapped to the processed Sphinx packet contained within the HTLC.
|
|
|
|
// This map is used as a staging area between when an HTLC is added to
|
|
|
|
// the log, and when it's locked into the commitment state of both
|
|
|
|
// chains. Once locked in, the processed packet is sent to the switch
|
|
|
|
// along with the HTLC to forward the packet to the next hop.
|
2017-02-21 05:10:05 +03:00
|
|
|
pendingCircuits map[uint64]*sphinx.ProcessedPacket
|
2016-09-22 05:41:26 +03:00
|
|
|
|
2016-07-13 03:45:29 +03:00
|
|
|
channel *lnwallet.LightningChannel
|
|
|
|
chanPoint *wire.OutPoint
|
|
|
|
}
|
2016-07-10 02:41:06 +03:00
|
|
|
|
2016-07-13 03:45:29 +03:00
|
|
|
// htlcManager is the primary goroutine which drives a channel's commitment
|
|
|
|
// update state-machine in response to messages received via several channels.
|
|
|
|
// The htlcManager reads messages from the upstream (remote) peer, and also
|
|
|
|
// from several possible downstream channels managed by the htlcSwitch. In the
|
|
|
|
// event that an htlc needs to be forwarded, then send-only htlcPlex chan is
|
|
|
|
// used which sends htlc packets to the switch for forwarding. Additionally,
|
2017-01-13 08:01:50 +03:00
|
|
|
// the htlcManager handles acting upon all timeouts for any active HTLCs,
|
2016-07-13 03:45:29 +03:00
|
|
|
// manages the channel's revocation window, and also the htlc trickle
|
|
|
|
// queue+timer for this active channels.
|
|
|
|
func (p *peer) htlcManager(channel *lnwallet.LightningChannel,
|
2016-07-17 04:20:13 +03:00
|
|
|
htlcPlex chan<- *htlcPacket, downstreamLink <-chan *htlcPacket,
|
2016-07-13 03:45:29 +03:00
|
|
|
upstreamLink <-chan lnwire.Message) {
|
|
|
|
|
|
|
|
chanStats := channel.StateSnapshot()
|
2016-07-22 03:10:30 +03:00
|
|
|
peerLog.Infof("HTLC manager for ChannelPoint(%v) started, "+
|
2016-07-13 03:45:29 +03:00
|
|
|
"our_balance=%v, their_balance=%v, chain_height=%v",
|
|
|
|
channel.ChannelPoint(), chanStats.LocalBalance,
|
|
|
|
chanStats.RemoteBalance, chanStats.NumUpdates)
|
|
|
|
|
|
|
|
// A new session for this active channel has just started, therefore we
|
|
|
|
// need to send our initial revocation window to the remote peer.
|
|
|
|
for i := 0; i < lnwallet.InitialRevocationWindow; i++ {
|
|
|
|
rev, err := channel.ExtendRevocationWindow()
|
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to expand revocation window: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
p.queueMsg(rev, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
state := &commitmentState{
|
2016-09-22 05:41:26 +03:00
|
|
|
channel: channel,
|
|
|
|
chanPoint: channel.ChannelPoint(),
|
2017-02-21 05:10:05 +03:00
|
|
|
clearedHTCLs: make(map[uint64]*pendingPayment),
|
|
|
|
htlcsToSettle: make(map[uint64]*channeldb.Invoice),
|
|
|
|
htlcsToCancel: make(map[uint64]lnwire.FailCode),
|
|
|
|
cancelReasons: make(map[uint64]lnwire.FailCode),
|
|
|
|
pendingCircuits: make(map[uint64]*sphinx.ProcessedPacket),
|
2016-09-22 05:41:26 +03:00
|
|
|
sphinx: p.server.sphinx,
|
|
|
|
switchChan: htlcPlex,
|
2017-02-21 05:10:05 +03:00
|
|
|
logCommitTimer: time.NewTimer(300 * time.Millisecond),
|
2016-07-13 03:45:29 +03:00
|
|
|
}
|
2016-07-22 03:10:30 +03:00
|
|
|
|
2016-09-21 03:15:26 +03:00
|
|
|
// TODO(roasbeef): check to see if able to settle any currently pending
|
2017-01-13 08:01:50 +03:00
|
|
|
// HTLCs
|
2017-02-03 04:05:25 +03:00
|
|
|
// * also need signals when new invoices are added by the
|
|
|
|
// invoiceRegistry
|
2016-09-21 03:15:26 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
batchTimer := time.NewTicker(50 * time.Millisecond)
|
|
|
|
defer batchTimer.Stop()
|
2016-06-21 22:32:32 +03:00
|
|
|
out:
|
|
|
|
for {
|
|
|
|
select {
|
2016-09-12 22:42:26 +03:00
|
|
|
case <-channel.UnilateralCloseSignal:
|
2016-11-29 06:43:57 +03:00
|
|
|
// TODO(roasbeef): need to send HTLC outputs to nursery
|
2016-09-12 22:42:26 +03:00
|
|
|
peerLog.Warnf("Remote peer has closed ChannelPoint(%v) on-chain",
|
|
|
|
state.chanPoint)
|
|
|
|
if err := wipeChannel(p, channel); err != nil {
|
2016-09-26 20:35:10 +03:00
|
|
|
peerLog.Errorf("unable to wipe channel %v", err)
|
2016-09-12 22:42:26 +03:00
|
|
|
}
|
2016-09-26 20:35:10 +03:00
|
|
|
|
2016-11-29 06:43:57 +03:00
|
|
|
p.server.breachArbiter.settledContracts <- state.chanPoint
|
|
|
|
|
2016-09-12 22:42:26 +03:00
|
|
|
break out
|
2017-02-21 05:10:05 +03:00
|
|
|
|
2016-09-12 22:42:26 +03:00
|
|
|
case <-channel.ForceCloseSignal:
|
2017-02-03 04:05:25 +03:00
|
|
|
// TODO(roasbeef): path never taken now that server
|
|
|
|
// force closes's directly?
|
2016-09-12 22:42:26 +03:00
|
|
|
peerLog.Warnf("ChannelPoint(%v) has been force "+
|
|
|
|
"closed, disconnecting from peerID(%x)",
|
|
|
|
state.chanPoint, p.id)
|
|
|
|
break out
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
case <-state.logCommitTick:
|
2016-07-22 03:10:30 +03:00
|
|
|
// If we haven't sent or received a new commitment
|
|
|
|
// update in some time, check to see if we have any
|
|
|
|
// pending updates we need to commit. If so, then send
|
2016-09-26 20:35:10 +03:00
|
|
|
// an update incrementing the unacked counter is
|
2016-10-30 17:54:59 +03:00
|
|
|
// successfully.
|
2016-09-26 20:39:47 +03:00
|
|
|
if !state.channel.PendingUpdates() &&
|
|
|
|
len(state.htlcsToSettle) == 0 {
|
2016-07-22 03:10:30 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
if err := p.updateCommitTx(state, false); err != nil {
|
|
|
|
peerLog.Errorf("unable to update commitment: %v",
|
|
|
|
err)
|
2016-07-22 03:10:30 +03:00
|
|
|
p.Disconnect()
|
|
|
|
break out
|
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
case <-batchTimer.C:
|
2016-07-22 03:10:30 +03:00
|
|
|
// If the current batch is empty, then we have no work
|
|
|
|
// here.
|
|
|
|
if len(state.pendingBatch) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, attempt to extend the remote commitment
|
|
|
|
// chain including all the currently pending entries.
|
2016-11-11 04:15:25 +03:00
|
|
|
// If the send was unsuccessful, then abandon the
|
2016-07-22 03:10:30 +03:00
|
|
|
// update, waiting for the revocation window to open
|
|
|
|
// up.
|
2017-02-21 05:10:05 +03:00
|
|
|
if err := p.updateCommitTx(state, false); err != nil {
|
2016-07-22 03:10:30 +03:00
|
|
|
peerLog.Errorf("unable to update "+
|
|
|
|
"commitment: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
case pkt := <-downstreamLink:
|
|
|
|
p.handleDownStreamPkt(state, pkt)
|
2017-02-21 05:10:05 +03:00
|
|
|
|
2016-07-10 02:41:06 +03:00
|
|
|
case msg, ok := <-upstreamLink:
|
|
|
|
// If the upstream message link is closed, this signals
|
|
|
|
// that the channel itself is being closed, therefore
|
|
|
|
// we exit.
|
|
|
|
if !ok {
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
p.handleUpstreamMsg(state, msg)
|
2016-06-21 22:32:32 +03:00
|
|
|
case <-p.quit:
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p.wg.Done()
|
2016-07-14 02:40:01 +03:00
|
|
|
peerLog.Tracef("htlcManager for peer %v done", p)
|
2016-06-21 22:32:32 +03:00
|
|
|
}
|
|
|
|
|
2017-02-16 15:39:38 +03:00
|
|
|
// handleInitMsg handles the incoming init message which contains global and
|
|
|
|
// local features vectors. If feature vectors are incompatible then disconnect.
|
|
|
|
func (p *peer) handleInitMsg(msg *lnwire.Init) error {
|
|
|
|
localSharedFeatures, err := p.server.localFeatures.Compare(msg.LocalFeatures)
|
|
|
|
if err != nil {
|
2017-02-23 01:49:04 +03:00
|
|
|
err := errors.Errorf("can compare remote and local feature "+
|
2017-02-16 15:39:38 +03:00
|
|
|
"vectors: %v", err)
|
|
|
|
peerLog.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.localSharedFeatures = localSharedFeatures
|
|
|
|
|
|
|
|
globalSharedFeatures, err := p.server.globalFeatures.Compare(msg.GlobalFeatures)
|
|
|
|
if err != nil {
|
2017-02-23 01:49:04 +03:00
|
|
|
err := errors.Errorf("can compare remote and global feature "+
|
2017-02-16 15:39:38 +03:00
|
|
|
"vectors: %v", err)
|
|
|
|
peerLog.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.globalSharedFeatures = globalSharedFeatures
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// sendInitMsg sends init message to remote peer which represent our
|
|
|
|
// features local and global vectors.
|
|
|
|
func (p *peer) sendInitMsg() error {
|
|
|
|
msg := lnwire.NewInitMessage(
|
|
|
|
p.server.globalFeatures,
|
|
|
|
p.server.localFeatures,
|
|
|
|
)
|
|
|
|
|
|
|
|
p.queueMsg(msg, nil)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
// handleDownStreamPkt processes an HTLC packet sent from the downstream HTLC
|
|
|
|
// Switch. Possible messages sent by the switch include requests to forward new
|
2017-01-13 08:01:50 +03:00
|
|
|
// HTLCs, timeout previously cleared HTLCs, and finally to settle currently
|
|
|
|
// cleared HTLCs with the upstream peer.
|
2016-07-17 04:20:13 +03:00
|
|
|
func (p *peer) handleDownStreamPkt(state *commitmentState, pkt *htlcPacket) {
|
2016-09-22 05:41:26 +03:00
|
|
|
var isSettle bool
|
2016-07-17 04:20:13 +03:00
|
|
|
switch htlc := pkt.msg.(type) {
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateAddHTLC:
|
2016-07-17 04:20:13 +03:00
|
|
|
// A new payment has been initiated via the
|
|
|
|
// downstream channel, so we add the new HTLC
|
|
|
|
// to our local log, then update the commitment
|
|
|
|
// chains.
|
2017-02-21 05:10:05 +03:00
|
|
|
htlc.ChannelPoint = *state.chanPoint
|
2016-11-23 11:36:55 +03:00
|
|
|
index, err := state.channel.AddHTLC(htlc)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: possibly perform fallback/retry logic
|
|
|
|
// depending on type of error
|
|
|
|
// TODO: send a cancel message back to the htlcSwitch.
|
|
|
|
peerLog.Errorf("Adding HTLC rejected: %v", err)
|
|
|
|
pkt.err <- err
|
|
|
|
|
|
|
|
// Increase the available bandwidth of the link,
|
|
|
|
// previously it was decremented and because
|
|
|
|
// HTLC adding failed we should do the reverse
|
|
|
|
// operation.
|
|
|
|
htlcSwitch := p.server.htlcSwitch
|
2017-02-21 05:10:05 +03:00
|
|
|
htlcSwitch.UpdateLink(&htlc.ChannelPoint, pkt.amt)
|
2016-11-23 11:36:55 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
p.queueMsg(htlc, nil)
|
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
state.pendingBatch = append(state.pendingBatch, &pendingPayment{
|
2017-02-21 10:57:43 +03:00
|
|
|
htlc: htlc,
|
|
|
|
index: index,
|
|
|
|
preImage: pkt.preImage,
|
|
|
|
err: pkt.err,
|
2016-07-22 03:10:30 +03:00
|
|
|
})
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateFufillHTLC:
|
|
|
|
// An HTLC we forward to the switch has just settled somewhere
|
2017-01-08 07:23:06 +03:00
|
|
|
// upstream. Therefore we settle the HTLC within the our local
|
|
|
|
// state machine.
|
2017-02-21 05:10:05 +03:00
|
|
|
pre := htlc.PaymentPreimage
|
2016-09-22 05:41:26 +03:00
|
|
|
logIndex, err := state.channel.SettleHTLC(pre)
|
|
|
|
if err != nil {
|
|
|
|
// TODO(roasbeef): broadcast on-chain
|
|
|
|
peerLog.Errorf("settle for incoming HTLC rejected: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
2016-07-22 03:10:30 +03:00
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// With the HTLC settled, we'll need to populate the wire
|
|
|
|
// message to target the specific channel and HTLC to be
|
|
|
|
// cancelled.
|
2017-02-21 05:10:05 +03:00
|
|
|
htlc.ChannelPoint = *state.chanPoint
|
|
|
|
htlc.ID = logIndex
|
2016-09-22 05:41:26 +03:00
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// Then we send the HTLC settle message to the connected peer
|
|
|
|
// so we can continue the propagation of the settle message.
|
|
|
|
p.queueMsg(htlc, nil)
|
|
|
|
isSettle = true
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateFailHTLC:
|
2017-01-08 07:23:06 +03:00
|
|
|
// An HTLC cancellation has been triggered somewhere upstream,
|
|
|
|
// we'll remove then HTLC from our local state machine.
|
2017-02-21 05:10:05 +03:00
|
|
|
logIndex, err := state.channel.FailHTLC(pkt.payHash)
|
2017-01-08 07:23:06 +03:00
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to cancel HTLC: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// With the HTLC removed, we'll need to populate the wire
|
|
|
|
// message to target the specific channel and HTLC to be
|
|
|
|
// cancelled. The "Reason" field will have already been set
|
|
|
|
// within the switch.
|
2017-02-21 05:10:05 +03:00
|
|
|
htlc.ChannelPoint = *state.chanPoint
|
|
|
|
htlc.ID = logIndex
|
2017-01-08 07:23:06 +03:00
|
|
|
|
|
|
|
// Finally, we send the HTLC message to the peer which
|
|
|
|
// initially created the HTLC.
|
2016-09-22 05:41:26 +03:00
|
|
|
p.queueMsg(htlc, nil)
|
|
|
|
isSettle = true
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
// If this newly added update exceeds the min batch size for adds, or
|
2016-09-22 05:41:26 +03:00
|
|
|
// this is a settle request, then initiate an update.
|
2017-01-13 08:01:50 +03:00
|
|
|
// TODO(roasbeef): enforce max HTLCs in flight limit
|
2016-09-22 05:41:26 +03:00
|
|
|
if len(state.pendingBatch) >= 10 || isSettle {
|
2017-02-21 05:10:05 +03:00
|
|
|
if err := p.updateCommitTx(state, false); err != nil {
|
2016-09-22 05:41:26 +03:00
|
|
|
peerLog.Errorf("unable to update "+
|
|
|
|
"commitment: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleUpstreamMsg processes wire messages related to commitment state
|
|
|
|
// updates from the upstream peer. The upstream peer is the peer whom we have a
|
|
|
|
// direct channel with, updating our respective commitment chains.
|
|
|
|
func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) {
|
|
|
|
switch htlcPkt := msg.(type) {
|
|
|
|
// TODO(roasbeef): timeouts
|
2016-07-22 03:10:30 +03:00
|
|
|
// * fail if can't parse sphinx mix-header
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateAddHTLC:
|
2016-09-21 03:15:26 +03:00
|
|
|
// Before adding the new HTLC to the state machine, parse the
|
|
|
|
// onion object in order to obtain the routing information.
|
2017-02-21 05:10:05 +03:00
|
|
|
blobReader := bytes.NewReader(htlcPkt.OnionBlob[:])
|
2016-09-21 03:15:26 +03:00
|
|
|
onionPkt := &sphinx.OnionPacket{}
|
|
|
|
if err := onionPkt.Decode(blobReader); err != nil {
|
|
|
|
peerLog.Errorf("unable to decode onion pkt: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
2016-10-28 06:40:08 +03:00
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// We just received an add request from an upstream peer, so we
|
|
|
|
// add it to our state machine, then add the HTLC to our
|
2017-01-13 08:01:50 +03:00
|
|
|
// "settle" list in the event that we know the preimage
|
2017-01-08 07:23:06 +03:00
|
|
|
index, err := state.channel.ReceiveHTLC(htlcPkt)
|
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("Receiving HTLC rejected: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): perform sanity checks on per-hop payload
|
|
|
|
// * time-lock is sane, fee, chain, etc
|
|
|
|
|
2016-10-28 06:40:08 +03:00
|
|
|
// Attempt to process the Sphinx packet. We include the payment
|
|
|
|
// hash of the HTLC as it's authenticated within the Sphinx
|
|
|
|
// packet itself as associated data in order to thwart attempts
|
|
|
|
// a replay attacks. In the case of a replay, an attacker is
|
|
|
|
// *forced* to use the same payment hash twice, thereby losing
|
|
|
|
// their money entirely.
|
2017-02-21 05:10:05 +03:00
|
|
|
rHash := htlcPkt.PaymentHash[:]
|
2016-10-28 06:40:08 +03:00
|
|
|
sphinxPacket, err := state.sphinx.ProcessOnionPacket(onionPkt, rHash)
|
2016-09-21 03:15:26 +03:00
|
|
|
if err != nil {
|
2017-01-08 07:23:06 +03:00
|
|
|
// If we're unable to parse the Sphinx packet, then
|
|
|
|
// we'll cancel the HTLC after the current commitment
|
|
|
|
// transition.
|
2016-09-21 03:15:26 +03:00
|
|
|
peerLog.Errorf("unable to process onion pkt: %v", err)
|
2017-01-08 07:23:06 +03:00
|
|
|
state.htlcsToCancel[index] = lnwire.SphinxParseError
|
2016-11-23 11:36:55 +03:00
|
|
|
return
|
|
|
|
}
|
2016-07-17 04:20:13 +03:00
|
|
|
|
2016-09-22 05:41:26 +03:00
|
|
|
switch sphinxPacket.Action {
|
2016-09-21 03:15:26 +03:00
|
|
|
// We're the designated payment destination. Therefore we
|
2016-09-22 05:41:26 +03:00
|
|
|
// attempt to see if we have an invoice locally which'll allow
|
|
|
|
// us to settle this HTLC.
|
2016-09-21 03:15:26 +03:00
|
|
|
case sphinx.ExitNode:
|
2017-02-21 05:10:05 +03:00
|
|
|
rHash := htlcPkt.PaymentHash
|
2016-09-21 03:15:26 +03:00
|
|
|
invoice, err := p.server.invoices.LookupInvoice(rHash)
|
|
|
|
if err != nil {
|
2017-01-08 07:23:06 +03:00
|
|
|
// If we're the exit node, but don't recognize
|
|
|
|
// the payment hash, then we'll fail the HTLC
|
|
|
|
// on the next state transition.
|
|
|
|
peerLog.Errorf("unable to settle HTLC, "+
|
|
|
|
"payment hash (%x) unrecognized", rHash[:])
|
|
|
|
state.htlcsToCancel[index] = lnwire.UnknownPaymentHash
|
2016-09-21 03:15:26 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// If we're not currently in debug mode, and the
|
|
|
|
// extended HTLC doesn't meet the value requested, then
|
|
|
|
// we'll fail the HTLC.
|
|
|
|
if !cfg.DebugHTLC && htlcPkt.Amount < invoice.Terms.Value {
|
|
|
|
peerLog.Errorf("rejecting HTLC due to incorrect "+
|
|
|
|
"amount: expected %v, received %v",
|
|
|
|
invoice.Terms.Value, htlcPkt.Amount)
|
|
|
|
state.htlcsToCancel[index] = lnwire.IncorrectValue
|
|
|
|
} else {
|
|
|
|
// Otherwise, everything is in order and we'll
|
|
|
|
// settle the HTLC after the current state
|
|
|
|
// transition.
|
|
|
|
state.htlcsToSettle[index] = invoice
|
|
|
|
}
|
2016-09-22 05:41:26 +03:00
|
|
|
|
|
|
|
// There are additional hops left within this route, so we
|
|
|
|
// track the next hop according to the index of this HTLC
|
|
|
|
// within their log. When forwarding locked-in HLTC's to the
|
|
|
|
// switch, we'll attach the routing information so the switch
|
|
|
|
// can finalize the circuit.
|
2016-09-21 03:15:26 +03:00
|
|
|
case sphinx.MoreHops:
|
2016-09-22 05:41:26 +03:00
|
|
|
state.pendingCircuits[index] = sphinxPacket
|
2016-09-21 03:15:26 +03:00
|
|
|
default:
|
|
|
|
peerLog.Errorf("mal formed onion packet")
|
2017-01-08 07:23:06 +03:00
|
|
|
state.htlcsToCancel[index] = lnwire.SphinxParseError
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
case *lnwire.UpdateFufillHTLC:
|
|
|
|
pre := htlcPkt.PaymentPreimage
|
|
|
|
idx := htlcPkt.ID
|
2016-07-22 03:10:30 +03:00
|
|
|
if err := state.channel.ReceiveHTLCSettle(pre, idx); err != nil {
|
2016-07-17 04:20:13 +03:00
|
|
|
// TODO(roasbeef): broadcast on-chain
|
|
|
|
peerLog.Errorf("settle for outgoing HTLC rejected: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
2016-10-16 00:41:11 +03:00
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// TODO(roasbeef): add preimage to DB in order to swipe
|
2016-10-16 00:41:11 +03:00
|
|
|
// repeated r-values
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.UpdateFailHTLC:
|
|
|
|
idx := htlcPkt.ID
|
|
|
|
if err := state.channel.ReceiveFailHTLC(idx); err != nil {
|
2017-01-08 07:23:06 +03:00
|
|
|
peerLog.Errorf("unable to recv HTLC cancel: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
state.cancelReasons[idx] = lnwire.FailCode(htlcPkt.Reason[0])
|
2017-01-08 07:23:06 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
case *lnwire.CommitSig:
|
2016-07-17 04:20:13 +03:00
|
|
|
// We just received a new update to our local commitment chain,
|
|
|
|
// validate this new commitment, closing the link if invalid.
|
2017-02-21 05:10:05 +03:00
|
|
|
// TODO(roasbeef): redundant re-serialization
|
2016-07-17 04:20:13 +03:00
|
|
|
sig := htlcPkt.CommitSig.Serialize()
|
2017-02-21 05:10:05 +03:00
|
|
|
if err := state.channel.ReceiveNewCommitment(sig); err != nil {
|
2016-07-17 04:20:13 +03:00
|
|
|
peerLog.Errorf("unable to accept new commitment: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
// As we've just just accepted a new state, we'll now
|
|
|
|
// immediately send the remote peer a revocation for our prior
|
|
|
|
// state.
|
2016-07-17 04:20:13 +03:00
|
|
|
nextRevocation, err := state.channel.RevokeCurrentCommitment()
|
|
|
|
if err != nil {
|
2017-02-21 05:10:05 +03:00
|
|
|
peerLog.Errorf("unable to revoke commitment: %v", err)
|
2016-07-17 04:20:13 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
p.queueMsg(nextRevocation, nil)
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
// If we just initiated a state transition, and we were waiting
|
|
|
|
// for a reply from the remote peer, then we don't need to
|
|
|
|
// response with a subsequent CommitSig message. So we toggle
|
|
|
|
// the `pendingUpdate` bool, and set a timer to wake us up in
|
|
|
|
// the future to check if we have any updates we need to
|
|
|
|
// commit.
|
|
|
|
if state.pendingUpdate {
|
|
|
|
state.pendingUpdate = false
|
|
|
|
|
|
|
|
if !state.logCommitTimer.Stop() {
|
|
|
|
select {
|
|
|
|
case <-state.logCommitTimer.C:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state.logCommitTimer.Reset(300 * time.Millisecond)
|
|
|
|
state.logCommitTick = state.logCommitTimer.C
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, the remote party initiated the state transition,
|
|
|
|
// so we'll reply with a signature to provide them with their
|
|
|
|
// version of the latest commitment state.
|
|
|
|
if err := p.updateCommitTx(state, true); err != nil {
|
|
|
|
peerLog.Errorf("unable to update commitment: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
case *lnwire.RevokeAndAck:
|
2016-07-17 04:20:13 +03:00
|
|
|
// We've received a revocation from the remote chain, if valid,
|
|
|
|
// this moves the remote chain forward, and expands our
|
|
|
|
// revocation window.
|
|
|
|
htlcsToForward, err := state.channel.ReceiveRevocation(htlcPkt)
|
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to accept revocation: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// If any of the HTLCs eligible for forwarding are pending
|
2017-01-08 07:23:06 +03:00
|
|
|
// settling or timing out previous outgoing payments, then we
|
2016-10-30 17:54:59 +03:00
|
|
|
// can them from the pending set, and signal the requester (if
|
2016-07-17 04:20:13 +03:00
|
|
|
// existing) that the payment has been fully fulfilled.
|
2016-08-26 02:30:22 +03:00
|
|
|
var bandwidthUpdate btcutil.Amount
|
2016-09-22 05:41:26 +03:00
|
|
|
settledPayments := make(map[lnwallet.PaymentHash]struct{})
|
2017-02-21 05:10:05 +03:00
|
|
|
cancelledHtlcs := make(map[uint64]struct{})
|
2016-07-17 04:20:13 +03:00
|
|
|
for _, htlc := range htlcsToForward {
|
2017-01-08 07:23:06 +03:00
|
|
|
parentIndex := htlc.ParentIndex
|
|
|
|
if p, ok := state.clearedHTCLs[parentIndex]; ok {
|
|
|
|
switch htlc.EntryType {
|
|
|
|
// If the HTLC was settled successfully, then
|
2017-02-21 10:57:43 +03:00
|
|
|
// we return a nil error as well as the payment
|
|
|
|
// preimage back to the possible caller.
|
2017-01-08 07:23:06 +03:00
|
|
|
case lnwallet.Settle:
|
2017-02-21 10:57:43 +03:00
|
|
|
p.preImage <- htlc.RPreimage
|
2017-01-08 07:23:06 +03:00
|
|
|
p.err <- nil
|
|
|
|
|
|
|
|
// Otherwise, the HTLC failed, so we propagate
|
|
|
|
// the error back to the potential caller.
|
2017-02-21 05:10:05 +03:00
|
|
|
case lnwallet.Fail:
|
2017-01-08 07:23:06 +03:00
|
|
|
errMsg := state.cancelReasons[parentIndex]
|
2017-02-21 10:57:43 +03:00
|
|
|
p.preImage <- [32]byte{}
|
2017-01-08 07:23:06 +03:00
|
|
|
p.err <- errors.New(errMsg.String())
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
delete(state.clearedHTCLs, htlc.ParentIndex)
|
|
|
|
}
|
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
// TODO(roasbeef): rework log entries to a shared
|
|
|
|
// interface.
|
|
|
|
if htlc.EntryType != lnwallet.Add {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
// If we can settle this HTLC within our local state
|
|
|
|
// update log, then send the update entry to the remote
|
|
|
|
// party.
|
2016-08-26 02:30:22 +03:00
|
|
|
invoice, ok := state.htlcsToSettle[htlc.Index]
|
2017-01-08 07:23:06 +03:00
|
|
|
if ok {
|
|
|
|
preimage := invoice.Terms.PaymentPreimage
|
|
|
|
logIndex, err := state.channel.SettleHTLC(preimage)
|
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to settle htlc: %v", err)
|
|
|
|
p.Disconnect()
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
settleMsg := &lnwire.UpdateFufillHTLC{
|
|
|
|
ChannelPoint: *state.chanPoint,
|
|
|
|
ID: logIndex,
|
|
|
|
PaymentPreimage: preimage,
|
2017-01-08 07:23:06 +03:00
|
|
|
}
|
|
|
|
p.queueMsg(settleMsg, nil)
|
|
|
|
|
|
|
|
delete(state.htlcsToSettle, htlc.Index)
|
|
|
|
settledPayments[htlc.RHash] = struct{}{}
|
|
|
|
|
|
|
|
bandwidthUpdate += htlc.Amount
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alternatively, if we marked this HTLC for
|
|
|
|
// cancellation, then immediately cancel the HTLC as
|
|
|
|
// it's now locked in within both commitment
|
|
|
|
// transactions.
|
|
|
|
reason, ok := state.htlcsToCancel[htlc.Index]
|
2016-07-22 03:10:30 +03:00
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2016-07-17 04:20:13 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
logIndex, err := state.channel.FailHTLC(htlc.RHash)
|
2016-07-17 04:20:13 +03:00
|
|
|
if err != nil {
|
2017-01-08 07:23:06 +03:00
|
|
|
peerLog.Errorf("unable to cancel htlc: %v", err)
|
2016-07-22 03:10:30 +03:00
|
|
|
p.Disconnect()
|
2016-07-17 04:20:13 +03:00
|
|
|
continue
|
|
|
|
}
|
2016-07-22 03:10:30 +03:00
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
cancelMsg := &lnwire.UpdateFailHTLC{
|
|
|
|
ChannelPoint: *state.chanPoint,
|
|
|
|
ID: logIndex,
|
|
|
|
Reason: []byte{byte(reason)},
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
2017-01-08 07:23:06 +03:00
|
|
|
p.queueMsg(cancelMsg, nil)
|
|
|
|
delete(state.htlcsToCancel, htlc.Index)
|
2016-08-26 02:30:22 +03:00
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
cancelledHtlcs[htlc.Index] = struct{}{}
|
2016-07-22 03:10:30 +03:00
|
|
|
}
|
|
|
|
|
2016-09-22 05:41:26 +03:00
|
|
|
go func() {
|
|
|
|
for _, htlc := range htlcsToForward {
|
2017-01-13 08:01:50 +03:00
|
|
|
// We don't need to forward any HTLCs that we
|
2017-01-08 07:23:06 +03:00
|
|
|
// just settled or cancelled above.
|
2016-11-18 05:43:33 +03:00
|
|
|
// TODO(roasbeef): key by index instead?
|
2016-09-22 05:41:26 +03:00
|
|
|
if _, ok := settledPayments[htlc.RHash]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2017-01-08 07:23:06 +03:00
|
|
|
if _, ok := cancelledHtlcs[htlc.Index]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2016-09-22 05:41:26 +03:00
|
|
|
|
|
|
|
onionPkt := state.pendingCircuits[htlc.Index]
|
|
|
|
delete(state.pendingCircuits, htlc.Index)
|
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
reason := state.cancelReasons[htlc.ParentIndex]
|
|
|
|
delete(state.cancelReasons, htlc.ParentIndex)
|
|
|
|
|
2016-09-22 05:41:26 +03:00
|
|
|
// Send this fully activated HTLC to the htlc
|
|
|
|
// switch to continue the chained clear/settle.
|
|
|
|
pkt, err := logEntryToHtlcPkt(*state.chanPoint,
|
2017-01-08 07:23:06 +03:00
|
|
|
htlc, onionPkt, reason)
|
2016-09-22 05:41:26 +03:00
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to make htlc pkt: %v",
|
|
|
|
err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
state.switchChan <- pkt
|
|
|
|
}
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
2017-01-08 07:23:06 +03:00
|
|
|
if len(settledPayments) == 0 && len(cancelledHtlcs) == 0 {
|
2016-07-22 03:10:30 +03:00
|
|
|
return
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
|
|
|
|
2016-08-26 02:30:22 +03:00
|
|
|
// Send an update to the htlc switch of our newly available
|
|
|
|
// payment bandwidth.
|
|
|
|
// TODO(roasbeef): ideally should wait for next state update.
|
|
|
|
if bandwidthUpdate != 0 {
|
|
|
|
p.server.htlcSwitch.UpdateLink(state.chanPoint,
|
|
|
|
bandwidthUpdate)
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:20:13 +03:00
|
|
|
// With all the settle updates added to the local and remote
|
|
|
|
// HTLC logs, initiate a state transition by updating the
|
|
|
|
// remote commitment chain.
|
2017-02-21 05:10:05 +03:00
|
|
|
if err := p.updateCommitTx(state, false); err != nil {
|
2016-07-22 03:10:30 +03:00
|
|
|
peerLog.Errorf("unable to update commitment: %v", err)
|
|
|
|
p.Disconnect()
|
2016-07-17 04:20:13 +03:00
|
|
|
return
|
|
|
|
}
|
2016-09-21 03:00:11 +03:00
|
|
|
|
|
|
|
// Notify the invoiceRegistry of the invoices we just settled
|
|
|
|
// with this latest commitment update.
|
2016-10-28 05:49:10 +03:00
|
|
|
// TODO(roasbeef): wait until next transition?
|
2017-02-23 01:49:04 +03:00
|
|
|
for invoice := range settledPayments {
|
2017-01-06 00:56:27 +03:00
|
|
|
err := p.server.invoices.SettleInvoice(chainhash.Hash(invoice))
|
2016-09-21 03:00:11 +03:00
|
|
|
if err != nil {
|
|
|
|
peerLog.Errorf("unable to settle invoice: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2016-07-17 04:20:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-13 03:45:29 +03:00
|
|
|
// updateCommitTx signs, then sends an update to the remote peer adding a new
|
|
|
|
// commitment to their commitment chain which includes all the latest updates
|
|
|
|
// we've received+processed up to this point.
|
2017-02-21 05:10:05 +03:00
|
|
|
func (p *peer) updateCommitTx(state *commitmentState, reply bool) error {
|
|
|
|
sigTheirs, err := state.channel.SignNextCommitment()
|
2016-07-22 03:10:30 +03:00
|
|
|
if err == lnwallet.ErrNoWindow {
|
|
|
|
peerLog.Tracef("revocation window exhausted, unable to send %v",
|
|
|
|
len(state.pendingBatch))
|
2017-02-21 05:10:05 +03:00
|
|
|
return nil
|
2016-07-22 03:10:30 +03:00
|
|
|
} else if err != nil {
|
2017-02-21 05:10:05 +03:00
|
|
|
return err
|
2016-07-13 03:45:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
parsedSig, err := btcec.ParseSignature(sigTheirs, btcec.S256())
|
|
|
|
if err != nil {
|
2017-02-21 05:10:05 +03:00
|
|
|
return fmt.Errorf("unable to parse sig: %v", err)
|
2016-07-13 03:45:29 +03:00
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
commitSig := &lnwire.CommitSig{
|
|
|
|
ChannelPoint: *state.chanPoint,
|
2016-07-13 03:45:29 +03:00
|
|
|
CommitSig: parsedSig,
|
|
|
|
}
|
|
|
|
p.queueMsg(commitSig, nil)
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
// As we've just cleared out a batch, move all pending updates to the
|
|
|
|
// map of cleared HTLCs, clearing out the set of pending updates.
|
2016-07-22 03:10:30 +03:00
|
|
|
for _, update := range state.pendingBatch {
|
|
|
|
state.clearedHTCLs[update.index] = update
|
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
// We've just initiated a state transition, attempt to stop the
|
|
|
|
// logCommitTimer. If the timer already ticked, then we'll consume the
|
|
|
|
// value, dropping
|
|
|
|
if state.logCommitTimer != nil && !state.logCommitTimer.Stop() {
|
|
|
|
select {
|
|
|
|
case <-state.logCommitTimer.C:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
state.logCommitTick = nil
|
|
|
|
|
|
|
|
// Finally, clear our the current batch, and flip the pendingUpdate
|
|
|
|
// bool to indicate were waiting for a commitment signature.
|
|
|
|
// TODO(roasbeef): re-slice instead to avoid GC?
|
2016-07-22 03:10:30 +03:00
|
|
|
state.pendingBatch = nil
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
// If this isn't a reply to a state transitioned initiated by the
|
|
|
|
// remote node, then we toggle the `pendingUpdate` bool to indicate
|
|
|
|
// that we're waiting for a CommitSig in response.
|
|
|
|
if !reply {
|
|
|
|
state.pendingUpdate = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2016-07-22 03:10:30 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 06:40:38 +03:00
|
|
|
// fetchNextPendingChanID provides unique IDs for each channel opened between
|
|
|
|
// two peers
|
|
|
|
func (p *peer) fetchNextPendingChanID() uint64 {
|
|
|
|
p.pendingChannelMtx.Lock()
|
|
|
|
defer p.pendingChannelMtx.Unlock()
|
|
|
|
|
|
|
|
chanID := p.nextPendingChannelID
|
|
|
|
p.nextPendingChannelID++
|
|
|
|
return chanID
|
|
|
|
}
|
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
// logEntryToHtlcPkt converts a particular Lightning Commitment Protocol (LCP)
|
|
|
|
// log entry the corresponding htlcPacket with src/dest set along with the
|
2017-01-13 08:01:50 +03:00
|
|
|
// proper wire message. This helper method is provided in order to aid an
|
2016-07-22 03:10:30 +03:00
|
|
|
// htlcManager in forwarding packets to the htlcSwitch.
|
2016-09-22 05:41:26 +03:00
|
|
|
func logEntryToHtlcPkt(chanPoint wire.OutPoint,
|
|
|
|
pd *lnwallet.PaymentDescriptor,
|
2017-01-08 07:23:06 +03:00
|
|
|
onionPkt *sphinx.ProcessedPacket,
|
2017-02-21 05:10:05 +03:00
|
|
|
reason lnwire.FailCode) (*htlcPacket, error) {
|
2016-09-22 05:41:26 +03:00
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
pkt := &htlcPacket{}
|
|
|
|
|
|
|
|
// TODO(roasbeef): alter after switch to log entry interface
|
|
|
|
var msg lnwire.Message
|
|
|
|
switch pd.EntryType {
|
2017-02-21 05:10:05 +03:00
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
case lnwallet.Add:
|
|
|
|
// TODO(roasbeef): timeout, onion blob, etc
|
2016-09-22 05:41:26 +03:00
|
|
|
var b bytes.Buffer
|
|
|
|
if err := onionPkt.Packet.Encode(&b); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:10:05 +03:00
|
|
|
htlc := &lnwire.UpdateAddHTLC{
|
2017-02-23 22:07:01 +03:00
|
|
|
Amount: pd.Amount,
|
2017-02-21 05:10:05 +03:00
|
|
|
PaymentHash: pd.RHash,
|
2016-07-22 03:10:30 +03:00
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
copy(htlc.OnionBlob[:], b.Bytes())
|
|
|
|
msg = htlc
|
|
|
|
|
2016-07-22 03:10:30 +03:00
|
|
|
case lnwallet.Settle:
|
2017-02-21 05:10:05 +03:00
|
|
|
msg = &lnwire.UpdateFufillHTLC{
|
|
|
|
PaymentPreimage: pd.RPreimage,
|
2016-07-22 03:10:30 +03:00
|
|
|
}
|
2017-02-21 05:10:05 +03:00
|
|
|
|
|
|
|
case lnwallet.Fail:
|
2017-01-08 07:23:06 +03:00
|
|
|
// For cancellation messages, we'll also need to set the rHash
|
|
|
|
// within the htlcPacket so the switch knows on which outbound
|
|
|
|
// link to forward the cancellation message
|
2017-02-21 05:10:05 +03:00
|
|
|
msg = &lnwire.UpdateFailHTLC{
|
|
|
|
Reason: []byte{byte(reason)},
|
2017-01-08 07:23:06 +03:00
|
|
|
}
|
|
|
|
pkt.payHash = pd.RHash
|
2016-07-22 03:10:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pkt.amt = pd.Amount
|
|
|
|
pkt.msg = msg
|
|
|
|
|
2016-09-22 05:41:26 +03:00
|
|
|
pkt.srcLink = chanPoint
|
|
|
|
pkt.onion = onionPkt
|
|
|
|
|
|
|
|
return pkt, nil
|
2016-07-13 03:45:29 +03:00
|
|
|
}
|
|
|
|
|
2016-06-21 22:32:32 +03:00
|
|
|
// TODO(roasbeef): make all start/stop mutexes a CAS
|