github.com/decred/dcrlnd@v0.7.6/routing/validation_barrier.go (about) 1 package routing 2 3 import ( 4 "sync" 5 6 "github.com/decred/dcrlnd/channeldb" 7 "github.com/decred/dcrlnd/lnwire" 8 "github.com/decred/dcrlnd/routing/route" 9 ) 10 11 // validationSignals contains two signals which allows the ValidationBarrier to 12 // communicate back to the caller whether a dependent should be processed or not 13 // based on whether its parent was successfully validated. Only one of these 14 // signals is to be used at a time. 15 type validationSignals struct { 16 // allow is the signal used to allow a dependent to be processed. 17 allow chan struct{} 18 19 // deny is the signal used to prevent a dependent from being processed. 20 deny chan struct{} 21 } 22 23 // ValidationBarrier is a barrier used to ensure proper validation order while 24 // concurrently validating new announcements for channel edges, and the 25 // attributes of channel edges. It uses this set of maps (protected by this 26 // mutex) to track validation dependencies. For a given channel our 27 // dependencies look like this: chanAnn <- chanUp <- nodeAnn. That is we must 28 // validate the item on the left of the arrow before that on the right. 29 type ValidationBarrier struct { 30 // validationSemaphore is a channel of structs which is used as a 31 // sempahore. Initially we'll fill this with a buffered channel of the 32 // size of the number of active requests. Each new job will consume 33 // from this channel, then restore the value upon completion. 34 validationSemaphore chan struct{} 35 36 // chanAnnFinSignal is map that keep track of all the pending 37 // ChannelAnnouncement like validation job going on. Once the job has 38 // been completed, the channel will be closed unblocking any 39 // dependants. 40 chanAnnFinSignal map[lnwire.ShortChannelID]*validationSignals 41 42 // chanEdgeDependencies tracks any channel edge updates which should 43 // wait until the completion of the ChannelAnnouncement before 44 // proceeding. This is a dependency, as we can't validate the update 45 // before we validate the announcement which creates the channel 46 // itself. 47 chanEdgeDependencies map[lnwire.ShortChannelID]*validationSignals 48 49 // nodeAnnDependencies tracks any pending NodeAnnouncement validation 50 // jobs which should wait until the completion of the 51 // ChannelAnnouncement before proceeding. 52 nodeAnnDependencies map[route.Vertex]*validationSignals 53 54 quit chan struct{} 55 sync.Mutex 56 } 57 58 // NewValidationBarrier creates a new instance of a validation barrier given 59 // the total number of active requests, and a quit channel which will be used 60 // to know when to kill pending, but unfilled jobs. 61 func NewValidationBarrier(numActiveReqs int, 62 quitChan chan struct{}) *ValidationBarrier { 63 64 v := &ValidationBarrier{ 65 chanAnnFinSignal: make(map[lnwire.ShortChannelID]*validationSignals), 66 chanEdgeDependencies: make(map[lnwire.ShortChannelID]*validationSignals), 67 nodeAnnDependencies: make(map[route.Vertex]*validationSignals), 68 quit: quitChan, 69 } 70 71 // We'll first initialize a set of sempahores to limit our concurrency 72 // when validating incoming requests in parallel. 73 v.validationSemaphore = make(chan struct{}, numActiveReqs) 74 for i := 0; i < numActiveReqs; i++ { 75 v.validationSemaphore <- struct{}{} 76 } 77 78 return v 79 } 80 81 // InitJobDependencies will wait for a new job slot to become open, and then 82 // sets up any dependent signals/trigger for the new job 83 func (v *ValidationBarrier) InitJobDependencies(job interface{}) { 84 // We'll wait for either a new slot to become open, or for the quit 85 // channel to be closed. 86 select { 87 case <-v.validationSemaphore: 88 case <-v.quit: 89 } 90 91 v.Lock() 92 defer v.Unlock() 93 94 // Once a slot is open, we'll examine the message of the job, to see if 95 // there need to be any dependent barriers set up. 96 switch msg := job.(type) { 97 98 // If this is a channel announcement, then we'll need to set up den 99 // tenancies, as we'll need to verify this before we verify any 100 // ChannelUpdates for the same channel, or NodeAnnouncements of nodes 101 // that are involved in this channel. This goes for both the wire 102 // type,s and also the types that we use within the database. 103 case *lnwire.ChannelAnnouncement: 104 105 // We ensure that we only create a new announcement signal iff, 106 // one doesn't already exist, as there may be duplicate 107 // announcements. We'll close this signal once the 108 // ChannelAnnouncement has been validated. This will result in 109 // all the dependent jobs being unlocked so they can finish 110 // execution themselves. 111 if _, ok := v.chanAnnFinSignal[msg.ShortChannelID]; !ok { 112 // We'll create the channel that we close after we 113 // validate this announcement. All dependants will 114 // point to this same channel, so they'll be unblocked 115 // at the same time. 116 signals := &validationSignals{ 117 allow: make(chan struct{}), 118 deny: make(chan struct{}), 119 } 120 121 v.chanAnnFinSignal[msg.ShortChannelID] = signals 122 v.chanEdgeDependencies[msg.ShortChannelID] = signals 123 124 v.nodeAnnDependencies[route.Vertex(msg.NodeID1)] = signals 125 v.nodeAnnDependencies[route.Vertex(msg.NodeID2)] = signals 126 } 127 case *channeldb.ChannelEdgeInfo: 128 129 shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) 130 if _, ok := v.chanAnnFinSignal[shortID]; !ok { 131 signals := &validationSignals{ 132 allow: make(chan struct{}), 133 deny: make(chan struct{}), 134 } 135 136 v.chanAnnFinSignal[shortID] = signals 137 v.chanEdgeDependencies[shortID] = signals 138 139 v.nodeAnnDependencies[route.Vertex(msg.NodeKey1Bytes)] = signals 140 v.nodeAnnDependencies[route.Vertex(msg.NodeKey2Bytes)] = signals 141 } 142 143 // These other types don't have any dependants, so no further 144 // initialization needs to be done beyond just occupying a job slot. 145 case *channeldb.ChannelEdgePolicy: 146 return 147 case *lnwire.ChannelUpdate: 148 return 149 case *lnwire.NodeAnnouncement: 150 // TODO(roasbeef): node ann needs to wait on existing channel updates 151 return 152 case *channeldb.LightningNode: 153 return 154 case *lnwire.AnnounceSignatures: 155 // TODO(roasbeef): need to wait on chan ann? 156 return 157 } 158 } 159 160 // CompleteJob returns a free slot to the set of available job slots. This 161 // should be called once a job has been fully completed. Otherwise, slots may 162 // not be returned to the internal scheduling, causing a deadlock when a new 163 // overflow job is attempted. 164 func (v *ValidationBarrier) CompleteJob() { 165 select { 166 case v.validationSemaphore <- struct{}{}: 167 case <-v.quit: 168 } 169 } 170 171 // WaitForDependants will block until any jobs that this job dependants on have 172 // finished executing. This allows us a graceful way to schedule goroutines 173 // based on any pending uncompleted dependent jobs. If this job doesn't have an 174 // active dependent, then this function will return immediately. 175 func (v *ValidationBarrier) WaitForDependants(job interface{}) error { 176 177 var ( 178 signals *validationSignals 179 ok bool 180 ) 181 182 v.Lock() 183 switch msg := job.(type) { 184 185 // Any ChannelUpdate or NodeAnnouncement jobs will need to wait on the 186 // completion of any active ChannelAnnouncement jobs related to them. 187 case *channeldb.ChannelEdgePolicy: 188 shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) 189 signals, ok = v.chanEdgeDependencies[shortID] 190 case *channeldb.LightningNode: 191 vertex := route.Vertex(msg.PubKeyBytes) 192 signals, ok = v.nodeAnnDependencies[vertex] 193 case *lnwire.ChannelUpdate: 194 signals, ok = v.chanEdgeDependencies[msg.ShortChannelID] 195 case *lnwire.NodeAnnouncement: 196 vertex := route.Vertex(msg.NodeID) 197 signals, ok = v.nodeAnnDependencies[vertex] 198 199 // Other types of jobs can be executed immediately, so we'll just 200 // return directly. 201 case *lnwire.AnnounceSignatures: 202 // TODO(roasbeef): need to wait on chan ann? 203 v.Unlock() 204 return nil 205 case *channeldb.ChannelEdgeInfo: 206 v.Unlock() 207 return nil 208 case *lnwire.ChannelAnnouncement: 209 v.Unlock() 210 return nil 211 } 212 v.Unlock() 213 214 // If we do have an active job, then we'll wait until either the signal 215 // is closed, or the set of jobs exits. 216 if ok { 217 select { 218 case <-v.quit: 219 return newErrf(ErrVBarrierShuttingDown, 220 "validation barrier shutting down") 221 case <-signals.deny: 222 return newErrf(ErrParentValidationFailed, 223 "parent validation failed") 224 case <-signals.allow: 225 return nil 226 } 227 } 228 229 return nil 230 } 231 232 // SignalDependants will allow/deny any jobs that are dependent on this job that 233 // they can continue execution. If the job doesn't have any dependants, then 234 // this function sill exit immediately. 235 func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { 236 v.Lock() 237 defer v.Unlock() 238 239 switch msg := job.(type) { 240 241 // If we've just finished executing a ChannelAnnouncement, then we'll 242 // close out the signal, and remove the signal from the map of active 243 // ones. This will allow/deny any dependent jobs to continue execution. 244 case *channeldb.ChannelEdgeInfo: 245 shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) 246 finSignals, ok := v.chanAnnFinSignal[shortID] 247 if ok { 248 if allow { 249 close(finSignals.allow) 250 } else { 251 close(finSignals.deny) 252 } 253 delete(v.chanAnnFinSignal, shortID) 254 } 255 case *lnwire.ChannelAnnouncement: 256 finSignals, ok := v.chanAnnFinSignal[msg.ShortChannelID] 257 if ok { 258 if allow { 259 close(finSignals.allow) 260 } else { 261 close(finSignals.deny) 262 } 263 delete(v.chanAnnFinSignal, msg.ShortChannelID) 264 } 265 266 delete(v.chanEdgeDependencies, msg.ShortChannelID) 267 268 // For all other job types, we'll delete the tracking entries from the 269 // map, as if we reach this point, then all dependants have already 270 // finished executing and we can proceed. 271 case *channeldb.LightningNode: 272 delete(v.nodeAnnDependencies, route.Vertex(msg.PubKeyBytes)) 273 case *lnwire.NodeAnnouncement: 274 delete(v.nodeAnnDependencies, route.Vertex(msg.NodeID)) 275 case *lnwire.ChannelUpdate: 276 delete(v.chanEdgeDependencies, msg.ShortChannelID) 277 case *channeldb.ChannelEdgePolicy: 278 shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) 279 delete(v.chanEdgeDependencies, shortID) 280 281 case *lnwire.AnnounceSignatures: 282 return 283 } 284 }