mirror of
https://github.com/muun/recovery.git
synced 2025-11-10 22:10:14 -05:00
Release v0.3.0
This commit is contained in:
607
vendor/github.com/lightningnetwork/lnd/netann/chan_status_manager.go
generated
vendored
Normal file
607
vendor/github.com/lightningnetwork/lnd/netann/chan_status_manager.go
generated
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrChanStatusManagerExiting signals that a shutdown of the
|
||||
// ChanStatusManager has already been requested.
|
||||
ErrChanStatusManagerExiting = errors.New("chan status manager exiting")
|
||||
|
||||
// ErrInvalidTimeoutConstraints signals that the ChanStatusManager could
|
||||
// not be initialized because the timeouts and sample intervals were
|
||||
// malformed.
|
||||
ErrInvalidTimeoutConstraints = errors.New("active_timeout + " +
|
||||
"sample_interval must be less than or equal to " +
|
||||
"inactive_timeout and be positive integers")
|
||||
|
||||
// ErrEnableInactiveChan signals that a request to enable a channel
|
||||
// could not be completed because the channel isn't actually active at
|
||||
// the time of the request.
|
||||
ErrEnableInactiveChan = errors.New("unable to enable channel which " +
|
||||
"is not currently active")
|
||||
)
|
||||
|
||||
// ChanStatusConfig holds parameters and resources required by the
|
||||
// ChanStatusManager to perform its duty.
|
||||
type ChanStatusConfig struct {
|
||||
// OurPubKey is the public key identifying this node on the network.
|
||||
OurPubKey *btcec.PublicKey
|
||||
|
||||
// MessageSigner signs messages that validate under OurPubKey.
|
||||
MessageSigner lnwallet.MessageSigner
|
||||
|
||||
// IsChannelActive checks whether the channel identified by the provided
|
||||
// ChannelID is considered active. This should only return true if the
|
||||
// channel has been sufficiently confirmed, the channel has received
|
||||
// FundingLocked, and the remote peer is online.
|
||||
IsChannelActive func(lnwire.ChannelID) bool
|
||||
|
||||
// ApplyChannelUpdate processes new ChannelUpdates signed by our node by
|
||||
// updating our local routing table and broadcasting the update to our
|
||||
// peers.
|
||||
ApplyChannelUpdate func(*lnwire.ChannelUpdate) error
|
||||
|
||||
// DB stores the set of channels that are to be monitored.
|
||||
DB DB
|
||||
|
||||
// Graph stores the channel info and policies for channels in DB.
|
||||
Graph ChannelGraph
|
||||
|
||||
// ChanEnableTimeout is the duration a peer's connect must remain stable
|
||||
// before attempting to reenable the channel.
|
||||
//
|
||||
// NOTE: This value is only used to verify that the relation between
|
||||
// itself, ChanDisableTimeout, and ChanStatusSampleInterval is correct.
|
||||
// The user is still responsible for ensuring that the same duration
|
||||
// elapses before attempting to reenable a channel.
|
||||
ChanEnableTimeout time.Duration
|
||||
|
||||
// ChanDisableTimeout is the duration the manager will wait after
|
||||
// detecting that a channel has become inactive before broadcasting an
|
||||
// update to disable the channel.
|
||||
ChanDisableTimeout time.Duration
|
||||
|
||||
// ChanStatusSampleInterval is the long-polling interval used by the
|
||||
// manager to check if the channels being monitored have become
|
||||
// inactive.
|
||||
ChanStatusSampleInterval time.Duration
|
||||
}
|
||||
|
||||
// ChanStatusManager facilitates requests to enable or disable a channel via a
|
||||
// network announcement that sets the disable bit on the ChannelUpdate
|
||||
// accordingly. The manager will periodically sample to detect cases where a
|
||||
// link has become inactive, and facilitate the process of disabling the channel
|
||||
// passively. The ChanStatusManager state machine is designed to reduce the
|
||||
// likelihood of spamming the network with updates for flapping peers.
|
||||
type ChanStatusManager struct {
|
||||
started sync.Once
|
||||
stopped sync.Once
|
||||
|
||||
cfg *ChanStatusConfig
|
||||
|
||||
// ourPubKeyBytes is the serialized compressed pubkey of our node.
|
||||
ourPubKeyBytes []byte
|
||||
|
||||
// chanStates contains the set of channels being monitored for status
|
||||
// updates. Access to the map is serialized by the statusManager's event
|
||||
// loop.
|
||||
chanStates channelStates
|
||||
|
||||
// enableRequests pipes external requests to enable a channel into the
|
||||
// primary event loop.
|
||||
enableRequests chan statusRequest
|
||||
|
||||
// disableRequests pipes external requests to disable a channel into the
|
||||
// primary event loop.
|
||||
disableRequests chan statusRequest
|
||||
|
||||
// statusSampleTicker fires at the interval prescribed by
|
||||
// ChanStatusSampleInterval to check if channels in chanStates have
|
||||
// become inactive.
|
||||
statusSampleTicker *time.Ticker
|
||||
|
||||
wg sync.WaitGroup
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// NewChanStatusManager initializes a new ChanStatusManager using the given
|
||||
// configuration. An error is returned if the timeouts and sample interval fail
|
||||
// to meet do not satisfy the equation:
|
||||
// ChanEnableTimeout + ChanStatusSampleInterval > ChanDisableTimeout.
|
||||
func NewChanStatusManager(cfg *ChanStatusConfig) (*ChanStatusManager, error) {
|
||||
// Assert that the config timeouts are properly formed. We require the
|
||||
// enable_timeout + sample_interval to be less than or equal to the
|
||||
// disable_timeout and that all are positive values. A peer that
|
||||
// disconnects and reconnects quickly may cause a disable update to be
|
||||
// sent, shortly followed by a reenable. Ensuring a healthy separation
|
||||
// helps dampen the possibility of spamming updates that toggle the
|
||||
// disable bit for such events.
|
||||
if cfg.ChanStatusSampleInterval <= 0 {
|
||||
return nil, ErrInvalidTimeoutConstraints
|
||||
}
|
||||
if cfg.ChanEnableTimeout <= 0 {
|
||||
return nil, ErrInvalidTimeoutConstraints
|
||||
}
|
||||
if cfg.ChanDisableTimeout <= 0 {
|
||||
return nil, ErrInvalidTimeoutConstraints
|
||||
}
|
||||
if cfg.ChanEnableTimeout+cfg.ChanStatusSampleInterval >
|
||||
cfg.ChanDisableTimeout {
|
||||
return nil, ErrInvalidTimeoutConstraints
|
||||
|
||||
}
|
||||
|
||||
return &ChanStatusManager{
|
||||
cfg: cfg,
|
||||
ourPubKeyBytes: cfg.OurPubKey.SerializeCompressed(),
|
||||
chanStates: make(channelStates),
|
||||
statusSampleTicker: time.NewTicker(cfg.ChanStatusSampleInterval),
|
||||
enableRequests: make(chan statusRequest),
|
||||
disableRequests: make(chan statusRequest),
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start safely starts the ChanStatusManager.
|
||||
func (m *ChanStatusManager) Start() error {
|
||||
var err error
|
||||
m.started.Do(func() {
|
||||
err = m.start()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *ChanStatusManager) start() error {
|
||||
channels, err := m.fetchChannels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Populate the initial states of all confirmed, public channels.
|
||||
for _, c := range channels {
|
||||
_, err := m.getOrInitChanStatus(c.FundingOutpoint)
|
||||
switch {
|
||||
|
||||
// If we can't retrieve the edge info for this channel, it may
|
||||
// have been pruned from the channel graph but not yet from our
|
||||
// set of channels. We'll skip it as we can't determine its
|
||||
// initial state.
|
||||
case err == channeldb.ErrEdgeNotFound:
|
||||
log.Warnf("Unable to find channel policies for %v, "+
|
||||
"skipping. This is typical if the channel is "+
|
||||
"in the process of closing.", c.FundingOutpoint)
|
||||
continue
|
||||
|
||||
case err != nil:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.wg.Add(1)
|
||||
go m.statusManager()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop safely shuts down the ChanStatusManager.
|
||||
func (m *ChanStatusManager) Stop() error {
|
||||
m.stopped.Do(func() {
|
||||
close(m.quit)
|
||||
m.wg.Wait()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestEnable submits a request to immediately enable a channel identified by
|
||||
// the provided outpoint. If the channel is already enabled, no action will be
|
||||
// taken. If the channel is marked pending-disable the channel will be returned
|
||||
// to an active status as the scheduled disable was never sent. Otherwise if the
|
||||
// channel is found to be disabled, a new announcement will be signed with the
|
||||
// disabled bit cleared and broadcast to the network.
|
||||
//
|
||||
// NOTE: RequestEnable should only be called after a stable connection with the
|
||||
// channel's peer has lasted at least the ChanEnableTimeout. Failure to do so
|
||||
// may result in behavior that deviates from the expected behavior of the state
|
||||
// machine.
|
||||
func (m *ChanStatusManager) RequestEnable(outpoint wire.OutPoint) error {
|
||||
return m.submitRequest(m.enableRequests, outpoint)
|
||||
}
|
||||
|
||||
// RequestDisable submits a request to immediately disable a channel identified
|
||||
// by the provided outpoint. If the channel is already disabled, no action will
|
||||
// be taken. Otherwise, a new announcement will be signed with the disabled bit
|
||||
// set and broadcast to the network.
|
||||
func (m *ChanStatusManager) RequestDisable(outpoint wire.OutPoint) error {
|
||||
return m.submitRequest(m.disableRequests, outpoint)
|
||||
}
|
||||
|
||||
// statusRequest is passed to the statusManager to request a change in status
|
||||
// for a particular channel point. The exact action is governed by passing the
|
||||
// request through one of the enableRequests or disableRequests channels.
|
||||
type statusRequest struct {
|
||||
outpoint wire.OutPoint
|
||||
errChan chan error
|
||||
}
|
||||
|
||||
// submitRequest sends a request for either enabling or disabling a particular
|
||||
// outpoint and awaits an error response. The request type is dictated by the
|
||||
// reqChan passed in, which can be either of the enableRequests or
|
||||
// disableRequests channels.
|
||||
func (m *ChanStatusManager) submitRequest(reqChan chan statusRequest,
|
||||
outpoint wire.OutPoint) error {
|
||||
|
||||
req := statusRequest{
|
||||
outpoint: outpoint,
|
||||
errChan: make(chan error, 1),
|
||||
}
|
||||
|
||||
select {
|
||||
case reqChan <- req:
|
||||
case <-m.quit:
|
||||
return ErrChanStatusManagerExiting
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-req.errChan:
|
||||
return err
|
||||
case <-m.quit:
|
||||
return ErrChanStatusManagerExiting
|
||||
}
|
||||
}
|
||||
|
||||
// statusManager is the primary event loop for the ChanStatusManager, providing
|
||||
// the necessary synchronization primitive to protect access to the chanStates
|
||||
// map. All requests to explicitly enable or disable a channel are processed
|
||||
// within this method. The statusManager will also periodically poll the active
|
||||
// status of channels within the htlcswitch to see if a disable announcement
|
||||
// should be scheduled or broadcast.
|
||||
//
|
||||
// NOTE: This method MUST be run as a goroutine.
|
||||
func (m *ChanStatusManager) statusManager() {
|
||||
defer m.wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
// Process any requests to mark channel as enabled.
|
||||
case req := <-m.enableRequests:
|
||||
req.errChan <- m.processEnableRequest(req.outpoint)
|
||||
|
||||
// Process any requests to mark channel as disabled.
|
||||
case req := <-m.disableRequests:
|
||||
req.errChan <- m.processDisableRequest(req.outpoint)
|
||||
|
||||
// Use long-polling to detect when channels become inactive.
|
||||
case <-m.statusSampleTicker.C:
|
||||
// First, do a sweep and mark any ChanStatusEnabled
|
||||
// channels that are not active within the htlcswitch as
|
||||
// ChanStatusPendingDisabled. The channel will then be
|
||||
// disabled if no request to enable is received before
|
||||
// the ChanDisableTimeout expires.
|
||||
m.markPendingInactiveChannels()
|
||||
|
||||
// Now, do another sweep to disable any channels that
|
||||
// were marked in a prior iteration as pending inactive
|
||||
// if the inactive chan timeout has elapsed.
|
||||
m.disableInactiveChannels()
|
||||
|
||||
case <-m.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processEnableRequest attempts to enable the given outpoint. If the method
|
||||
// returns nil, the status of the channel in chanStates will be
|
||||
// ChanStatusEnabled. If the channel is not active at the time of the request,
|
||||
// ErrEnableInactiveChan will be returned. An update will be broadcast only if
|
||||
// the channel is currently disabled, otherwise no update will be sent on the
|
||||
// network.
|
||||
func (m *ChanStatusManager) processEnableRequest(outpoint wire.OutPoint) error {
|
||||
curState, err := m.getOrInitChanStatus(outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Quickly check to see if the requested channel is active within the
|
||||
// htlcswitch and return an error if it isn't.
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&outpoint)
|
||||
if !m.cfg.IsChannelActive(chanID) {
|
||||
return ErrEnableInactiveChan
|
||||
}
|
||||
|
||||
switch curState.Status {
|
||||
|
||||
// Channel is already enabled, nothing to do.
|
||||
case ChanStatusEnabled:
|
||||
return nil
|
||||
|
||||
// The channel is enabled, though we are now canceling the scheduled
|
||||
// disable.
|
||||
case ChanStatusPendingDisabled:
|
||||
log.Debugf("Channel(%v) already enabled, canceling scheduled "+
|
||||
"disable", outpoint)
|
||||
|
||||
// We'll sign a new update if the channel is still disabled.
|
||||
case ChanStatusDisabled:
|
||||
log.Infof("Announcing channel(%v) enabled", outpoint)
|
||||
|
||||
err := m.signAndSendNextUpdate(outpoint, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.chanStates.markEnabled(outpoint)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processDisableRequest attempts to disable the given outpoint. If the method
|
||||
// returns nil, the status of the channel in chanStates will be
|
||||
// ChanStatusDisabled. An update will only be sent if the channel has a status
|
||||
// other than ChanStatusEnabled, otherwise no update will be sent on the
|
||||
// network.
|
||||
func (m *ChanStatusManager) processDisableRequest(outpoint wire.OutPoint) error {
|
||||
curState, err := m.getOrInitChanStatus(outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch curState.Status {
|
||||
|
||||
// Channel is already disabled, nothing to do.
|
||||
case ChanStatusDisabled:
|
||||
return nil
|
||||
|
||||
// We'll sign a new update disabling the channel if the current status
|
||||
// is enabled or pending-inactive.
|
||||
case ChanStatusEnabled, ChanStatusPendingDisabled:
|
||||
log.Infof("Announcing channel(%v) disabled [requested]",
|
||||
outpoint)
|
||||
|
||||
err := m.signAndSendNextUpdate(outpoint, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If the disable was requested via the manager's public interface, we
|
||||
// will remove the output from our map of channel states. Typically this
|
||||
// signals that the channel is being closed, so this frees up the space
|
||||
// in the map. If for some reason the channel isn't closed, the state
|
||||
// will be repopulated on subsequent calls to RequestEnable or
|
||||
// RequestDisable via a db lookup, or on startup.
|
||||
delete(m.chanStates, outpoint)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// markPendingInactiveChannels performs a sweep of the database's active
|
||||
// channels and determines which, if any, should have a disable announcement
|
||||
// scheduled. Once an active channel is determined to be pending-inactive, one
|
||||
// of two transitions can follow. Either the channel is disabled because no
|
||||
// request to enable is received before the scheduled disable is broadcast, or
|
||||
// the channel is successfully reenabled and channel is returned to an active
|
||||
// state from the POV of the ChanStatusManager.
|
||||
func (m *ChanStatusManager) markPendingInactiveChannels() {
|
||||
channels, err := m.fetchChannels()
|
||||
if err != nil {
|
||||
log.Errorf("Unable to load active channels: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, c := range channels {
|
||||
// Determine the initial status of the active channel, and
|
||||
// populate the entry in the chanStates map.
|
||||
curState, err := m.getOrInitChanStatus(c.FundingOutpoint)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to retrieve chan status for "+
|
||||
"Channel(%v): %v", c.FundingOutpoint, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// If the channel's status is not ChanStatusEnabled, we are
|
||||
// done. Either it is already disabled, or it has been marked
|
||||
// ChanStatusPendingDisable meaning that we have already
|
||||
// scheduled the time at which it will be disabled.
|
||||
if curState.Status != ChanStatusEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
// If our bookkeeping shows the channel as active, sample the
|
||||
// htlcswitch to see if it believes the link is also active. If
|
||||
// so, we will skip marking it as ChanStatusPendingDisabled.
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&c.FundingOutpoint)
|
||||
if m.cfg.IsChannelActive(chanID) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, we discovered that this link was inactive within
|
||||
// the switch. Compute the time at which we will send out a
|
||||
// disable if the peer is unable to reestablish a stable
|
||||
// connection.
|
||||
disableTime := time.Now().Add(m.cfg.ChanDisableTimeout)
|
||||
|
||||
log.Debugf("Marking channel(%v) pending-inactive",
|
||||
c.FundingOutpoint)
|
||||
|
||||
m.chanStates.markPendingDisabled(c.FundingOutpoint, disableTime)
|
||||
}
|
||||
}
|
||||
|
||||
// disableInactiveChannels scans through the set of monitored channels, and
|
||||
// broadcast a disable update for any pending inactive channels whose
|
||||
// SendDisableTime has been superseded by the current time.
|
||||
func (m *ChanStatusManager) disableInactiveChannels() {
|
||||
// Now, disable any channels whose inactive chan timeout has elapsed.
|
||||
now := time.Now()
|
||||
for outpoint, state := range m.chanStates {
|
||||
// Ignore statuses that are not in the pending-inactive state.
|
||||
if state.Status != ChanStatusPendingDisabled {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ignore statuses for which the disable timeout has not
|
||||
// expired.
|
||||
if state.SendDisableTime.After(now) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("Announcing channel(%v) disabled "+
|
||||
"[detected]", outpoint)
|
||||
|
||||
// Sign an update disabling the channel.
|
||||
err := m.signAndSendNextUpdate(outpoint, true)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to sign update disabling "+
|
||||
"channel(%v): %v", outpoint, err)
|
||||
|
||||
// If the edge was not found, this is a likely indicator
|
||||
// that the channel has been closed. Thus we remove the
|
||||
// outpoint from the set of tracked outpoints to prevent
|
||||
// further attempts.
|
||||
if err == channeldb.ErrEdgeNotFound {
|
||||
log.Debugf("Removing channel(%v) from "+
|
||||
"consideration for passive disabling",
|
||||
outpoint)
|
||||
delete(m.chanStates, outpoint)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Record that the channel has now been disabled.
|
||||
m.chanStates.markDisabled(outpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// fetchChannels returns the working set of channels managed by the
|
||||
// ChanStatusManager. The returned channels are filtered to only contain public
|
||||
// channels.
|
||||
func (m *ChanStatusManager) fetchChannels() ([]*channeldb.OpenChannel, error) {
|
||||
allChannels, err := m.cfg.DB.FetchAllOpenChannels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Filter out private channels.
|
||||
var channels []*channeldb.OpenChannel
|
||||
for _, c := range allChannels {
|
||||
// We'll skip any private channels, as they aren't used for
|
||||
// routing within the network by other nodes.
|
||||
if c.ChannelFlags&lnwire.FFAnnounceChannel == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
channels = append(channels, c)
|
||||
}
|
||||
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
// signAndSendNextUpdate computes and signs a valid update for the passed
|
||||
// outpoint, with the ability to toggle the disabled bit. The new update will
|
||||
// use the current time as the update's timestamp, or increment the old
|
||||
// timestamp by 1 to ensure the update can propagate. If signing is successful,
|
||||
// the new update will be sent out on the network.
|
||||
func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint,
|
||||
disabled bool) error {
|
||||
|
||||
// Retrieve the latest update for this channel. We'll use this
|
||||
// as our starting point to send the new update.
|
||||
chanUpdate, err := m.fetchLastChanUpdateByOutPoint(outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = SignChannelUpdate(
|
||||
m.cfg.MessageSigner, m.cfg.OurPubKey, chanUpdate,
|
||||
ChanUpdSetDisable(disabled), ChanUpdSetTimestamp,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.cfg.ApplyChannelUpdate(chanUpdate)
|
||||
}
|
||||
|
||||
// fetchLastChanUpdateByOutPoint fetches the latest policy for our direction of
|
||||
// a channel, and crafts a new ChannelUpdate with this policy. Returns an error
|
||||
// in case our ChannelEdgePolicy is not found in the database.
|
||||
func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) (
|
||||
*lnwire.ChannelUpdate, error) {
|
||||
|
||||
// Get the edge info and policies for this channel from the graph.
|
||||
info, edge1, edge2, err := m.cfg.Graph.FetchChannelEdgesByOutpoint(&op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ExtractChannelUpdate(m.ourPubKeyBytes, info, edge1, edge2)
|
||||
}
|
||||
|
||||
// loadInitialChanState determines the initial ChannelState for a particular
|
||||
// outpoint. The initial ChanStatus for a given outpoint will either be
|
||||
// ChanStatusEnabled or ChanStatusDisabled, determined by inspecting the bits on
|
||||
// the most recent announcement. An error is returned if the latest update could
|
||||
// not be retrieved.
|
||||
func (m *ChanStatusManager) loadInitialChanState(
|
||||
outpoint *wire.OutPoint) (ChannelState, error) {
|
||||
|
||||
lastUpdate, err := m.fetchLastChanUpdateByOutPoint(*outpoint)
|
||||
if err != nil {
|
||||
return ChannelState{}, err
|
||||
}
|
||||
|
||||
// Determine the channel's starting status by inspecting the disable bit
|
||||
// on last announcement we sent out.
|
||||
var initialStatus ChanStatus
|
||||
if lastUpdate.ChannelFlags&lnwire.ChanUpdateDisabled == 0 {
|
||||
initialStatus = ChanStatusEnabled
|
||||
} else {
|
||||
initialStatus = ChanStatusDisabled
|
||||
}
|
||||
|
||||
return ChannelState{
|
||||
Status: initialStatus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getOrInitChanStatus retrieves the current ChannelState for a particular
|
||||
// outpoint. If the chanStates map already contains an entry for the outpoint,
|
||||
// the value in the map is returned. Otherwise, the outpoint's initial status is
|
||||
// computed and updated in the chanStates map before being returned.
|
||||
func (m *ChanStatusManager) getOrInitChanStatus(
|
||||
outpoint wire.OutPoint) (ChannelState, error) {
|
||||
|
||||
// Return the current ChannelState from the chanStates map if it is
|
||||
// already known to the ChanStatusManager.
|
||||
if curState, ok := m.chanStates[outpoint]; ok {
|
||||
return curState, nil
|
||||
}
|
||||
|
||||
// Otherwise, determine the initial state based on the last update we
|
||||
// sent for the outpoint.
|
||||
initialState, err := m.loadInitialChanState(&outpoint)
|
||||
if err != nil {
|
||||
return ChannelState{}, err
|
||||
}
|
||||
|
||||
// Finally, store the initial state in the chanStates map. This will
|
||||
// serve as are up-to-date view of the outpoint's current status, in
|
||||
// addition to making the channel eligible for detecting inactivity.
|
||||
m.chanStates[outpoint] = initialState
|
||||
|
||||
return initialState, nil
|
||||
}
|
||||
86
vendor/github.com/lightningnetwork/lnd/netann/channel_announcement.go
generated
vendored
Normal file
86
vendor/github.com/lightningnetwork/lnd/netann/channel_announcement.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// CreateChanAnnouncement is a helper function which creates all channel
|
||||
// announcements given the necessary channel related database items. This
|
||||
// function is used to transform out database structs into the corresponding wire
|
||||
// structs for announcing new channels to other peers, or simply syncing up a
|
||||
// peer's initial routing table upon connect.
|
||||
func CreateChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
|
||||
chanInfo *channeldb.ChannelEdgeInfo,
|
||||
e1, e2 *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement,
|
||||
*lnwire.ChannelUpdate, *lnwire.ChannelUpdate, error) {
|
||||
|
||||
// First, using the parameters of the channel, along with the channel
|
||||
// authentication chanProof, we'll create re-create the original
|
||||
// authenticated channel announcement.
|
||||
chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
|
||||
chanAnn := &lnwire.ChannelAnnouncement{
|
||||
ShortChannelID: chanID,
|
||||
NodeID1: chanInfo.NodeKey1Bytes,
|
||||
NodeID2: chanInfo.NodeKey2Bytes,
|
||||
ChainHash: chanInfo.ChainHash,
|
||||
BitcoinKey1: chanInfo.BitcoinKey1Bytes,
|
||||
BitcoinKey2: chanInfo.BitcoinKey2Bytes,
|
||||
Features: lnwire.NewRawFeatureVector(),
|
||||
ExtraOpaqueData: chanInfo.ExtraOpaqueData,
|
||||
}
|
||||
|
||||
err := chanAnn.Features.Decode(bytes.NewReader(chanInfo.Features))
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
chanAnn.BitcoinSig1, err = lnwire.NewSigFromRawSignature(
|
||||
chanProof.BitcoinSig1Bytes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
chanAnn.BitcoinSig2, err = lnwire.NewSigFromRawSignature(
|
||||
chanProof.BitcoinSig2Bytes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
chanAnn.NodeSig1, err = lnwire.NewSigFromRawSignature(
|
||||
chanProof.NodeSig1Bytes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
chanAnn.NodeSig2, err = lnwire.NewSigFromRawSignature(
|
||||
chanProof.NodeSig2Bytes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// We'll unconditionally queue the channel's existence chanProof as it
|
||||
// will need to be processed before either of the channel update
|
||||
// networkMsgs.
|
||||
|
||||
// Since it's up to a node's policy as to whether they advertise the
|
||||
// edge in a direction, we don't create an advertisement if the edge is
|
||||
// nil.
|
||||
var edge1Ann, edge2Ann *lnwire.ChannelUpdate
|
||||
if e1 != nil {
|
||||
edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
if e2 != nil {
|
||||
edge2Ann, err = ChannelUpdateFromEdge(chanInfo, e2)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return chanAnn, edge1Ann, edge2Ann, nil
|
||||
}
|
||||
75
vendor/github.com/lightningnetwork/lnd/netann/channel_state.go
generated
vendored
Normal file
75
vendor/github.com/lightningnetwork/lnd/netann/channel_state.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
// ChanStatus is a type that enumerates the possible states a ChanStatusManager
|
||||
// tracks for its known channels.
|
||||
type ChanStatus uint8
|
||||
|
||||
const (
|
||||
// ChanStatusEnabled indicates that the channel's last announcement has
|
||||
// the disabled bit cleared.
|
||||
ChanStatusEnabled ChanStatus = iota
|
||||
|
||||
// ChanStatusPendingDisabled indicates that the channel's last
|
||||
// announcement has the disabled bit cleared, but that the channel was
|
||||
// detected in an inactive state. Channels in this state will have a
|
||||
// disabling announcement sent after the ChanInactiveTimeout expires
|
||||
// from the time of the first detection--unless the channel is
|
||||
// explicitly reenabled before the disabling occurs.
|
||||
ChanStatusPendingDisabled
|
||||
|
||||
// ChanStatusDisabled indicates that the channel's last announcement has
|
||||
// the disabled bit set.
|
||||
ChanStatusDisabled
|
||||
)
|
||||
|
||||
// ChannelState describes the ChanStatusManager's view of a channel, and
|
||||
// describes the current state the channel's disabled status on the network.
|
||||
type ChannelState struct {
|
||||
// Status is the channel's current ChanStatus from the POV of the
|
||||
// ChanStatusManager.
|
||||
Status ChanStatus
|
||||
|
||||
// SendDisableTime is the earliest time at which the ChanStatusManager
|
||||
// will passively send a new disable announcement on behalf of this
|
||||
// channel.
|
||||
//
|
||||
// NOTE: This field is only non-zero if status is
|
||||
// ChanStatusPendingDisabled.
|
||||
SendDisableTime time.Time
|
||||
}
|
||||
|
||||
// channelStates is a map of channel outpoints to their channelState. All
|
||||
// changes made after setting an entry initially should be made using receiver
|
||||
// methods below.
|
||||
type channelStates map[wire.OutPoint]ChannelState
|
||||
|
||||
// markEnabled creates a channelState using ChanStatusEnabled.
|
||||
func (s *channelStates) markEnabled(outpoint wire.OutPoint) {
|
||||
(*s)[outpoint] = ChannelState{
|
||||
Status: ChanStatusEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
// markDisabled creates a channelState using ChanStatusDisabled.
|
||||
func (s *channelStates) markDisabled(outpoint wire.OutPoint) {
|
||||
(*s)[outpoint] = ChannelState{
|
||||
Status: ChanStatusDisabled,
|
||||
}
|
||||
}
|
||||
|
||||
// markPendingDisabled creates a channelState using ChanStatusPendingDisabled
|
||||
// and sets the ChannelState's SendDisableTime to sendDisableTime.
|
||||
func (s *channelStates) markPendingDisabled(outpoint wire.OutPoint,
|
||||
sendDisableTime time.Time) {
|
||||
|
||||
(*s)[outpoint] = ChannelState{
|
||||
Status: ChanStatusPendingDisabled,
|
||||
SendDisableTime: sendDisableTime,
|
||||
}
|
||||
}
|
||||
148
vendor/github.com/lightningnetwork/lnd/netann/channel_update.go
generated
vendored
Normal file
148
vendor/github.com/lightningnetwork/lnd/netann/channel_update.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// ChannelUpdateModifier is a closure that makes in-place modifications to an
|
||||
// lnwire.ChannelUpdate.
|
||||
type ChannelUpdateModifier func(*lnwire.ChannelUpdate)
|
||||
|
||||
// ChanUpdSetDisable is a functional option that sets the disabled channel flag
|
||||
// if disabled is true, and clears the bit otherwise.
|
||||
func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier {
|
||||
return func(update *lnwire.ChannelUpdate) {
|
||||
if disabled {
|
||||
// Set the bit responsible for marking a channel as
|
||||
// disabled.
|
||||
update.ChannelFlags |= lnwire.ChanUpdateDisabled
|
||||
} else {
|
||||
// Clear the bit responsible for marking a channel as
|
||||
// disabled.
|
||||
update.ChannelFlags &= ^lnwire.ChanUpdateDisabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChanUpdSetTimestamp is a functional option that sets the timestamp of the
|
||||
// update to the current time, or increments it if the timestamp is already in
|
||||
// the future.
|
||||
func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
|
||||
newTimestamp := uint32(time.Now().Unix())
|
||||
if newTimestamp <= update.Timestamp {
|
||||
// Increment the prior value to ensure the timestamp
|
||||
// monotonically increases, otherwise the update won't
|
||||
// propagate.
|
||||
newTimestamp = update.Timestamp + 1
|
||||
}
|
||||
update.Timestamp = newTimestamp
|
||||
}
|
||||
|
||||
// SignChannelUpdate applies the given modifiers to the passed
|
||||
// lnwire.ChannelUpdate, then signs the resulting update. The provided update
|
||||
// should be the most recent, valid update, otherwise the timestamp may not
|
||||
// monotonically increase from the prior.
|
||||
//
|
||||
// NOTE: This method modifies the given update.
|
||||
func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey,
|
||||
update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error {
|
||||
|
||||
// Apply the requested changes to the channel update.
|
||||
for _, modifier := range mods {
|
||||
modifier(update)
|
||||
}
|
||||
|
||||
// Create the DER-encoded ECDSA signature over the message digest.
|
||||
sig, err := SignAnnouncement(signer, pubKey, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the DER-encoded signature into a fixed-size 64-byte array.
|
||||
update.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractChannelUpdate attempts to retrieve a lnwire.ChannelUpdate message from
|
||||
// an edge's info and a set of routing policies.
|
||||
//
|
||||
// NOTE: The passed policies can be nil.
|
||||
func ExtractChannelUpdate(ownerPubKey []byte,
|
||||
info *channeldb.ChannelEdgeInfo,
|
||||
policies ...*channeldb.ChannelEdgePolicy) (
|
||||
*lnwire.ChannelUpdate, error) {
|
||||
|
||||
// Helper function to extract the owner of the given policy.
|
||||
owner := func(edge *channeldb.ChannelEdgePolicy) []byte {
|
||||
var pubKey *btcec.PublicKey
|
||||
if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
|
||||
pubKey, _ = info.NodeKey1()
|
||||
} else {
|
||||
pubKey, _ = info.NodeKey2()
|
||||
}
|
||||
|
||||
// If pubKey was not found, just return nil.
|
||||
if pubKey == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pubKey.SerializeCompressed()
|
||||
}
|
||||
|
||||
// Extract the channel update from the policy we own, if any.
|
||||
for _, edge := range policies {
|
||||
if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) {
|
||||
return ChannelUpdateFromEdge(info, edge)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to extract ChannelUpdate for channel %v",
|
||||
info.ChannelPoint)
|
||||
}
|
||||
|
||||
// UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the
|
||||
// given edge info and policy.
|
||||
func UnsignedChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo,
|
||||
policy *channeldb.ChannelEdgePolicy) *lnwire.ChannelUpdate {
|
||||
|
||||
return &lnwire.ChannelUpdate{
|
||||
ChainHash: info.ChainHash,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(policy.ChannelID),
|
||||
Timestamp: uint32(policy.LastUpdate.Unix()),
|
||||
ChannelFlags: policy.ChannelFlags,
|
||||
MessageFlags: policy.MessageFlags,
|
||||
TimeLockDelta: policy.TimeLockDelta,
|
||||
HtlcMinimumMsat: policy.MinHTLC,
|
||||
HtlcMaximumMsat: policy.MaxHTLC,
|
||||
BaseFee: uint32(policy.FeeBaseMSat),
|
||||
FeeRate: uint32(policy.FeeProportionalMillionths),
|
||||
ExtraOpaqueData: policy.ExtraOpaqueData,
|
||||
}
|
||||
}
|
||||
|
||||
// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge
|
||||
// info and policy.
|
||||
func ChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo,
|
||||
policy *channeldb.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) {
|
||||
|
||||
update := UnsignedChannelUpdateFromEdge(info, policy)
|
||||
|
||||
var err error
|
||||
update.Signature, err = lnwire.NewSigFromRawSignature(policy.SigBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return update, nil
|
||||
}
|
||||
23
vendor/github.com/lightningnetwork/lnd/netann/interface.go
generated
vendored
Normal file
23
vendor/github.com/lightningnetwork/lnd/netann/interface.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
)
|
||||
|
||||
// DB abstracts the required database functionality needed by the
|
||||
// ChanStatusManager.
|
||||
type DB interface {
|
||||
// FetchAllOpenChannels returns a slice of all open channels known to
|
||||
// the daemon. This may include private or pending channels.
|
||||
FetchAllOpenChannels() ([]*channeldb.OpenChannel, error)
|
||||
}
|
||||
|
||||
// ChannelGraph abstracts the required channel graph queries used by the
|
||||
// ChanStatusManager.
|
||||
type ChannelGraph interface {
|
||||
// FetchChannelEdgesByOutpoint returns the channel edge info and most
|
||||
// recent channel edge policies for a given outpoint.
|
||||
FetchChannelEdgesByOutpoint(*wire.OutPoint) (*channeldb.ChannelEdgeInfo,
|
||||
*channeldb.ChannelEdgePolicy, *channeldb.ChannelEdgePolicy, error)
|
||||
}
|
||||
45
vendor/github.com/lightningnetwork/lnd/netann/log.go
generated
vendored
Normal file
45
vendor/github.com/lightningnetwork/lnd/netann/log.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btclog"
|
||||
"github.com/lightningnetwork/lnd/build"
|
||||
)
|
||||
|
||||
// log is a logger that is initialized with no output filters. This means the
|
||||
// package will not perform any logging by default until the caller requests
|
||||
// it.
|
||||
var log btclog.Logger
|
||||
|
||||
// The default amount of logging is none.
|
||||
func init() {
|
||||
UseLogger(build.NewSubLogger("NANN", nil))
|
||||
}
|
||||
|
||||
// DisableLog disables all library log output. Logging output is disabled by
|
||||
// by default until UseLogger is called.
|
||||
func DisableLog() {
|
||||
UseLogger(btclog.Disabled)
|
||||
}
|
||||
|
||||
// UseLogger uses a specified Logger to output package logging info. This
|
||||
// should be used in preference to SetLogWriter if the caller is also using
|
||||
// btclog.
|
||||
func UseLogger(logger btclog.Logger) {
|
||||
log = logger
|
||||
}
|
||||
|
||||
// logClosure is used to provide a closure over expensive logging operations so
|
||||
// don't have to be performed when the logging level doesn't warrant it.
|
||||
type logClosure func() string // nolint:unused
|
||||
|
||||
// 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 { // nolint:unused
|
||||
return logClosure(c)
|
||||
}
|
||||
60
vendor/github.com/lightningnetwork/lnd/netann/node_announcement.go
generated
vendored
Normal file
60
vendor/github.com/lightningnetwork/lnd/netann/node_announcement.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// NodeAnnModifier is a closure that makes in-place modifications to an
|
||||
// lnwire.NodeAnnouncement.
|
||||
type NodeAnnModifier func(*lnwire.NodeAnnouncement)
|
||||
|
||||
// NodeAnnSetAddrs is a functional option that allows updating the addresses of
|
||||
// the given node announcement.
|
||||
func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) {
|
||||
return func(nodeAnn *lnwire.NodeAnnouncement) {
|
||||
nodeAnn.Addresses = addrs
|
||||
}
|
||||
}
|
||||
|
||||
// NodeAnnSetTimestamp is a functional option that sets the timestamp of the
|
||||
// announcement to the current time, or increments it if the timestamp is
|
||||
// already in the future.
|
||||
func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) {
|
||||
newTimestamp := uint32(time.Now().Unix())
|
||||
if newTimestamp <= nodeAnn.Timestamp {
|
||||
// Increment the prior value to ensure the timestamp
|
||||
// monotonically increases, otherwise the announcement won't
|
||||
// propagate.
|
||||
newTimestamp = nodeAnn.Timestamp + 1
|
||||
}
|
||||
nodeAnn.Timestamp = newTimestamp
|
||||
}
|
||||
|
||||
// SignNodeAnnouncement applies the given modifies to the passed
|
||||
// lnwire.NodeAnnouncement, then signs the resulting announcement. The provided
|
||||
// update should be the most recent, valid update, otherwise the timestamp may
|
||||
// not monotonically increase from the prior.
|
||||
func SignNodeAnnouncement(signer lnwallet.MessageSigner,
|
||||
pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement,
|
||||
mods ...NodeAnnModifier) error {
|
||||
|
||||
// Apply the requested changes to the node announcement.
|
||||
for _, modifier := range mods {
|
||||
modifier(nodeAnn)
|
||||
}
|
||||
|
||||
// Create the DER-encoded ECDSA signature over the message digest.
|
||||
sig, err := SignAnnouncement(signer, pubKey, nodeAnn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the DER-encoded signature into a fixed-size 64-byte array.
|
||||
nodeAnn.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||
return err
|
||||
}
|
||||
83
vendor/github.com/lightningnetwork/lnd/netann/node_signer.go
generated
vendored
Normal file
83
vendor/github.com/lightningnetwork/lnd/netann/node_signer.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
)
|
||||
|
||||
// NodeSigner is an implementation of the MessageSigner interface backed by the
|
||||
// identity private key of running lnd node.
|
||||
type NodeSigner struct {
|
||||
privKey *btcec.PrivateKey
|
||||
}
|
||||
|
||||
// NewNodeSigner creates a new instance of the NodeSigner backed by the target
|
||||
// private key.
|
||||
func NewNodeSigner(key *btcec.PrivateKey) *NodeSigner {
|
||||
priv := &btcec.PrivateKey{}
|
||||
priv.Curve = btcec.S256()
|
||||
priv.PublicKey.X = key.X
|
||||
priv.PublicKey.Y = key.Y
|
||||
priv.D = key.D
|
||||
return &NodeSigner{
|
||||
privKey: priv,
|
||||
}
|
||||
}
|
||||
|
||||
// SignMessage signs a double-sha256 digest of the passed msg under the
|
||||
// resident node's private key. If the target public key is _not_ the node's
|
||||
// private key, then an error will be returned.
|
||||
func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
|
||||
// If this isn't our identity public key, then we'll exit early with an
|
||||
// error as we can't sign with this key.
|
||||
if !pubKey.IsEqual(n.privKey.PubKey()) {
|
||||
return nil, fmt.Errorf("unknown public key")
|
||||
}
|
||||
|
||||
// Otherwise, we'll sign the dsha256 of the target message.
|
||||
digest := chainhash.DoubleHashB(msg)
|
||||
sig, err := n.privKey.Sign(digest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the message: %v", err)
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// SignCompact signs a double-sha256 digest of the msg parameter under the
|
||||
// resident node's private key. The returned signature is a pubkey-recoverable
|
||||
// signature.
|
||||
func (n *NodeSigner) SignCompact(msg []byte) ([]byte, error) {
|
||||
// We'll sign the dsha256 of the target message.
|
||||
digest := chainhash.DoubleHashB(msg)
|
||||
|
||||
return n.SignDigestCompact(digest)
|
||||
}
|
||||
|
||||
// SignDigestCompact signs the provided message digest under the resident
|
||||
// node's private key. The returned signature is a pubkey-recoverable signature.
|
||||
func (n *NodeSigner) SignDigestCompact(hash []byte) ([]byte, error) {
|
||||
|
||||
// Should the signature reference a compressed public key or not.
|
||||
isCompressedKey := true
|
||||
|
||||
// btcec.SignCompact returns a pubkey-recoverable signature
|
||||
sig, err := btcec.SignCompact(
|
||||
btcec.S256(), n.privKey, hash, isCompressedKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// A compile time check to ensure that NodeSigner implements the MessageSigner
|
||||
// interface.
|
||||
var _ lnwallet.MessageSigner = (*NodeSigner)(nil)
|
||||
37
vendor/github.com/lightningnetwork/lnd/netann/sign.go
generated
vendored
Normal file
37
vendor/github.com/lightningnetwork/lnd/netann/sign.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package netann
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// SignAnnouncement signs any type of gossip message that is announced on the
|
||||
// network.
|
||||
func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey,
|
||||
msg lnwire.Message) (input.Signature, error) {
|
||||
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
switch m := msg.(type) {
|
||||
case *lnwire.ChannelAnnouncement:
|
||||
data, err = m.DataToSign()
|
||||
case *lnwire.ChannelUpdate:
|
||||
data, err = m.DataToSign()
|
||||
case *lnwire.NodeAnnouncement:
|
||||
data, err = m.DataToSign()
|
||||
default:
|
||||
return nil, fmt.Errorf("can't sign %T message", m)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get data to sign: %v", err)
|
||||
}
|
||||
|
||||
return signer.SignMessage(pubKey, data)
|
||||
}
|
||||
Reference in New Issue
Block a user