package feature import ( "errors" "fmt" "github.com/lightningnetwork/lnd/lnwire" ) var ( // ErrUnknownSet is returned if a proposed feature vector contains a // set that is unknown to LND. ErrUnknownSet = errors.New("unknown feature bit set") // ErrFeatureConfigured is returned if an attempt is made to unset a // feature that was configured at startup. ErrFeatureConfigured = errors.New("can't unset configured feature") ) // 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 // NoAnchors unsets any bits signaling support for anchor outputs. NoAnchors bool // NoWumbo unsets any bits signalling support for wumbo channels. NoWumbo bool // NoTaprootChans unsets any bits signaling support for taproot // channels. NoTaprootChans bool // NoScriptEnforcementLease unsets any bits signaling support for script // enforced leases. NoScriptEnforcementLease bool // NoKeysend unsets any bits signaling support for accepting keysend // payments. NoKeysend bool // 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 // NoAnySegwit unsets any bits that signal support for using other // segwit witness versions for co-op closes. NoAnySegwit bool // NoRouteBlinding unsets route blinding feature bits. NoRouteBlinding bool // NoTaprootOverlay unsets the taproot overlay channel feature bits. NoTaprootOverlay bool // CustomFeatures is a set of custom features to advertise in each // set. CustomFeatures map[Set][]lnwire.FeatureBit } // 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 // are fulfilled by cloning these internal feature vectors. fsets map[Set]*lnwire.RawFeatureVector // configFeatures is a set of custom features that were "hard set" in // lnd's config that cannot be updated at runtime (as is the case with // our "standard" features that are defined in LND). configFeatures map[Set]*lnwire.FeatureVector } // 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) } // newManager creates a new feature Manager, applying any custom modifications // 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. configFeatures := make(map[Set]*lnwire.FeatureVector) for set, raw := range fsets { if cfg.NoTLVOnion { raw.Unset(lnwire.TLVOnionPayloadOptional) raw.Unset(lnwire.TLVOnionPayloadRequired) raw.Unset(lnwire.PaymentAddrOptional) raw.Unset(lnwire.PaymentAddrRequired) raw.Unset(lnwire.MPPOptional) raw.Unset(lnwire.MPPRequired) raw.Unset(lnwire.RouteBlindingOptional) raw.Unset(lnwire.RouteBlindingRequired) raw.Unset(lnwire.Bolt11BlindedPathsOptional) raw.Unset(lnwire.Bolt11BlindedPathsRequired) raw.Unset(lnwire.AMPOptional) raw.Unset(lnwire.AMPRequired) raw.Unset(lnwire.KeysendOptional) raw.Unset(lnwire.KeysendRequired) } if cfg.NoStaticRemoteKey { raw.Unset(lnwire.StaticRemoteKeyOptional) raw.Unset(lnwire.StaticRemoteKeyRequired) } if cfg.NoAnchors { raw.Unset(lnwire.AnchorsZeroFeeHtlcTxOptional) raw.Unset(lnwire.AnchorsZeroFeeHtlcTxRequired) // 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) } } } } if cfg.NoWumbo { raw.Unset(lnwire.WumboChannelsOptional) raw.Unset(lnwire.WumboChannelsRequired) } if cfg.NoScriptEnforcementLease { raw.Unset(lnwire.ScriptEnforcedLeaseOptional) raw.Unset(lnwire.ScriptEnforcedLeaseRequired) } if cfg.NoKeysend { raw.Unset(lnwire.KeysendOptional) raw.Unset(lnwire.KeysendRequired) } if cfg.NoOptionScidAlias { raw.Unset(lnwire.ScidAliasOptional) raw.Unset(lnwire.ScidAliasRequired) } if cfg.NoZeroConf { raw.Unset(lnwire.ZeroConfOptional) raw.Unset(lnwire.ZeroConfRequired) } if cfg.NoAnySegwit { raw.Unset(lnwire.ShutdownAnySegwitOptional) raw.Unset(lnwire.ShutdownAnySegwitRequired) } if cfg.NoTaprootChans { raw.Unset(lnwire.SimpleTaprootChannelsOptionalStaging) raw.Unset(lnwire.SimpleTaprootChannelsRequiredStaging) } if cfg.NoRouteBlinding { raw.Unset(lnwire.RouteBlindingOptional) raw.Unset(lnwire.RouteBlindingRequired) raw.Unset(lnwire.Bolt11BlindedPathsOptional) raw.Unset(lnwire.Bolt11BlindedPathsRequired) } if cfg.NoTaprootOverlay { raw.Unset(lnwire.SimpleTaprootOverlayChansOptional) raw.Unset(lnwire.SimpleTaprootOverlayChansRequired) } for _, custom := range cfg.CustomFeatures[set] { if custom > set.Maximum() { return nil, fmt.Errorf("feature bit: %v "+ "exceeds set: %v maximum: %v", custom, set, set.Maximum()) } if raw.IsSet(custom) { return nil, fmt.Errorf("feature bit: %v "+ "already set", custom) } if err := raw.SafeSet(custom); err != nil { return nil, fmt.Errorf("%w: could not set "+ "feature: %d", err, custom) } } // Track custom features separately so that we can check that // they aren't unset in subsequent updates. If there is no // entry for the set, the vector will just be empty. configFeatures[set] = lnwire.NewFeatureVector( lnwire.NewRawFeatureVector(cfg.CustomFeatures[set]...), lnwire.Features, ) // 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: %w", set, err) } } return &Manager{ fsets: fsets, configFeatures: configFeatures, }, 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() } // setRaw sets a new raw feature vector for the given set. func (m *Manager) setRaw(set Set, raw *lnwire.RawFeatureVector) { m.fsets[set] = raw } // 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) } // 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 } // 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 } if err := m.Get(set).ValidateUpdate( newFeatures, set.Maximum(), ); err != nil { return err } // If any features were configured for this set, ensure that // they are still set in the new feature vector. if cfgFeat, haveCfgFeat := m.configFeatures[set]; haveCfgFeat { for feature := range cfgFeat.Features() { if !newFeatures.IsSet(feature) { return fmt.Errorf("%w: can't unset: "+ "%d", ErrFeatureConfigured, feature) } } } 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 { m.setRaw(set, features.Clone()) } return nil }