mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-01 18:27:43 +02:00
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.
This commit is contained in:
@@ -16,6 +16,10 @@ var (
|
||||
// set of features are made.
|
||||
ErrFeatureStandard = errors.New("feature is used in standard " +
|
||||
"protocol set")
|
||||
|
||||
// ErrFeatureBitMaximum is returned when a feature bit exceeds the
|
||||
// maximum allowable value.
|
||||
ErrFeatureBitMaximum = errors.New("feature bit exceeds allowed maximum")
|
||||
)
|
||||
|
||||
// FeatureBit represents a feature that can be enabled in either a local or
|
||||
@@ -227,17 +231,18 @@ const (
|
||||
// TODO: Decide on actual feature bit value.
|
||||
ScriptEnforcedLeaseOptional FeatureBit = 2023
|
||||
|
||||
// maxAllowedSize is a maximum allowed size of feature vector.
|
||||
// MaxBolt11Feature is the maximum feature bit value allowed in bolt 11
|
||||
// invoices.
|
||||
//
|
||||
// NOTE: Within the protocol, the maximum allowed message size is 65535
|
||||
// bytes for all messages. Accounting for the overhead within the feature
|
||||
// message to signal the type of message, that leaves us with 65533 bytes
|
||||
// for the init message itself. Next, we reserve 4 bytes to encode the
|
||||
// lengths of both the local and global feature vectors, so 65529 bytes
|
||||
// for the local and global features. Knocking off one byte for the sake
|
||||
// of the calculation, that leads us to 32764 bytes for each feature
|
||||
// vector, or 131056 different features.
|
||||
maxAllowedSize = 32764
|
||||
// The base 32 encoded tagged fields in invoices are limited to 10 bits
|
||||
// to express the length of the field's data.
|
||||
//nolint:lll
|
||||
// See: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md#tagged-fields
|
||||
//
|
||||
// With a maximum length field of 1023 (2^10 -1) and 5 bit encoding,
|
||||
// the highest feature bit that can be expressed is:
|
||||
// 1023 * 5 - 1 = 5114.
|
||||
MaxBolt11Feature = 5114
|
||||
)
|
||||
|
||||
// IsRequired returns true if the feature bit is even, and false otherwise.
|
||||
@@ -354,8 +359,12 @@ func (fv *RawFeatureVector) Merge(other *RawFeatureVector) error {
|
||||
// new feature vector provided, checking that it does not alter any of the
|
||||
// "standard" features that are defined by LND. The new feature vector should
|
||||
// be inclusive of all features in the original vector that it still wants to
|
||||
// advertise, setting and unsetting updates as desired.
|
||||
func (fv *RawFeatureVector) ValidateUpdate(other *RawFeatureVector) error {
|
||||
// advertise, setting and unsetting updates as desired. Features in the vector
|
||||
// are also checked against a maximum inclusive value, as feature vectors in
|
||||
// different contexts have different maximum values.
|
||||
func (fv *RawFeatureVector) ValidateUpdate(other *RawFeatureVector,
|
||||
maximumValue FeatureBit) error {
|
||||
|
||||
// Run through the new set of features and check that we're not adding
|
||||
// any feature bits that are defined but not set in LND.
|
||||
for feature := range other.features {
|
||||
@@ -363,6 +372,12 @@ func (fv *RawFeatureVector) ValidateUpdate(other *RawFeatureVector) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if feature > maximumValue {
|
||||
return fmt.Errorf("can't set feature bit %d: %w %v",
|
||||
feature, ErrFeatureBitMaximum,
|
||||
maximumValue)
|
||||
}
|
||||
|
||||
if name, known := Features[feature]; known {
|
||||
return fmt.Errorf("can't set feature "+
|
||||
"bit %d (%v): %w", feature, name,
|
||||
|
Reference in New Issue
Block a user