2019-11-08 14:29:16 +01:00
|
|
|
package feature
|
|
|
|
|
|
|
|
import (
|
2023-04-03 14:07:23 +02:00
|
|
|
"errors"
|
2019-11-08 14:29:16 +01:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
)
|
|
|
|
|
2023-04-03 14:07:23 +02:00
|
|
|
// ErrUnknownSet is returned if a proposed feature vector contains a set that
|
|
|
|
// is unknown to LND.
|
|
|
|
var ErrUnknownSet = errors.New("unknown feature bit set")
|
|
|
|
|
2019-11-08 14:29:16 +01:00
|
|
|
// Config houses any runtime modifications to the default set descriptors. For
|
|
|
|
// our purposes, this typically means disabling certain features to test legacy
|
|
|
|
// protocol interoperability or functionality.
|
|
|
|
type Config struct {
|
|
|
|
// NoTLVOnion unsets any optional or required TLVOnionPaylod bits from
|
|
|
|
// all feature sets.
|
|
|
|
NoTLVOnion bool
|
|
|
|
|
|
|
|
// NoStaticRemoteKey unsets any optional or required StaticRemoteKey
|
|
|
|
// bits from all feature sets.
|
|
|
|
NoStaticRemoteKey bool
|
2020-03-06 16:11:48 +01:00
|
|
|
|
|
|
|
// NoAnchors unsets any bits signaling support for anchor outputs.
|
|
|
|
NoAnchors bool
|
2020-07-02 06:03:12 +02:00
|
|
|
|
|
|
|
// NoWumbo unsets any bits signalling support for wumbo channels.
|
|
|
|
NoWumbo bool
|
2021-07-14 00:20:46 +02:00
|
|
|
|
|
|
|
// NoScriptEnforcementLease unsets any bits signaling support for script
|
|
|
|
// enforced leases.
|
|
|
|
NoScriptEnforcementLease bool
|
2022-04-14 13:54:57 +02:00
|
|
|
|
|
|
|
// NoKeysend unsets any bits signaling support for accepting keysend
|
|
|
|
// payments.
|
|
|
|
NoKeysend bool
|
2022-04-04 21:16:13 +02:00
|
|
|
|
|
|
|
// NoOptionScidAlias unsets any bits signalling support for
|
|
|
|
// option_scid_alias. This also implicitly disables zero-conf channels.
|
|
|
|
NoOptionScidAlias bool
|
|
|
|
|
|
|
|
// NoZeroConf unsets any bits signalling support for zero-conf
|
|
|
|
// channels. This should be used instead of NoOptionScidAlias to still
|
|
|
|
// keep option-scid-alias support.
|
|
|
|
NoZeroConf bool
|
2022-08-05 04:09:39 +02:00
|
|
|
|
|
|
|
// NoAnySegwit unsets any bits that signal support for using other
|
|
|
|
// segwit witness versions for co-op closes.
|
|
|
|
NoAnySegwit bool
|
2019-11-08 14:29:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Manager is responsible for generating feature vectors for different requested
|
|
|
|
// feature sets.
|
|
|
|
type Manager struct {
|
|
|
|
// fsets is a static map of feature set to raw feature vectors. Requests
|
2022-01-13 17:29:43 +01:00
|
|
|
// are fulfilled by cloning these internal feature vectors.
|
2019-11-08 14:29:16 +01:00
|
|
|
fsets map[Set]*lnwire.RawFeatureVector
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewManager creates a new feature Manager, applying any custom modifications
|
|
|
|
// to its feature sets before returning.
|
|
|
|
func NewManager(cfg Config) (*Manager, error) {
|
|
|
|
return newManager(cfg, defaultSetDesc)
|
|
|
|
}
|
|
|
|
|
2020-07-02 06:03:12 +02:00
|
|
|
// newManager creates a new feature Manager, applying any custom modifications
|
2019-11-08 14:29:16 +01:00
|
|
|
// to its feature sets before returning. This method accepts the setDesc as its
|
|
|
|
// own parameter so that it can be unit tested.
|
|
|
|
func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
|
|
|
// First build the default feature vector for all known sets.
|
|
|
|
fsets := make(map[Set]*lnwire.RawFeatureVector)
|
|
|
|
for bit, sets := range desc {
|
|
|
|
for set := range sets {
|
|
|
|
// Fetch the feature vector for this set, allocating a
|
|
|
|
// new one if it doesn't exist.
|
|
|
|
fv, ok := fsets[set]
|
|
|
|
if !ok {
|
|
|
|
fv = lnwire.NewRawFeatureVector()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the configured bit on the feature vector,
|
|
|
|
// ensuring that we don't set two feature bits for the
|
|
|
|
// same pair.
|
|
|
|
err := fv.SafeSet(bit)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to set "+
|
|
|
|
"%v in %v: %v", bit, set, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the updated feature vector under its set.
|
|
|
|
fsets[set] = fv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, remove any features as directed by the config.
|
2019-12-16 22:06:45 +01:00
|
|
|
for set, raw := range fsets {
|
2019-11-08 14:29:16 +01:00
|
|
|
if cfg.NoTLVOnion {
|
2019-12-16 22:06:45 +01:00
|
|
|
raw.Unset(lnwire.TLVOnionPayloadOptional)
|
|
|
|
raw.Unset(lnwire.TLVOnionPayloadRequired)
|
|
|
|
raw.Unset(lnwire.PaymentAddrOptional)
|
|
|
|
raw.Unset(lnwire.PaymentAddrRequired)
|
|
|
|
raw.Unset(lnwire.MPPOptional)
|
|
|
|
raw.Unset(lnwire.MPPRequired)
|
2021-03-25 03:48:08 +01:00
|
|
|
raw.Unset(lnwire.AMPOptional)
|
|
|
|
raw.Unset(lnwire.AMPRequired)
|
2022-04-14 13:54:57 +02:00
|
|
|
raw.Unset(lnwire.KeysendOptional)
|
|
|
|
raw.Unset(lnwire.KeysendRequired)
|
2019-11-08 14:29:16 +01:00
|
|
|
}
|
|
|
|
if cfg.NoStaticRemoteKey {
|
2019-12-16 22:06:45 +01:00
|
|
|
raw.Unset(lnwire.StaticRemoteKeyOptional)
|
|
|
|
raw.Unset(lnwire.StaticRemoteKeyRequired)
|
|
|
|
}
|
2020-03-06 16:11:48 +01:00
|
|
|
if cfg.NoAnchors {
|
2020-12-07 14:12:45 +01:00
|
|
|
raw.Unset(lnwire.AnchorsZeroFeeHtlcTxOptional)
|
|
|
|
raw.Unset(lnwire.AnchorsZeroFeeHtlcTxRequired)
|
2021-11-20 00:58:56 +01:00
|
|
|
|
|
|
|
// If anchors are disabled, then we also need to
|
|
|
|
// disable all other features that depend on it as
|
|
|
|
// well, as otherwise we may create an invalid feature
|
|
|
|
// bit set.
|
|
|
|
for bit, depFeatures := range deps {
|
|
|
|
for depFeature := range depFeatures {
|
|
|
|
switch {
|
|
|
|
case depFeature == lnwire.AnchorsZeroFeeHtlcTxRequired:
|
|
|
|
fallthrough
|
|
|
|
case depFeature == lnwire.AnchorsZeroFeeHtlcTxOptional:
|
|
|
|
raw.Unset(bit)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-06 16:11:48 +01:00
|
|
|
}
|
2020-07-02 06:03:12 +02:00
|
|
|
if cfg.NoWumbo {
|
|
|
|
raw.Unset(lnwire.WumboChannelsOptional)
|
|
|
|
raw.Unset(lnwire.WumboChannelsRequired)
|
|
|
|
}
|
2021-07-14 00:20:46 +02:00
|
|
|
if cfg.NoScriptEnforcementLease {
|
|
|
|
raw.Unset(lnwire.ScriptEnforcedLeaseOptional)
|
|
|
|
raw.Unset(lnwire.ScriptEnforcedLeaseRequired)
|
|
|
|
}
|
2022-04-14 13:54:57 +02:00
|
|
|
if cfg.NoKeysend {
|
|
|
|
raw.Unset(lnwire.KeysendOptional)
|
|
|
|
raw.Unset(lnwire.KeysendRequired)
|
|
|
|
}
|
2022-04-04 21:16:13 +02:00
|
|
|
if cfg.NoOptionScidAlias {
|
|
|
|
raw.Unset(lnwire.ScidAliasOptional)
|
|
|
|
raw.Unset(lnwire.ScidAliasRequired)
|
|
|
|
}
|
|
|
|
if cfg.NoZeroConf {
|
|
|
|
raw.Unset(lnwire.ZeroConfOptional)
|
|
|
|
raw.Unset(lnwire.ZeroConfRequired)
|
|
|
|
}
|
2022-08-05 04:09:39 +02:00
|
|
|
if cfg.NoAnySegwit {
|
|
|
|
raw.Unset(lnwire.ShutdownAnySegwitOptional)
|
|
|
|
raw.Unset(lnwire.ShutdownAnySegwitRequired)
|
|
|
|
}
|
2019-12-16 22:06:45 +01:00
|
|
|
|
|
|
|
// Ensure that all of our feature sets properly set any
|
|
|
|
// dependent features.
|
|
|
|
fv := lnwire.NewFeatureVector(raw, lnwire.Features)
|
|
|
|
err := ValidateDeps(fv)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid feature set %v: %v",
|
|
|
|
set, err)
|
2019-11-08 14:29:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Manager{
|
|
|
|
fsets: fsets,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRaw returns a raw feature vector for the passed set. If no set is known,
|
|
|
|
// an empty raw feature vector is returned.
|
|
|
|
func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector {
|
|
|
|
if fv, ok := m.fsets[set]; ok {
|
|
|
|
return fv.Clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
return lnwire.NewRawFeatureVector()
|
|
|
|
}
|
|
|
|
|
2023-04-04 09:11:13 +02:00
|
|
|
// setRaw sets a new raw feature vector for the given set.
|
|
|
|
func (m *Manager) setRaw(set Set, raw *lnwire.RawFeatureVector) {
|
2022-01-03 00:56:04 +01:00
|
|
|
m.fsets[set] = raw
|
|
|
|
}
|
|
|
|
|
2019-11-08 14:29:16 +01:00
|
|
|
// Get returns a feature vector for the passed set. If no set is known, an empty
|
|
|
|
// feature vector is returned.
|
|
|
|
func (m *Manager) Get(set Set) *lnwire.FeatureVector {
|
|
|
|
raw := m.GetRaw(set)
|
|
|
|
return lnwire.NewFeatureVector(raw, lnwire.Features)
|
|
|
|
}
|
2019-12-17 20:58:28 +01:00
|
|
|
|
|
|
|
// ListSets returns a list of the feature sets that our node supports.
|
|
|
|
func (m *Manager) ListSets() []Set {
|
|
|
|
var sets []Set
|
|
|
|
|
|
|
|
for set := range m.fsets {
|
|
|
|
sets = append(sets, set)
|
|
|
|
}
|
|
|
|
|
|
|
|
return sets
|
|
|
|
}
|
2023-04-03 14:07:23 +02:00
|
|
|
|
|
|
|
// UpdateFeatureSets accepts a map of new feature vectors for each of the
|
|
|
|
// manager's known sets, validates that the update can be applied and modifies
|
|
|
|
// the feature manager's internal state. If a set is not included in the update
|
|
|
|
// map, it is left unchanged. The feature vectors provided are expected to
|
|
|
|
// include the current set of features, updated with desired bits added/removed.
|
|
|
|
func (m *Manager) UpdateFeatureSets(
|
|
|
|
updates map[Set]*lnwire.RawFeatureVector) error {
|
|
|
|
|
|
|
|
for set, newFeatures := range updates {
|
|
|
|
if !set.valid() {
|
|
|
|
return fmt.Errorf("%w: set: %d", ErrUnknownSet, set)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := newFeatures.ValidatePairs(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-04-25 17:01:52 +02:00
|
|
|
if err := m.Get(set).ValidateUpdate(
|
|
|
|
newFeatures, set.Maximum(),
|
|
|
|
); err != nil {
|
2023-04-03 14:07:23 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fv := lnwire.NewFeatureVector(newFeatures, lnwire.Features)
|
|
|
|
if err := ValidateDeps(fv); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only update the current feature sets once every proposed set has
|
|
|
|
// passed validation so that we don't partially update any sets then
|
|
|
|
// fail out on a later set's validation.
|
|
|
|
for set, features := range updates {
|
2023-04-04 09:11:13 +02:00
|
|
|
m.setRaw(set, features.Clone())
|
2023-04-03 14:07:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|