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 }