chancloser: new package for cooperative channel closure

Introduces a new chancloser package which exposes a ChanCloser
struct that handles the cooperative channel closure negotiation
and is meant to replace chancloser.go in the lnd package. Updates
all references to chancloser.go to instead use chancloser package.
This commit is contained in:
nsa 2020-06-16 20:33:06 -04:00
parent 8528ec4568
commit 2d68a64a5b
7 changed files with 97 additions and 50 deletions

@ -1,4 +1,4 @@
package lnd package chancloser
import ( import (
"bytes" "bytes"
@ -70,13 +70,13 @@ const (
closeFinished closeFinished
) )
// ChanCloseCfg holds all the items that a channelCloser requires to carry out its // ChanCloseCfg holds all the items that a ChanCloser requires to carry out its
// duties. // duties.
type ChanCloseCfg struct { type ChanCloseCfg struct {
// Channel is the channel that should be closed. // Channel is the channel that should be closed.
Channel *lnwallet.LightningChannel Channel *lnwallet.LightningChannel
// UnregisterChannel is a function closure that allows the channelCloser to // UnregisterChannel is a function closure that allows the ChanCloser to
// unregister a channel. Once this has been done, no further HTLC's should // unregister a channel. Once this has been done, no further HTLC's should
// be routed through the channel. // be routed through the channel.
UnregisterChannel func(lnwire.ChannelID) UnregisterChannel func(lnwire.ChannelID)
@ -96,15 +96,15 @@ type ChanCloseCfg struct {
Quit chan struct{} Quit chan struct{}
} }
// channelCloser is a state machine that handles the cooperative channel closure // ChanCloser is a state machine that handles the cooperative channel closure
// procedure. This includes shutting down a channel, marking it ineligible for // procedure. This includes shutting down a channel, marking it ineligible for
// routing HTLC's, negotiating fees with the remote party, and finally // routing HTLC's, negotiating fees with the remote party, and finally
// broadcasting the fully signed closure transaction to the network. // broadcasting the fully signed closure transaction to the network.
type channelCloser struct { type ChanCloser struct {
// state is the current state of the state machine. // state is the current state of the state machine.
state closeState state closeState
// cfg holds the configuration for this channelCloser instance. // cfg holds the configuration for this ChanCloser instance.
cfg ChanCloseCfg cfg ChanCloseCfg
// chanPoint is the full channel point of the target channel. // chanPoint is the full channel point of the target channel.
@ -162,7 +162,7 @@ type channelCloser struct {
// be populated iff, we're the initiator of this closing request. // be populated iff, we're the initiator of this closing request.
func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte, func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32, idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32,
closeReq *htlcswitch.ChanClose, locallyInitiated bool) *channelCloser { closeReq *htlcswitch.ChanClose, locallyInitiated bool) *ChanCloser {
// Given the target fee-per-kw, we'll compute what our ideal _total_ fee // Given the target fee-per-kw, we'll compute what our ideal _total_ fee
// will be starting at for this fee negotiation. // will be starting at for this fee negotiation.
@ -177,17 +177,17 @@ func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
// TODO(roasbeef): clamp fee func? // TODO(roasbeef): clamp fee func?
channelCommitFee := cfg.Channel.StateSnapshot().CommitFee channelCommitFee := cfg.Channel.StateSnapshot().CommitFee
if idealFeeSat > channelCommitFee { if idealFeeSat > channelCommitFee {
peerLog.Infof("Ideal starting fee of %v is greater than commit "+ chancloserLog.Infof("Ideal starting fee of %v is greater than commit "+
"fee of %v, clamping", int64(idealFeeSat), int64(channelCommitFee)) "fee of %v, clamping", int64(idealFeeSat), int64(channelCommitFee))
idealFeeSat = channelCommitFee idealFeeSat = channelCommitFee
} }
peerLog.Infof("Ideal fee for closure of ChannelPoint(%v) is: %v sat", chancloserLog.Infof("Ideal fee for closure of ChannelPoint(%v) is: %v sat",
cfg.Channel.ChannelPoint(), int64(idealFeeSat)) cfg.Channel.ChannelPoint(), int64(idealFeeSat))
cid := lnwire.NewChanIDFromOutPoint(cfg.Channel.ChannelPoint()) cid := lnwire.NewChanIDFromOutPoint(cfg.Channel.ChannelPoint())
return &channelCloser{ return &ChanCloser{
closeReq: closeReq, closeReq: closeReq,
state: closeIdle, state: closeIdle,
chanPoint: *cfg.Channel.ChannelPoint(), chanPoint: *cfg.Channel.ChannelPoint(),
@ -203,7 +203,7 @@ func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
// initChanShutdown begins the shutdown process by un-registering the channel, // initChanShutdown begins the shutdown process by un-registering the channel,
// and creating a valid shutdown message to our target delivery address. // and creating a valid shutdown message to our target delivery address.
func (c *channelCloser) initChanShutdown() (*lnwire.Shutdown, error) { func (c *ChanCloser) initChanShutdown() (*lnwire.Shutdown, error) {
// With both items constructed we'll now send the shutdown message for this // With both items constructed we'll now send the shutdown message for this
// particular channel, advertising a shutdown request to our desired // particular channel, advertising a shutdown request to our desired
// closing script. // closing script.
@ -215,7 +215,7 @@ func (c *channelCloser) initChanShutdown() (*lnwire.Shutdown, error) {
// We do so before closing the channel as otherwise the current edge policy // We do so before closing the channel as otherwise the current edge policy
// won't be retrievable from the graph. // won't be retrievable from the graph.
if err := c.cfg.DisableChannel(c.chanPoint); err != nil { if err := c.cfg.DisableChannel(c.chanPoint); err != nil {
peerLog.Warnf("Unable to disable channel %v on close: %v", chancloserLog.Warnf("Unable to disable channel %v on close: %v",
c.chanPoint, err) c.chanPoint, err)
} }
@ -233,7 +233,8 @@ func (c *channelCloser) initChanShutdown() (*lnwire.Shutdown, error) {
return nil, err return nil, err
} }
peerLog.Infof("ChannelPoint(%v): sending shutdown message", c.chanPoint) chancloserLog.Infof("ChannelPoint(%v): sending shutdown message",
c.chanPoint)
return shutdown, nil return shutdown, nil
} }
@ -242,14 +243,14 @@ func (c *channelCloser) initChanShutdown() (*lnwire.Shutdown, error) {
// cooperative channel closure. This message returns the shutdown message to // cooperative channel closure. This message returns the shutdown message to
// send to the remote party. Upon completion, we enter the // send to the remote party. Upon completion, we enter the
// closeShutdownInitiated phase as we await a response. // closeShutdownInitiated phase as we await a response.
func (c *channelCloser) ShutdownChan() (*lnwire.Shutdown, error) { func (c *ChanCloser) ShutdownChan() (*lnwire.Shutdown, error) {
// If we attempt to shutdown the channel for the first time, and we're not // If we attempt to shutdown the channel for the first time, and we're not
// in the closeIdle state, then the caller made an error. // in the closeIdle state, then the caller made an error.
if c.state != closeIdle { if c.state != closeIdle {
return nil, ErrChanAlreadyClosing return nil, ErrChanAlreadyClosing
} }
peerLog.Infof("ChannelPoint(%v): initiating shutdown", c.chanPoint) chancloserLog.Infof("ChannelPoint(%v): initiating shutdown", c.chanPoint)
shutdownMsg, err := c.initChanShutdown() shutdownMsg, err := c.initChanShutdown()
if err != nil { if err != nil {
@ -270,7 +271,7 @@ func (c *channelCloser) ShutdownChan() (*lnwire.Shutdown, error) {
// //
// NOTE: This transaction is only available if the state machine is in the // NOTE: This transaction is only available if the state machine is in the
// closeFinished state. // closeFinished state.
func (c *channelCloser) ClosingTx() (*wire.MsgTx, error) { func (c *ChanCloser) ClosingTx() (*wire.MsgTx, error) {
// If the state machine hasn't finished closing the channel, then we'll // If the state machine hasn't finished closing the channel, then we'll
// return an error as we haven't yet computed the closing tx. // return an error as we haven't yet computed the closing tx.
if c.state != closeFinished { if c.state != closeFinished {
@ -285,17 +286,17 @@ func (c *channelCloser) ClosingTx() (*wire.MsgTx, error) {
// //
// NOTE: This will only return a non-nil pointer if we were the initiator of // NOTE: This will only return a non-nil pointer if we were the initiator of
// the cooperative closure workflow. // the cooperative closure workflow.
func (c *channelCloser) CloseRequest() *htlcswitch.ChanClose { func (c *ChanCloser) CloseRequest() *htlcswitch.ChanClose {
return c.closeReq return c.closeReq
} }
// Channel returns the channel stored in the config. // Channel returns the channel stored in the config.
func (c *channelCloser) Channel() *lnwallet.LightningChannel { func (c *ChanCloser) Channel() *lnwallet.LightningChannel {
return c.cfg.Channel return c.cfg.Channel
} }
// NegotiationHeight returns the negotiation height. // NegotiationHeight returns the negotiation height.
func (c *channelCloser) NegotiationHeight() uint32 { func (c *ChanCloser) NegotiationHeight() uint32 {
return c.negotiationHeight return c.negotiationHeight
} }
@ -317,7 +318,7 @@ func maybeMatchScript(disconnect func() error, upfrontScript,
// If an upfront shutdown script was provided, disconnect from the peer, as // If an upfront shutdown script was provided, disconnect from the peer, as
// per BOLT 2, and return an error. // per BOLT 2, and return an error.
if !bytes.Equal(upfrontScript, peerScript) { if !bytes.Equal(upfrontScript, peerScript) {
peerLog.Warnf("peer's script: %x does not match upfront "+ chancloserLog.Warnf("peer's script: %x does not match upfront "+
"shutdown script: %x", peerScript, upfrontScript) "shutdown script: %x", peerScript, upfrontScript)
// Disconnect from the peer because they have violated option upfront // Disconnect from the peer because they have violated option upfront
@ -336,8 +337,8 @@ func maybeMatchScript(disconnect func() error, upfrontScript,
// This method will update the state accordingly and return two primary values: // This method will update the state accordingly and return two primary values:
// the next set of messages to be sent, and a bool indicating if the fee // the next set of messages to be sent, and a bool indicating if the fee
// negotiation process has completed. If the second value is true, then this // negotiation process has completed. If the second value is true, then this
// means the channelCloser can be garbage collected. // means the ChanCloser can be garbage collected.
func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, func (c *ChanCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
bool, error) { bool, error) {
switch c.state { switch c.state {
@ -390,7 +391,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
return nil, false, err return nil, false, err
} }
peerLog.Infof("ChannelPoint(%v): responding to shutdown", chancloserLog.Infof("ChannelPoint(%v): responding to shutdown",
c.chanPoint) c.chanPoint)
msgsToSend := make([]lnwire.Message, 0, 2) msgsToSend := make([]lnwire.Message, 0, 2)
@ -445,7 +446,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
// closing transaction should look like. // closing transaction should look like.
c.state = closeFeeNegotiation c.state = closeFeeNegotiation
peerLog.Infof("ChannelPoint(%v): shutdown response received, "+ chancloserLog.Infof("ChannelPoint(%v): shutdown response received, "+
"entering fee negotiation", c.chanPoint) "entering fee negotiation", c.chanPoint)
// Starting with our ideal fee rate, we'll create an initial closing // Starting with our ideal fee rate, we'll create an initial closing
@ -482,9 +483,8 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
// We'll now attempt to ratchet towards a fee deemed acceptable by // We'll now attempt to ratchet towards a fee deemed acceptable by
// both parties, factoring in our ideal fee rate, and the last // both parties, factoring in our ideal fee rate, and the last
// proposed fee by both sides. // proposed fee by both sides.
feeProposal := calcCompromiseFee(c.chanPoint, feeProposal := calcCompromiseFee(c.chanPoint, c.idealFeeSat,
c.idealFeeSat, c.lastFeeProposal, c.lastFeeProposal, remoteProposedFee,
remoteProposedFee,
) )
// With our new fee proposal calculated, we'll craft a new close // With our new fee proposal calculated, we'll craft a new close
@ -499,13 +499,13 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
// we'll return this latest close signed message so we can continue // we'll return this latest close signed message so we can continue
// negotiation. // negotiation.
if feeProposal != remoteProposedFee { if feeProposal != remoteProposedFee {
peerLog.Debugf("ChannelPoint(%v): close tx fee "+ chancloserLog.Debugf("ChannelPoint(%v): close tx fee "+
"disagreement, continuing negotiation", c.chanPoint) "disagreement, continuing negotiation", c.chanPoint)
return []lnwire.Message{closeSigned}, false, nil return []lnwire.Message{closeSigned}, false, nil
} }
} }
peerLog.Infof("ChannelPoint(%v) fee of %v accepted, ending "+ chancloserLog.Infof("ChannelPoint(%v) fee of %v accepted, ending "+
"negotiation", c.chanPoint, remoteProposedFee) "negotiation", c.chanPoint, remoteProposedFee)
// Otherwise, we've agreed on a fee for the closing transaction! We'll // Otherwise, we've agreed on a fee for the closing transaction! We'll
@ -540,7 +540,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
// With the closing transaction crafted, we'll now broadcast it to the // With the closing transaction crafted, we'll now broadcast it to the
// network. // network.
peerLog.Infof("Broadcasting cooperative close tx: %v", chancloserLog.Infof("Broadcasting cooperative close tx: %v",
newLogClosure(func() string { newLogClosure(func() string {
return spew.Sdump(closeTx) return spew.Sdump(closeTx)
}), }),
@ -579,7 +579,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
// proposeCloseSigned attempts to propose a new signature for the closing // proposeCloseSigned attempts to propose a new signature for the closing
// transaction for a channel based on the prior fee negotiations and our current // transaction for a channel based on the prior fee negotiations and our current
// compromise fee. // compromise fee.
func (c *channelCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingSigned, error) { func (c *ChanCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingSigned, error) {
rawSig, _, _, err := c.cfg.Channel.CreateCloseProposal( rawSig, _, _, err := c.cfg.Channel.CreateCloseProposal(
fee, c.localDeliveryScript, c.remoteDeliveryScript, fee, c.localDeliveryScript, c.remoteDeliveryScript,
) )
@ -595,7 +595,7 @@ func (c *channelCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingS
return nil, err return nil, err
} }
peerLog.Infof("ChannelPoint(%v): proposing fee of %v sat to close "+ chancloserLog.Infof("ChannelPoint(%v): proposing fee of %v sat to close "+
"chan", c.chanPoint, int64(fee)) "chan", c.chanPoint, int64(fee))
// We'll assemble a ClosingSigned message using this information and return // We'll assemble a ClosingSigned message using this information and return
@ -650,7 +650,7 @@ func calcCompromiseFee(chanPoint wire.OutPoint, ourIdealFee, lastSentFee,
// TODO(roasbeef): take in number of rounds as well? // TODO(roasbeef): take in number of rounds as well?
peerLog.Infof("ChannelPoint(%v): computing fee compromise, ideal="+ chancloserLog.Infof("ChannelPoint(%v): computing fee compromise, ideal="+
"%v, last_sent=%v, remote_offer=%v", chanPoint, int64(ourIdealFee), "%v, last_sent=%v, remote_offer=%v", chanPoint, int64(ourIdealFee),
int64(lastSentFee), int64(remoteFee)) int64(lastSentFee), int64(remoteFee))
@ -676,7 +676,7 @@ func calcCompromiseFee(chanPoint wire.OutPoint, ourIdealFee, lastSentFee,
// If the fee is lower, but still acceptable, then we'll just return // If the fee is lower, but still acceptable, then we'll just return
// this fee and end the negotiation. // this fee and end the negotiation.
if feeInAcceptableRange(lastSentFee, remoteFee) { if feeInAcceptableRange(lastSentFee, remoteFee) {
peerLog.Infof("ChannelPoint(%v): proposed remote fee is "+ chancloserLog.Infof("ChannelPoint(%v): proposed remote fee is "+
"close enough, capitulating", chanPoint) "close enough, capitulating", chanPoint)
return remoteFee return remoteFee
} }
@ -690,13 +690,12 @@ func calcCompromiseFee(chanPoint wire.OutPoint, ourIdealFee, lastSentFee,
// If the fee is greater, but still acceptable, then we'll just return // If the fee is greater, but still acceptable, then we'll just return
// this fee in order to put an end to the negotiation. // this fee in order to put an end to the negotiation.
if feeInAcceptableRange(lastSentFee, remoteFee) { if feeInAcceptableRange(lastSentFee, remoteFee) {
peerLog.Infof("ChannelPoint(%v): proposed remote fee is "+ chancloserLog.Infof("ChannelPoint(%v): proposed remote fee is "+
"close enough, capitulating", chanPoint) "close enough, capitulating", chanPoint)
return remoteFee return remoteFee
} }
// Otherwise, we'll rachet the fee up using our current // Otherwise, we'll ratchet the fee up using our current algorithm.
// algorithm.
return ratchetFee(lastSentFee, true) return ratchetFee(lastSentFee, true)
default: default:

@ -1,4 +1,4 @@
package lnd package chancloser
import ( import (
"crypto/rand" "crypto/rand"

@ -0,0 +1,41 @@
package chancloser
import (
"github.com/btcsuite/btclog"
"github.com/lightningnetwork/lnd/build"
)
// chancloserLog is a logger that is initialized with the btclog.Disabled
// logger.
var chancloserLog btclog.Logger
// The default amount of logging is none.
func init() {
UseLogger(build.NewSubLogger("CHCL", nil))
}
// DisableLog disables all logging output.
func DisableLog() {
UseLogger(btclog.Disabled)
}
// UseLogger uses a specified Logger to output package logging info.
func UseLogger(logger btclog.Logger) {
chancloserLog = logger
}
// logClosure is used to provide a closure over expensive logging operations
// so they aren't performed when the logging level doesn't warrant it.
type logClosure func() string
// String invokes the underlying function and returns the result.
func (c logClosure) String() string {
return c()
}
// newLogClosure returns a new closure over a function that returns a string
// which itself provides a Stringer interface so that it can be used with the
// logging system.
func newLogClosure(c func() string) logClosure {
return logClosure(c)
}

2
log.go

@ -26,6 +26,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/verrpc" "github.com/lightningnetwork/lnd/lnrpc/verrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding" "github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/monitoring" "github.com/lightningnetwork/lnd/monitoring"
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
@ -121,6 +122,7 @@ func SetupLoggers(root *build.RotatingLogWriter) {
AddSubLogger(root, "WTCL", wtclient.UseLogger) AddSubLogger(root, "WTCL", wtclient.UseLogger)
AddSubLogger(root, "PRNF", peernotifier.UseLogger) AddSubLogger(root, "PRNF", peernotifier.UseLogger)
AddSubLogger(root, "CHFD", chanfunding.UseLogger) AddSubLogger(root, "CHFD", chanfunding.UseLogger)
AddSubLogger(root, "CHCL", chancloser.UseLogger)
AddSubLogger(root, routing.Subsystem, routing.UseLogger, localchans.UseLogger) AddSubLogger(root, routing.Subsystem, routing.UseLogger, localchans.UseLogger)
AddSubLogger(root, routerrpc.Subsystem, routerrpc.UseLogger) AddSubLogger(root, routerrpc.Subsystem, routerrpc.UseLogger)

21
peer.go

@ -27,6 +27,7 @@ import (
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/pool" "github.com/lightningnetwork/lnd/pool"
"github.com/lightningnetwork/lnd/queue" "github.com/lightningnetwork/lnd/queue"
@ -190,7 +191,7 @@ type peer struct {
// messages are directed to one of these active state machines. Once // messages are directed to one of these active state machines. Once
// the channel has been closed, the state machine will be delete from // the channel has been closed, the state machine will be delete from
// the map. // the map.
activeChanCloses map[lnwire.ChannelID]*channelCloser activeChanCloses map[lnwire.ChannelID]*chancloser.ChanCloser
// localCloseChanReqs is a channel in which any local requests to close // localCloseChanReqs is a channel in which any local requests to close
// a particular channel are sent over. // a particular channel are sent over.
@ -302,7 +303,7 @@ func newPeer(cfg *Config, conn net.Conn, connReq *connmgr.ConnReq, server *serve
activeMsgStreams: make(map[lnwire.ChannelID]*msgStream), activeMsgStreams: make(map[lnwire.ChannelID]*msgStream),
activeChanCloses: make(map[lnwire.ChannelID]*channelCloser), activeChanCloses: make(map[lnwire.ChannelID]*chancloser.ChanCloser),
localCloseChanReqs: make(chan *htlcswitch.ChanClose), localCloseChanReqs: make(chan *htlcswitch.ChanClose),
linkFailures: make(chan linkFailureReport), linkFailures: make(chan linkFailureReport),
chanCloseMsgs: make(chan *closeMsg), chanCloseMsgs: make(chan *closeMsg),
@ -2232,7 +2233,9 @@ func (p *peer) reenableActiveChannels() {
// for the target channel ID. If the channel isn't active an error is returned. // for the target channel ID. If the channel isn't active an error is returned.
// Otherwise, either an existing state machine will be returned, or a new one // Otherwise, either an existing state machine will be returned, or a new one
// will be created. // will be created.
func (p *peer) fetchActiveChanCloser(chanID lnwire.ChannelID) (*channelCloser, error) { func (p *peer) fetchActiveChanCloser(chanID lnwire.ChannelID) (
*chancloser.ChanCloser, error) {
// First, we'll ensure that we actually know of the target channel. If // First, we'll ensure that we actually know of the target channel. If
// not, we'll ignore this message. // not, we'll ignore this message.
p.activeChanMtx.RLock() p.activeChanMtx.RLock()
@ -2288,8 +2291,8 @@ func (p *peer) fetchActiveChanCloser(chanID lnwire.ChannelID) (*channelCloser, e
return nil, fmt.Errorf("cannot obtain best block") return nil, fmt.Errorf("cannot obtain best block")
} }
chanCloser = NewChanCloser( chanCloser = chancloser.NewChanCloser(
ChanCloseCfg{ chancloser.ChanCloseCfg{
Channel: channel, Channel: channel,
UnregisterChannel: p.server.htlcSwitch.RemoveLink, UnregisterChannel: p.server.htlcSwitch.RemoveLink,
BroadcastTx: p.server.cc.wallet.PublishTransaction, BroadcastTx: p.server.cc.wallet.PublishTransaction,
@ -2334,7 +2337,7 @@ func chooseDeliveryScript(upfront,
// the upfront shutdown script (because closing out to a different script // the upfront shutdown script (because closing out to a different script
// would violate upfront shutdown). // would violate upfront shutdown).
if !bytes.Equal(upfront, requested) { if !bytes.Equal(upfront, requested) {
return nil, ErrUpfrontShutdownScriptMismatch return nil, chancloser.ErrUpfrontShutdownScriptMismatch
} }
// The user requested script matches the upfront shutdown script, so we // The user requested script matches the upfront shutdown script, so we
@ -2404,8 +2407,8 @@ func (p *peer) handleLocalCloseReq(req *htlcswitch.ChanClose) {
return return
} }
chanCloser := NewChanCloser( chanCloser := chancloser.NewChanCloser(
ChanCloseCfg{ chancloser.ChanCloseCfg{
Channel: channel, Channel: channel,
UnregisterChannel: p.server.htlcSwitch.RemoveLink, UnregisterChannel: p.server.htlcSwitch.RemoveLink,
BroadcastTx: p.server.cc.wallet.PublishTransaction, BroadcastTx: p.server.cc.wallet.PublishTransaction,
@ -2520,7 +2523,7 @@ func (p *peer) handleLinkFailure(failure linkFailureReport) {
// machine should be passed in. Once the transaction has been sufficiently // machine should be passed in. Once the transaction has been sufficiently
// confirmed, the channel will be marked as fully closed within the database, // confirmed, the channel will be marked as fully closed within the database,
// and any clients will be notified of updates to the closing state. // and any clients will be notified of updates to the closing state.
func (p *peer) finalizeChanClosure(chanCloser *channelCloser) { func (p *peer) finalizeChanClosure(chanCloser *chancloser.ChanCloser) {
closeReq := chanCloser.CloseRequest() closeReq := chanCloser.CloseRequest()
// First, we'll clear all indexes related to the channel in question. // First, we'll clear all indexes related to the channel in question.

@ -14,6 +14,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
@ -642,7 +643,7 @@ func TestChooseDeliveryScript(t *testing.T) {
userScript: script1, userScript: script1,
shutdownScript: script2, shutdownScript: script2,
expectedScript: nil, expectedScript: nil,
expectedError: ErrUpfrontShutdownScriptMismatch, expectedError: chancloser.ErrUpfrontShutdownScriptMismatch,
}, },
{ {
name: "Only upfront script", name: "Only upfront script",
@ -733,7 +734,7 @@ func TestCustomShutdownScript(t *testing.T) {
name: "Shutdown set, user script different", name: "Shutdown set, user script different",
update: setShutdown, update: setShutdown,
userCloseScript: []byte("different addr"), userCloseScript: []byte("different addr"),
expectedError: ErrUpfrontShutdownScriptMismatch, expectedError: chancloser.ErrUpfrontShutdownScriptMismatch,
}, },
} }

@ -24,6 +24,7 @@ import (
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/shachain" "github.com/lightningnetwork/lnd/shachain"
@ -441,7 +442,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, publTx chan *wire.MsgTx,
activeChannels: make(map[lnwire.ChannelID]*lnwallet.LightningChannel), activeChannels: make(map[lnwire.ChannelID]*lnwallet.LightningChannel),
newChannels: make(chan *newChannelMsg, 1), newChannels: make(chan *newChannelMsg, 1),
activeChanCloses: make(map[lnwire.ChannelID]*channelCloser), activeChanCloses: make(map[lnwire.ChannelID]*chancloser.ChanCloser),
localCloseChanReqs: make(chan *htlcswitch.ChanClose), localCloseChanReqs: make(chan *htlcswitch.ChanClose),
chanCloseMsgs: make(chan *closeMsg), chanCloseMsgs: make(chan *closeMsg),