multi: send channel update with disabled active on force and coop chan closes
This commit is contained in:
parent
191e111661
commit
873cccc7a6
@ -78,6 +78,10 @@ type chanCloseCfg struct {
|
|||||||
// broadcastTx broadcasts the passed transaction to the network.
|
// broadcastTx broadcasts the passed transaction to the network.
|
||||||
broadcastTx func(*wire.MsgTx) error
|
broadcastTx func(*wire.MsgTx) error
|
||||||
|
|
||||||
|
// disableChannel disables a channel, resulting in it not being able to
|
||||||
|
// forward payments.
|
||||||
|
disableChannel func(wire.OutPoint) 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.
|
// machine should cease all progress and shutdown.
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
@ -436,6 +440,16 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll attempt to disable the channel in the background to
|
||||||
|
// avoid blocking due to sending the update message to all
|
||||||
|
// active peers.
|
||||||
|
go func() {
|
||||||
|
if err := c.cfg.disableChannel(c.chanPoint); err != nil {
|
||||||
|
peerLog.Errorf("Unable to disable channel %v on "+
|
||||||
|
"close: %v", c.chanPoint, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Finally, we'll transition to the closeFinished state, and
|
// Finally, we'll transition to the closeFinished state, and
|
||||||
// also return the final close signed message we sent.
|
// also return the final close signed message we sent.
|
||||||
// Additionally, we return true for the second argument to
|
// Additionally, we return true for the second argument to
|
||||||
|
@ -122,6 +122,10 @@ type ChainArbitratorConfig struct {
|
|||||||
|
|
||||||
// ChainIO allows us to query the state of the current main chain.
|
// ChainIO allows us to query the state of the current main chain.
|
||||||
ChainIO lnwallet.BlockChainIO
|
ChainIO lnwallet.BlockChainIO
|
||||||
|
|
||||||
|
// DisableChannel disables a channel, resulting in it not being able to
|
||||||
|
// forward payments.
|
||||||
|
DisableChannel func(wire.OutPoint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainArbitrator is a sub-system that oversees the on-chain resolution of all
|
// ChainArbitrator is a sub-system that oversees the on-chain resolution of all
|
||||||
@ -667,6 +671,16 @@ func (c *ChainArbitrator) ForceCloseContract(chanPoint wire.OutPoint) (*wire.Msg
|
|||||||
return nil, fmt.Errorf("ChainArbitrator shutting down")
|
return nil, fmt.Errorf("ChainArbitrator shutting down")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll attempt to disable the channel in the background to
|
||||||
|
// avoid blocking due to sending the update message to all
|
||||||
|
// active peers.
|
||||||
|
go func() {
|
||||||
|
if err := c.cfg.DisableChannel(chanPoint); err != nil {
|
||||||
|
log.Errorf("Unable to disable channel %v on "+
|
||||||
|
"close: %v", chanPoint, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return closeTx, nil
|
return closeTx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
peer.go
30
peer.go
@ -1677,6 +1677,7 @@ func (p *peer) fetchActiveChanCloser(chanID lnwire.ChannelID) (*channelCloser, e
|
|||||||
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,
|
||||||
|
disableChannel: p.server.disableChannel,
|
||||||
quit: p.quit,
|
quit: p.quit,
|
||||||
},
|
},
|
||||||
deliveryAddr,
|
deliveryAddr,
|
||||||
@ -1733,11 +1734,13 @@ func (p *peer) handleLocalCloseReq(req *htlcswitch.ChanClose) {
|
|||||||
req.Err <- err
|
req.Err <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
chanCloser := newChannelCloser(
|
chanCloser := newChannelCloser(
|
||||||
chanCloseCfg{
|
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,
|
||||||
|
disableChannel: p.server.disableChannel,
|
||||||
quit: p.quit,
|
quit: p.quit,
|
||||||
},
|
},
|
||||||
deliveryAddr,
|
deliveryAddr,
|
||||||
@ -2013,8 +2016,8 @@ func fetchLastChanUpdate(s *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if edge1 == nil || edge2 == nil {
|
if edge1 == nil || edge2 == nil {
|
||||||
return nil, errors.Errorf("unable to find "+
|
return nil, fmt.Errorf("unable to find channel by "+
|
||||||
"channel by ShortChannelID(%v)", cid)
|
"ShortChannelID(%v)", cid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're the outgoing node on the first edge, then that
|
// If we're the outgoing node on the first edge, then that
|
||||||
@ -2027,27 +2030,6 @@ func fetchLastChanUpdate(s *server,
|
|||||||
local = edge1
|
local = edge1
|
||||||
}
|
}
|
||||||
|
|
||||||
update := lnwire.ChannelUpdate{
|
return extractChannelUpdate(info, local)
|
||||||
ChainHash: info.ChainHash,
|
|
||||||
ShortChannelID: lnwire.NewShortChanIDFromInt(local.ChannelID),
|
|
||||||
Timestamp: uint32(local.LastUpdate.Unix()),
|
|
||||||
Flags: local.Flags,
|
|
||||||
TimeLockDelta: local.TimeLockDelta,
|
|
||||||
HtlcMinimumMsat: local.MinHTLC,
|
|
||||||
BaseFee: uint32(local.FeeBaseMSat),
|
|
||||||
FeeRate: uint32(local.FeeProportionalMillionths),
|
|
||||||
}
|
|
||||||
update.Signature, err = lnwire.NewSigFromRawSignature(local.SigBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hswcLog.Tracef("Sending latest channel_update: %v",
|
|
||||||
newLogClosure(func() string {
|
|
||||||
return spew.Sdump(update)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return &update, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
server.go
120
server.go
@ -661,6 +661,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
return ErrServerShuttingDown
|
return ErrServerShuttingDown
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
DisableChannel: s.disableChannel,
|
||||||
}, chanDB)
|
}, chanDB)
|
||||||
|
|
||||||
s.breachArbiter = newBreachArbiter(&BreachConfig{
|
s.breachArbiter = newBreachArbiter(&BreachConfig{
|
||||||
@ -2588,3 +2589,122 @@ func (s *server) fetchNodeAdvertisedAddr(pub *btcec.PublicKey) (net.Addr, error)
|
|||||||
|
|
||||||
return node.Addresses[0], nil
|
return node.Addresses[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disableChannel disables a channel, resulting in it not being able to forward
|
||||||
|
// payments. This is done by sending a new channel update across the network
|
||||||
|
// with the disabled flag set.
|
||||||
|
func (s *server) disableChannel(op wire.OutPoint) error {
|
||||||
|
// Retrieve the latest update for this channel. We'll use this
|
||||||
|
// as our starting point to send the new update.
|
||||||
|
chanUpdate, err := s.fetchLastChanUpdateByOutPoint(op)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the bit responsible for marking a channel as disabled.
|
||||||
|
chanUpdate.Flags |= lnwire.ChanUpdateDisabled
|
||||||
|
|
||||||
|
// We must now update the message's timestamp and generate a new
|
||||||
|
// signature.
|
||||||
|
chanUpdate.Timestamp = uint32(time.Now().Unix())
|
||||||
|
|
||||||
|
chanUpdateMsg, err := chanUpdate.DataToSign()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKey := s.identityPriv.PubKey()
|
||||||
|
sig, err := s.nodeSigner.SignMessage(pubKey, chanUpdateMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chanUpdate.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once signed, we'll send the new update to all of our peers.
|
||||||
|
return s.applyChannelUpdate(chanUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchLastChanUpdateByOutPoint fetches the latest update for a channel from
|
||||||
|
// our point of view.
|
||||||
|
func (s *server) fetchLastChanUpdateByOutPoint(op wire.OutPoint) (*lnwire.ChannelUpdate, error) {
|
||||||
|
graph := s.chanDB.ChannelGraph()
|
||||||
|
info, edge1, edge2, err := graph.FetchChannelEdgesByOutpoint(&op)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if edge1 == nil || edge2 == nil {
|
||||||
|
return nil, fmt.Errorf("unable to find channel(%v)", op)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're the outgoing node on the first edge, then that
|
||||||
|
// means the second edge is our policy. Otherwise, the first
|
||||||
|
// edge is our policy.
|
||||||
|
var local *channeldb.ChannelEdgePolicy
|
||||||
|
|
||||||
|
ourPubKey := s.identityPriv.PubKey().SerializeCompressed()
|
||||||
|
if bytes.Equal(edge1.Node.PubKeyBytes[:], ourPubKey) {
|
||||||
|
local = edge2
|
||||||
|
} else {
|
||||||
|
local = edge1
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractChannelUpdate(info, local)
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractChannelUpdate retrieves a lnwire.ChannelUpdate message from an edge's
|
||||||
|
// info and routing policy.
|
||||||
|
func extractChannelUpdate(info *channeldb.ChannelEdgeInfo,
|
||||||
|
policy *channeldb.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) {
|
||||||
|
|
||||||
|
update := &lnwire.ChannelUpdate{
|
||||||
|
ChainHash: info.ChainHash,
|
||||||
|
ShortChannelID: lnwire.NewShortChanIDFromInt(policy.ChannelID),
|
||||||
|
Timestamp: uint32(policy.LastUpdate.Unix()),
|
||||||
|
Flags: policy.Flags,
|
||||||
|
TimeLockDelta: policy.TimeLockDelta,
|
||||||
|
HtlcMinimumMsat: policy.MinHTLC,
|
||||||
|
BaseFee: uint32(policy.FeeBaseMSat),
|
||||||
|
FeeRate: uint32(policy.FeeProportionalMillionths),
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
update.Signature, err = lnwire.NewSigFromRawSignature(policy.SigBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return update, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyChannelUpdate applies the channel update to the different sub-systems of
|
||||||
|
// the server.
|
||||||
|
func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate) error {
|
||||||
|
newChannelPolicy := &channeldb.ChannelEdgePolicy{
|
||||||
|
SigBytes: update.Signature.ToSignatureBytes(),
|
||||||
|
ChannelID: update.ShortChannelID.ToUint64(),
|
||||||
|
LastUpdate: time.Unix(int64(update.Timestamp), 0),
|
||||||
|
Flags: update.Flags,
|
||||||
|
TimeLockDelta: update.TimeLockDelta,
|
||||||
|
MinHTLC: update.HtlcMinimumMsat,
|
||||||
|
FeeBaseMSat: lnwire.MilliSatoshi(update.BaseFee),
|
||||||
|
FeeProportionalMillionths: lnwire.MilliSatoshi(update.FeeRate),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.chanRouter.UpdateEdge(newChannelPolicy)
|
||||||
|
if err != nil && !routing.IsError(err, routing.ErrIgnored) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKey := s.identityPriv.PubKey()
|
||||||
|
errChan := s.authGossiper.ProcessLocalAnnouncement(update, pubKey)
|
||||||
|
select {
|
||||||
|
case err := <-errChan:
|
||||||
|
return err
|
||||||
|
case <-s.quit:
|
||||||
|
return ErrServerShuttingDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user