github.com/decred/dcrlnd@v0.7.6/feature/deps.go (about)

     1  package feature
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/decred/dcrlnd/lnwire"
     7  )
     8  
     9  type (
    10  	// featureSet contains a set of feature bits.
    11  	featureSet map[lnwire.FeatureBit]struct{}
    12  
    13  	// supportedFeatures maps the feature bit from a feature vector to a
    14  	// boolean indicating if this features dependencies have already been
    15  	// verified. This allows us to short circuit verification if multiple
    16  	// features have common dependencies, or map traversal starts verifying
    17  	// from the bottom up.
    18  	supportedFeatures map[lnwire.FeatureBit]bool
    19  
    20  	// depDesc maps a features to its set of dependent features, which must
    21  	// also be present for the vector to be valid. This can be used to
    22  	// recursively check the dependency chain for features in a feature
    23  	// vector.
    24  	depDesc map[lnwire.FeatureBit]featureSet
    25  )
    26  
    27  // ErrMissingFeatureDep is an error signaling that a transitive dependency in a
    28  // feature vector is not set properly.
    29  type ErrMissingFeatureDep struct {
    30  	dep lnwire.FeatureBit
    31  }
    32  
    33  // NewErrMissingFeatureDep creates a new ErrMissingFeatureDep error.
    34  func NewErrMissingFeatureDep(dep lnwire.FeatureBit) ErrMissingFeatureDep {
    35  	return ErrMissingFeatureDep{dep: dep}
    36  }
    37  
    38  // Error returns a human-readable description of the missing dep error.
    39  func (e ErrMissingFeatureDep) Error() string {
    40  	return fmt.Sprintf("missing feature dependency: %v", e.dep)
    41  }
    42  
    43  // deps is the default set of dependencies for assigned feature bits. If a
    44  // feature is not present in the depDesc it is assumed to have no dependencies.
    45  //
    46  // NOTE: For proper functioning, only the optional variant of feature bits
    47  // should be used in the following descriptor. In the future it may be necessary
    48  // to distinguish the dependencies for optional and required bits, but for now
    49  // the validation code maps required bits to optional ones since it simplifies
    50  // the number of constraints.
    51  var deps = depDesc{
    52  	lnwire.PaymentAddrOptional: {
    53  		lnwire.TLVOnionPayloadOptional: {},
    54  	},
    55  	lnwire.MPPOptional: {
    56  		lnwire.PaymentAddrOptional: {},
    57  	},
    58  	lnwire.AnchorsOptional: {
    59  		lnwire.StaticRemoteKeyOptional: {},
    60  	},
    61  	lnwire.AnchorsZeroFeeHtlcTxOptional: {
    62  		lnwire.StaticRemoteKeyOptional: {},
    63  	},
    64  	lnwire.AMPOptional: {
    65  		lnwire.PaymentAddrOptional: {},
    66  	},
    67  	lnwire.ExplicitChannelTypeOptional: {},
    68  	lnwire.ScriptEnforcedLeaseOptional: {
    69  		lnwire.ExplicitChannelTypeOptional:  {},
    70  		lnwire.AnchorsZeroFeeHtlcTxOptional: {},
    71  	},
    72  }
    73  
    74  // ValidateDeps asserts that a feature vector sets all features and their
    75  // transitive dependencies properly. It assumes that the dependencies between
    76  // optional and required features are identical, e.g. if a feature is required
    77  // but its dependency is optional, that is sufficient.
    78  func ValidateDeps(fv *lnwire.FeatureVector) error {
    79  	features := fv.Features()
    80  	supported := initSupported(features)
    81  
    82  	return validateDeps(features, supported)
    83  }
    84  
    85  // validateDeps is a subroutine that recursively checks that the passed features
    86  // have all of their associated dependencies in the supported map.
    87  func validateDeps(features featureSet, supported supportedFeatures) error {
    88  	for bit := range features {
    89  		// Convert any required bits to optional.
    90  		bit = mapToOptional(bit)
    91  
    92  		// If the supported features doesn't contain the dependency, this
    93  		// vector is invalid.
    94  		checked, ok := supported[bit]
    95  		if !ok {
    96  			return NewErrMissingFeatureDep(bit)
    97  		}
    98  
    99  		// Alternatively, if we know that this dependency is valid, we
   100  		// can short circuit and continue verifying other bits.
   101  		if checked {
   102  			continue
   103  		}
   104  
   105  		// Recursively validate dependencies, since this method ranges
   106  		// over the subDeps. This method will return true even if
   107  		// subDeps is nil.
   108  		subDeps := deps[bit]
   109  		if err := validateDeps(subDeps, supported); err != nil {
   110  			return err
   111  		}
   112  
   113  		// Once we've confirmed that this feature's dependencies, if
   114  		// any, are sound, we record this so other paths taken through
   115  		// `bit` return early when inspecting the supported map.
   116  		supported[bit] = true
   117  	}
   118  
   119  	return nil
   120  }
   121  
   122  // initSupported sets all bits from the feature vector as supported but not
   123  // checked. This signals that the validity of their dependencies has not been
   124  // verified. All required bits are mapped to optional to simplify the DAG.
   125  func initSupported(features featureSet) supportedFeatures {
   126  	supported := make(supportedFeatures)
   127  	for bit := range features {
   128  		bit = mapToOptional(bit)
   129  		supported[bit] = false
   130  	}
   131  
   132  	return supported
   133  }
   134  
   135  // mapToOptional returns the optional variant of a given feature bit pair. Our
   136  // dependendency graph is described using only optional feature bits, which
   137  // reduces the number of constraints we need to express in the descriptor.
   138  func mapToOptional(bit lnwire.FeatureBit) lnwire.FeatureBit {
   139  	if bit.IsRequired() {
   140  		bit ^= 0x01
   141  	}
   142  	return bit
   143  }