lnd/feature/set.go
Carla Kirk-Cohen 019127c4f4
multi: add restriction on maximum feature bit in invoices
Base 32 encoded bolt 11 invoices only allow 10 bits to express the
length of the feature vector in a tagged field, so there is a much
lower limit on the values invoice custom features can hold.

Other places in the protocol are theoretically limited by the maximum
message size, but since we express a feature bit as u16 we don't need
to be concerned about this.

The decision is made to track maximum per-set in the feature manager,
which is conceptually aware of sets and then validate in lnwire/features
against some arbitrary maximum value provided to the caller to keep
the base features package unaware of sets.
2023-05-04 10:35:45 -04:00

84 lines
2.3 KiB
Go

package feature
import (
"math"
"github.com/lightningnetwork/lnd/lnwire"
)
// Set is an enum identifying various feature sets, which separates the single
// feature namespace into distinct categories depending what context a feature
// vector is being used.
type Set uint8
const (
// SetInit identifies features that should be sent in an Init message to
// a remote peer.
SetInit Set = iota
// SetLegacyGlobal identifies features that should be set in the legacy
// GlobalFeatures field of an Init message, which maintains backwards
// compatibility with nodes that haven't implemented flat features.
SetLegacyGlobal
// SetNodeAnn identifies features that should be advertised on node
// announcements.
SetNodeAnn
// SetInvoice identifies features that should be advertised on invoices
// generated by the daemon.
SetInvoice
// SetInvoiceAmp identifies the features that should be advertised on
// AMP invoices generated by the daemon.
SetInvoiceAmp
// setSentinel is used to mark the end of our known sets. This enum
// member must *always* be the last item in the iota list to ensure
// that validation works as expected.
setSentinel
)
// valid returns a boolean indicating whether a set value is one of our
// predefined feature sets.
func (s Set) valid() bool {
return s < setSentinel
}
// String returns a human-readable description of a Set.
func (s Set) String() string {
switch s {
case SetInit:
return "SetInit"
case SetLegacyGlobal:
return "SetLegacyGlobal"
case SetNodeAnn:
return "SetNodeAnn"
case SetInvoice:
return "SetInvoice"
case SetInvoiceAmp:
return "SetInvoiceAmp"
default:
return "SetUnknown"
}
}
// Maximum returns the maximum allowable value for a feature bit in the context
// of a set. The maximum feature value we can express differs by set context
// because the amount of space available varies between protocol messages. In
// practice this should never be a problem (reasonably one would never hit
// these high ranges), but we enforce these maximums for the sake of sane
// validation.
func (s Set) Maximum() lnwire.FeatureBit {
switch s {
case SetInvoice, SetInvoiceAmp:
return lnwire.MaxBolt11Feature
// The space available in other sets is > math.MaxUint16, so we just
// return the maximum value our expression of a feature bit allows so
// that any value will pass.
default:
return math.MaxUint16
}
}