chancloser+peer: export negotiationHeight, channel, and error

This commit is contained in:
nsa 2020-06-11 15:25:05 -04:00
parent 38b8e54ba7
commit ec2d999371
4 changed files with 72 additions and 62 deletions

@ -27,10 +27,10 @@ var (
// a message while it is in an unknown state.
ErrInvalidState = fmt.Errorf("invalid state")
// errUpfrontShutdownScriptMismatch is returned when a peer or end user
// ErrUpfrontShutdownScriptMismatch is returned when a peer or end user
// provides a script to cooperatively close out to which does not match
// the upfront shutdown script previously set for that party.
errUpfrontShutdownScriptMismatch = fmt.Errorf("shutdown " +
ErrUpfrontShutdownScriptMismatch = fmt.Errorf("shutdown " +
"script does not match upfront shutdown script")
)
@ -71,30 +71,30 @@ const (
closeFinished
)
// chanCloseCfg holds all the items that a channelCloser requires to carry out
// ChanCloseCfg holds all the items that a channelCloser requires to carry out
// its duties.
type chanCloseCfg struct {
// channel is the channel that should be closed.
channel *lnwallet.LightningChannel
type ChanCloseCfg struct {
// Channel is the channel that should be closed.
Channel *lnwallet.LightningChannel
// unregisterChannel is a function closure that allows the
// UnregisterChannel is a function closure that allows the
// channelCloser to re-register a channel. Once this has been done, no
// further HTLC's should be routed through the channel.
unregisterChannel func(lnwire.ChannelID)
UnregisterChannel func(lnwire.ChannelID)
// broadcastTx broadcasts the passed transaction to the network.
broadcastTx func(*wire.MsgTx, string) error
// BroadcastTx broadcasts the passed transaction to the network.
BroadcastTx func(*wire.MsgTx, string) error
// disableChannel disables a channel, resulting in it not being able to
// DisableChannel disables a channel, resulting in it not being able to
// forward payments.
disableChannel func(wire.OutPoint) error
DisableChannel func(wire.OutPoint) error
// disconnect will disconnect from the remote peer in this close.
disconnect func() error
// Disconnect will disconnect from the remote peer in this close.
Disconnect func() error
// quit is a channel that should be sent upon in the occasion the state
// Quit is a channel that should be sent upon in the occasion the state
// machine should cease all progress and shutdown.
quit chan struct{}
Quit chan struct{}
}
// channelCloser is a state machine that handles the cooperative channel
@ -106,7 +106,7 @@ type channelCloser struct {
state closeState
// cfg holds the configuration for this channelCloser instance.
cfg chanCloseCfg
cfg ChanCloseCfg
// chanPoint is the full channel point of the target channel.
chanPoint wire.OutPoint
@ -159,10 +159,10 @@ type channelCloser struct {
locallyInitiated bool
}
// newChannelCloser creates a new instance of the channel closure given the
// NewChanCloser creates a new instance of the channel closure given the
// passed configuration, and delivery+fee preference. The final argument should
// only be populated iff, we're the initiator of this closing request.
func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32,
closeReq *htlcswitch.ChanClose, locallyInitiated bool) *channelCloser {
@ -170,14 +170,14 @@ func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
// fee will be starting at for this fee negotiation.
//
// TODO(roasbeef): should factor in minimal commit
idealFeeSat := cfg.channel.CalcFee(idealFeePerKw)
idealFeeSat := cfg.Channel.CalcFee(idealFeePerKw)
// If this fee is greater than the fee currently present within the
// commitment transaction, then we'll clamp it down to be within the
// proper range.
//
// TODO(roasbeef): clamp fee func?
channelCommitFee := cfg.channel.StateSnapshot().CommitFee
channelCommitFee := cfg.Channel.StateSnapshot().CommitFee
if idealFeeSat > channelCommitFee {
peerLog.Infof("Ideal starting fee of %v is greater than "+
"commit fee of %v, clamping", int64(idealFeeSat),
@ -187,13 +187,13 @@ func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
}
peerLog.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{
closeReq: closeReq,
state: closeIdle,
chanPoint: *cfg.channel.ChannelPoint(),
chanPoint: *cfg.Channel.ChannelPoint(),
cid: cid,
cfg: cfg,
negotiationHeight: negotiationHeight,
@ -217,21 +217,21 @@ func (c *channelCloser) initChanShutdown() (*lnwire.Shutdown, error) {
// Before closing, we'll attempt to send a disable update for the
// channel. We do so before closing the channel as otherwise the current
// edge policy 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", c.chanPoint, err)
}
// Before returning the shutdown message, we'll unregister the channel
// to ensure that it isn't seen as usable within the system.
c.cfg.unregisterChannel(c.cid)
c.cfg.UnregisterChannel(c.cid)
// Before continuing, mark the channel as cooperatively closed with a
// nil txn. Even though we haven't negotiated the final txn, this
// guarantees that our listchannels rpc will be externally consistent,
// and reflect that the channel is being shutdown by the time the
// closing request returns.
err := c.cfg.channel.MarkCoopBroadcasted(nil, c.locallyInitiated)
err := c.cfg.Channel.MarkCoopBroadcasted(nil, c.locallyInitiated)
if err != nil {
return nil, err
}
@ -292,6 +292,16 @@ func (c *channelCloser) CloseRequest() *htlcswitch.ChanClose {
return c.closeReq
}
// Channel returns the channel stored in the config.
func (c *channelCloser) Channel() *lnwallet.LightningChannel {
return c.cfg.Channel
}
// NegotiationHeight returns the negotiation height.
func (c *channelCloser) NegotiationHeight() uint32 {
return c.negotiationHeight
}
// maybeMatchScript attempts to match the script provided in our peer's
// shutdown message with the upfront shutdown script we have on record.
// If no upfront shutdown script was set, we do not need to enforce option
@ -320,7 +330,7 @@ func maybeMatchScript(disconnect func() error,
return err
}
return errUpfrontShutdownScriptMismatch
return ErrUpfrontShutdownScriptMismatch
}
return nil
@ -350,21 +360,21 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// wants to close), we'll check if this is a frozen channel or
// not. If the channel is frozen as we were also the initiator
// of the channel opening, then we'll deny their close attempt.
chanInitiator := c.cfg.channel.IsInitiator()
if !chanInitiator && c.cfg.channel.State().ChanType.IsFrozen() &&
c.negotiationHeight < c.cfg.channel.State().ThawHeight {
chanInitiator := c.cfg.Channel.IsInitiator()
if !chanInitiator && c.cfg.Channel.State().ChanType.IsFrozen() &&
c.negotiationHeight < c.cfg.Channel.State().ThawHeight {
return nil, false, fmt.Errorf("initiator attempting "+
"to co-op close frozen ChannelPoint(%v) "+
"(current_height=%v, thaw_height=%v)",
c.chanPoint, c.negotiationHeight,
c.cfg.channel.State().ThawHeight)
c.cfg.Channel.State().ThawHeight)
}
// If the remote node opened the channel with option upfront shutdown
// script, check that the script they provided matches.
if err := maybeMatchScript(
c.cfg.disconnect, c.cfg.channel.RemoteUpfrontShutdownScript(),
c.cfg.Disconnect, c.cfg.Channel.RemoteUpfrontShutdownScript(),
shutDownMsg.Address,
); err != nil {
return nil, false, err
@ -423,7 +433,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// If the remote node opened the channel with option upfront shutdown
// script, check that the script they provided matches.
if err := maybeMatchScript(
c.cfg.disconnect, c.cfg.channel.RemoteUpfrontShutdownScript(),
c.cfg.Disconnect, c.cfg.Channel.RemoteUpfrontShutdownScript(),
shutDownMsg.Address,
); err != nil {
return nil, false, err
@ -445,7 +455,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// closing proposal, but only if we're the initiator, as
// otherwise, the other party will send their first proposal
// first.
if c.cfg.channel.IsInitiator() {
if c.cfg.Channel.IsInitiator() {
closeSigned, err := c.proposeCloseSigned(c.idealFeeSat)
if err != nil {
return nil, false, err
@ -519,7 +529,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
return nil, false, err
}
closeTx, _, err := c.cfg.channel.CompleteCooperativeClose(
closeTx, _, err := c.cfg.Channel.CompleteCooperativeClose(
localSig, remoteSig, c.localDeliveryScript,
c.remoteDeliveryScript, remoteProposedFee,
)
@ -531,7 +541,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// Before publishing the closing tx, we persist it to the
// database, such that it can be republished if something goes
// wrong.
err = c.cfg.channel.MarkCoopBroadcasted(
err = c.cfg.Channel.MarkCoopBroadcasted(
closeTx, c.locallyInitiated,
)
if err != nil {
@ -544,7 +554,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
newLogClosure(func() string {
return spew.Sdump(closeTx)
}))
err = c.cfg.broadcastTx(closeTx, "")
err = c.cfg.BroadcastTx(closeTx, "")
if err != nil {
return nil, false, err
}
@ -582,7 +592,7 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// transaction for a channel based on the prior fee negotiations and our
// current compromise fee.
func (c *channelCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingSigned, error) {
rawSig, _, _, err := c.cfg.channel.CreateCloseProposal(
rawSig, _, _, err := c.cfg.Channel.CreateCloseProposal(
fee, c.localDeliveryScript, c.remoteDeliveryScript,
)
if err != nil {

@ -49,7 +49,7 @@ func TestMaybeMatchScript(t *testing.T) {
name: "upfront shutdown set, script not ok",
shutdownScript: addr1,
upfrontScript: addr2,
expectedErr: errUpfrontShutdownScriptMismatch,
expectedErr: ErrUpfrontShutdownScriptMismatch,
},
{
name: "nil shutdown and empty upfront",

40
peer.go

@ -2114,7 +2114,7 @@ out:
// As the negotiations failed, we'll reset the
// channel state to ensure we act to on-chain
// events as normal.
chanCloser.cfg.channel.ResetState()
chanCloser.Channel().ResetState()
if chanCloser.CloseRequest() != nil {
chanCloser.CloseRequest().Err <- err
@ -2288,16 +2288,16 @@ func (p *peer) fetchActiveChanCloser(chanID lnwire.ChannelID) (*channelCloser, e
return nil, fmt.Errorf("cannot obtain best block")
}
chanCloser = newChannelCloser(
chanCloseCfg{
channel: channel,
unregisterChannel: p.server.htlcSwitch.RemoveLink,
broadcastTx: p.server.cc.wallet.PublishTransaction,
disableChannel: p.server.chanStatusMgr.RequestDisable,
disconnect: func() error {
chanCloser = NewChanCloser(
ChanCloseCfg{
Channel: channel,
UnregisterChannel: p.server.htlcSwitch.RemoveLink,
BroadcastTx: p.server.cc.wallet.PublishTransaction,
DisableChannel: p.server.chanStatusMgr.RequestDisable,
Disconnect: func() error {
return p.server.DisconnectPeer(p.IdentityKey())
},
quit: p.quit,
Quit: p.quit,
},
deliveryScript,
feePerKw,
@ -2334,7 +2334,7 @@ func chooseDeliveryScript(upfront,
// the upfront shutdown script (because closing out to a different script
// would violate upfront shutdown).
if !bytes.Equal(upfront, requested) {
return nil, errUpfrontShutdownScriptMismatch
return nil, ErrUpfrontShutdownScriptMismatch
}
// The user requested script matches the upfront shutdown script, so we
@ -2404,16 +2404,16 @@ func (p *peer) handleLocalCloseReq(req *htlcswitch.ChanClose) {
return
}
chanCloser := newChannelCloser(
chanCloseCfg{
channel: channel,
unregisterChannel: p.server.htlcSwitch.RemoveLink,
broadcastTx: p.server.cc.wallet.PublishTransaction,
disableChannel: p.server.chanStatusMgr.RequestDisable,
disconnect: func() error {
chanCloser := NewChanCloser(
ChanCloseCfg{
Channel: channel,
UnregisterChannel: p.server.htlcSwitch.RemoveLink,
BroadcastTx: p.server.cc.wallet.PublishTransaction,
DisableChannel: p.server.chanStatusMgr.RequestDisable,
Disconnect: func() error {
return p.server.DisconnectPeer(p.IdentityKey())
},
quit: p.quit,
Quit: p.quit,
},
deliveryScript,
req.TargetFeePerKw,
@ -2524,7 +2524,7 @@ func (p *peer) finalizeChanClosure(chanCloser *channelCloser) {
closeReq := chanCloser.CloseRequest()
// First, we'll clear all indexes related to the channel in question.
chanPoint := chanCloser.cfg.channel.ChannelPoint()
chanPoint := chanCloser.Channel().ChannelPoint()
p.WipeChannel(chanPoint)
// Next, we'll launch a goroutine which will request to be notified by
@ -2558,7 +2558,7 @@ func (p *peer) finalizeChanClosure(chanCloser *channelCloser) {
}
}
go waitForChanToClose(chanCloser.negotiationHeight, notifier, errChan,
go waitForChanToClose(chanCloser.NegotiationHeight(), notifier, errChan,
chanPoint, &closingTxid, closingTx.TxOut[0].PkScript, func() {
// Respond to the local subsystem which requested the

@ -642,7 +642,7 @@ func TestChooseDeliveryScript(t *testing.T) {
userScript: script1,
shutdownScript: script2,
expectedScript: nil,
expectedError: errUpfrontShutdownScriptMismatch,
expectedError: ErrUpfrontShutdownScriptMismatch,
},
{
name: "Only upfront script",
@ -733,7 +733,7 @@ func TestCustomShutdownScript(t *testing.T) {
name: "Shutdown set, user script different",
update: setShutdown,
userCloseScript: []byte("different addr"),
expectedError: errUpfrontShutdownScriptMismatch,
expectedError: ErrUpfrontShutdownScriptMismatch,
},
}