github.com/annchain/OG@v0.0.9/og/fetcher/fetcher.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package fetcher contains the sequencer announcement based synchronisation. 18 package fetcher 19 20 import ( 21 "errors" 22 "github.com/annchain/OG/arefactor/common/goroutine" 23 types2 "github.com/annchain/OG/arefactor/og/types" 24 "github.com/annchain/OG/og/protocol/dagmessage" 25 "github.com/annchain/OG/og/types" 26 "github.com/annchain/OG/og/types/archive" 27 28 "math/rand" 29 "time" 30 31 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 32 ) 33 34 const ( 35 arriveTimeout = 500 * time.Millisecond // Time allowance before an announced sequencer is explicitly requested 36 gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches 37 fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested sequencer 38 maxUncleDist = 7 // Maximum allowed backward distance from the chain head 39 maxQueueDist = 32 // Maximum allowed distance from the chain head to queue 40 hashLimit = 256 // Maximum number of unique sequencers a peer may have announced 41 sequencerLimit = 64 // Maximum number of unique sequencers a peer may have delivered 42 ) 43 44 var ( 45 errTerminated = errors.New("terminated") 46 ) 47 48 // sequencerRetrievalFn is a callback type for retrieving a sequencer from the local chain. 49 type sequencerRetrievalFn func(types2.Hash) *types.Sequencer 50 51 // headerRequesterFn is a callback type for sending a header retrieval request. 52 type headerRequesterFn func(peerId string, hash types2.Hash) error 53 54 // bodyRequesterFn is a callback type for sending a body retrieval request. 55 type bodyRequesterFn func(peerId string, hashs types2.Hashes) error 56 57 // chainHeightFn is a callback type to retrieve the current chain height. 58 type chainHeightFn func() uint64 59 60 // chainInsertFn is a callback type to insert a batch of sequencers into the local chain. 61 type chainInsertFn func(seq *types.Sequencer, txs types.Txis) error 62 63 // peerDropFn is a callback type for dropping a peer detected as malicious. 64 type peerDropFn func(id string) 65 66 // announce is the hash notification of the availability of a new sequencer in the 67 // network. 68 type announce struct { 69 hash types2.Hash // Hash of the sequencer being announced 70 number uint64 // Number of the sequencer being announced (0 = unknown | old protocol) 71 header *dagmessage.SequencerHeader // Header of the sequencer partially reassembled (new protocol) 72 time time.Time // Timestamp of the announcement 73 74 origin string // Identifier of the peer originating the notification 75 76 fetchHeader headerRequesterFn // Fetcher function to retrieve the header of an announced sequencer 77 fetchBodies bodyRequesterFn // Fetcher function to retrieve the body of an announced sequencer 78 } 79 80 // headerFilterTask represents a batch of headers needing fetcher filtering. 81 type headerFilterTask struct { 82 peer string // The source peer of sequencer headers 83 headers []*dagmessage.SequencerHeader // Collection of headers to filter 84 time time.Time // Arrival time of the headers 85 } 86 87 // bodyFilterTask represents a batch of sequencer bodies (transactions and uncles) 88 // needing fetcher filtering. 89 type bodyFilterTask struct { 90 peer string // The source peer of sequencer bodies 91 transactions []types.Txis // Collection of transactions per sequencer bodies 92 sequencers []*types.Sequencer 93 time time.Time // Arrival time of the sequencers' contents 94 } 95 96 // inject represents a schedules import operation. 97 type inject struct { 98 origin string 99 sequencer *types.Sequencer 100 } 101 102 // Fetcher is responsible for accumulating sequencer announcements from various peers 103 // and scheduling them for retrieval. 104 type Fetcher struct { 105 // Various event channels 106 notify chan *announce 107 inject chan *inject 108 109 sequencerFilter chan chan []*types.Sequencer 110 headerFilter chan chan *headerFilterTask 111 bodyFilter chan chan *bodyFilterTask 112 113 done chan types2.Hash 114 quit chan struct{} 115 116 // Announce states 117 announces map[string]int // Per peer announce counts to prevent memory exhaustion 118 announced map[types2.Hash][]*announce // Announced sequencers, scheduled for fetching 119 fetching map[types2.Hash]*announce // Announced sequencers, currently fetching 120 fetched map[types2.Hash][]*announce // sequencers with headers fetched, scheduled for body retrieval 121 completing map[types2.Hash]*announce // sequencers with headers, currently body-completing 122 123 // sequencer cache 124 queue *prque.Prque // Queue containing the import operations (sequencer number sorted) 125 queues map[string]int // Per peer sequencer counts to prevent memory exhaustion 126 queued map[types2.Hash]*inject // Set of already queued sequencers (to dedupe imports) 127 128 getsequencer sequencerRetrievalFn 129 130 chainHeight chainHeightFn // Retrieves the current chain's height 131 insertChain chainInsertFn // Injects a batch of sequencers into the chain 132 dropPeer peerDropFn // Drops a peer for misbehaving 133 134 // Testing hooks 135 announceChangeHook func(types2.Hash, bool) // Method to call upon adding or deleting a hash from the announce list 136 queueChangeHook func(types2.Hash, bool) // Method to call upon adding or deleting a sequencer from the import queue 137 fetchingHook func(types2.Hashes) // Method to call upon starting a sequencer (eth/61) or header (eth/62) fetch 138 completingHook func(types2.Hashes) // Method to call upon starting a sequencer body fetch (eth/62) 139 importedHook func(sequencer *types.Sequencer) // Method to call upon successful sequencer import (both eth/61 and eth/62) 140 } 141 142 // New creates a sequencer fetcher to retrieve sequencers based on hash announcements. 143 func New(getsequencer sequencerRetrievalFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher { 144 return &Fetcher{ 145 notify: make(chan *announce), 146 inject: make(chan *inject), 147 sequencerFilter: make(chan chan []*types.Sequencer), 148 headerFilter: make(chan chan *headerFilterTask), 149 bodyFilter: make(chan chan *bodyFilterTask), 150 done: make(chan types2.Hash), 151 quit: make(chan struct{}), 152 announces: make(map[string]int), 153 announced: make(map[types2.Hash][]*announce), 154 fetching: make(map[types2.Hash]*announce), 155 fetched: make(map[types2.Hash][]*announce), 156 completing: make(map[types2.Hash]*announce), 157 queue: prque.New(), 158 queues: make(map[string]int), 159 queued: make(map[types2.Hash]*inject), 160 getsequencer: getsequencer, 161 chainHeight: chainHeight, 162 insertChain: insertChain, 163 dropPeer: dropPeer, 164 } 165 } 166 167 // Start boots up the announcement based synchroniser, accepting and processing 168 // hash notifications and sequencer fetches until termination requested. 169 func (f *Fetcher) Start() { 170 goroutine.New(f.loop) 171 } 172 173 // Stop terminates the announcement based synchroniser, canceling all pending 174 // operations. 175 func (f *Fetcher) Stop() { 176 close(f.quit) 177 } 178 179 // Notify announces the fetcher of the potential availability of a new sequencer in 180 // the network. 181 func (f *Fetcher) Notify(peer string, hash types2.Hash, number uint64, time time.Time, 182 headerFetcher headerRequesterFn, bodyFetcher bodyRequesterFn) error { 183 sequencer := &announce{ 184 hash: hash, 185 number: number, 186 time: time, 187 origin: peer, 188 fetchHeader: headerFetcher, 189 fetchBodies: bodyFetcher, 190 } 191 select { 192 case f.notify <- sequencer: 193 return nil 194 case <-f.quit: 195 return errTerminated 196 } 197 } 198 199 // Enqueue tries to fill gaps the the fetcher's future import queue. 200 func (f *Fetcher) Enqueue(peer string, sequencer *types.Sequencer) error { 201 op := &inject{ 202 origin: peer, 203 sequencer: sequencer, 204 } 205 select { 206 case f.inject <- op: 207 return nil 208 case <-f.quit: 209 return errTerminated 210 } 211 } 212 213 // FilterHeaders extracts all the headers that were explicitly requested by the fetcher, 214 // returning those that should be handled differently. 215 func (f *Fetcher) FilterHeaders(peer string, headers dagmessage.SequencerHeaders, time time.Time) []*dagmessage.SequencerHeader { 216 log.WithField("peer", peer).WithField("headers", headers).Trace( 217 "Filtering headers") 218 219 // Send the filter channel to the fetcher 220 filter := make(chan *headerFilterTask) 221 222 select { 223 case f.headerFilter <- filter: 224 case <-f.quit: 225 return nil 226 } 227 // Request the filtering of the header list 228 select { 229 case filter <- &headerFilterTask{peer: peer, headers: headers, time: time}: 230 case <-f.quit: 231 return nil 232 } 233 // Retrieve the headers remaining after filtering 234 select { 235 case task := <-filter: 236 return task.headers 237 case <-f.quit: 238 return nil 239 } 240 } 241 242 // FilterBodies extracts all the sequencer bodies that were explicitly requested by 243 // the fetcher, returning those that should be handled differently. 244 func (f *Fetcher) FilterBodies(peer string, transactions []types.Txis, sequencers archive.Sequencers, time time.Time) []types.Txis { 245 log.WithField("txs", len(transactions)).WithField("sequencers ", sequencers).WithField( 246 "peer", peer).Trace("Filtering bodies") 247 248 // Send the filter channel to the fetcher 249 filter := make(chan *bodyFilterTask) 250 251 select { 252 case f.bodyFilter <- filter: 253 case <-f.quit: 254 return nil 255 } 256 // Request the filtering of the body list 257 select { 258 case filter <- &bodyFilterTask{peer: peer, transactions: transactions, sequencers: sequencers, time: time}: 259 case <-f.quit: 260 return nil 261 } 262 // Retrieve the bodies remaining after filtering 263 select { 264 case task := <-filter: 265 return task.transactions 266 case <-f.quit: 267 return nil 268 } 269 } 270 271 // Loop is the main fetcher loop, checking and processing various notification 272 // events. 273 func (f *Fetcher) loop() { 274 // Iterate the sequencer fetching until a quit is requested 275 fetchTimer := time.NewTimer(0) 276 completeTimer := time.NewTimer(0) 277 278 for { 279 // Clean up any expired sequencer fetches 280 for hash, announce := range f.fetching { 281 if time.Since(announce.time) > fetchTimeout { 282 f.forgetHash(hash) 283 } 284 } 285 // Import any queued sequencers that could potentially fit 286 height := f.chainHeight() 287 for !f.queue.Empty() { 288 op := f.queue.PopItem().(*inject) 289 hash := op.sequencer.GetHash() 290 if f.queueChangeHook != nil { 291 f.queueChangeHook(hash, false) 292 } 293 // If too high up the chain or phase, continue later 294 number := op.sequencer.Number() 295 if number > height+1 { 296 f.queue.Push(op, -float32(number)) 297 if f.queueChangeHook != nil { 298 f.queueChangeHook(hash, true) 299 } 300 break 301 } 302 // Otherwise if fresh and still unknown, try and import 303 if number+maxUncleDist < height || f.getsequencer(hash) != nil { 304 f.forgetsequencer(hash) 305 continue 306 } 307 //todo 308 f.insert(op.origin, op.sequencer, nil) 309 } 310 // Wait for an outside event to occur 311 select { 312 case <-f.quit: 313 // Fetcher terminating, abort all operations 314 return 315 316 case notification := <-f.notify: 317 // A sequencer was announced, make sure the peer isn't DOSing us 318 propAnnounceInMeter.Mark(1) 319 320 count := f.announces[notification.origin] + 1 321 if count > hashLimit { 322 log.WithField("peer", notification.origin).WithField( 323 "limit", hashLimit).Debug("Sender exceeded outstanding announces") 324 propAnnounceDOSMeter.Mark(1) 325 break 326 } 327 // If we have a valid sequencer number, check that it's potentially useful 328 if notification.number > 0 { 329 if dist := int64(notification.number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { 330 log.WithField("peer", notification.origin).WithField("number", notification.number).WithField( 331 "hash", notification.hash).WithField("distance", dist).Debug("Sender discarded announcement") 332 propAnnounceDropMeter.Mark(1) 333 break 334 } 335 } 336 // All is well, schedule the announce if sequencer's not yet downloading 337 if _, ok := f.fetching[notification.hash]; ok { 338 break 339 } 340 if _, ok := f.completing[notification.hash]; ok { 341 break 342 } 343 f.announces[notification.origin] = count 344 f.announced[notification.hash] = append(f.announced[notification.hash], notification) 345 if f.announceChangeHook != nil && len(f.announced[notification.hash]) == 1 { 346 f.announceChangeHook(notification.hash, true) 347 } 348 if len(f.announced) == 1 { 349 f.rescheduleFetch(fetchTimer) 350 } 351 352 case op := <-f.inject: 353 // A direct sequencer insertion was requested, try and fill any pending gaps 354 propBroadcastInMeter.Mark(1) 355 f.enqueue(op.origin, op.sequencer) 356 357 case hash := <-f.done: 358 // A pending import finished, remove all traces of the notification 359 f.forgetHash(hash) 360 f.forgetsequencer(hash) 361 362 case <-fetchTimer.C: 363 // At least one sequencer's timer ran out, check for needing retrieval 364 request := make(map[string]types2.Hashes) 365 366 for hash, announces := range f.announced { 367 if time.Since(announces[0].time) > arriveTimeout-gatherSlack { 368 // Pick a random peer to retrieve from, reset all others 369 announce := announces[rand.Intn(len(announces))] 370 f.forgetHash(hash) 371 372 // If the sequencer still didn't arrive, queue for fetching 373 if f.getsequencer(hash) == nil { 374 request[announce.origin] = append(request[announce.origin], hash) 375 f.fetching[hash] = announce 376 } 377 } 378 } 379 // Send out all sequencer header requests 380 for peer, hashes := range request { 381 log.WithField("peer", peer).WithField("list", hashes).Trace( 382 "Fetching scheduled headers") 383 384 // Create a closure of the fetch and schedule in on a new thread 385 fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes 386 function := func() { 387 defer goroutine.DumpStack(true) 388 if f.fetchingHook != nil { 389 f.fetchingHook(hashes) 390 } 391 for _, hash := range hashes { 392 headerFetchMeter.Mark(1) 393 fetchHeader(peer, hash) // Suboptimal, but protocol doesn't allow batch header retrievals 394 } 395 } 396 goroutine.New(function) 397 } 398 // Schedule the next fetch if sequencers are still pending 399 f.rescheduleFetch(fetchTimer) 400 401 case <-completeTimer.C: 402 // At least one header's timer ran out, retrieve everything 403 request := make(map[string]types2.Hashes) 404 405 for hash, announces := range f.fetched { 406 // Pick a random peer to retrieve from, reset all others 407 announce := announces[rand.Intn(len(announces))] 408 f.forgetHash(hash) 409 410 // If the sequencer still didn't arrive, queue for completion 411 if f.getsequencer(hash) == nil { 412 request[announce.origin] = append(request[announce.origin], hash) 413 f.completing[hash] = announce 414 } 415 } 416 // Send out all sequencer body requests 417 for peer, hashes := range request { 418 log.WithField("peer", peer).WithField("list", hashes).Trace( 419 "Fetching scheduled bodies") 420 421 // Create a closure of the fetch and schedule in on a new thread 422 if f.completingHook != nil { 423 f.completingHook(hashes) 424 } 425 bodyFetchMeter.Mark(int64(len(hashes))) 426 function := func() { f.completing[hashes[0]].fetchBodies(peer, hashes) } 427 goroutine.New(function) 428 } 429 // Schedule the next fetch if sequencers are still pending 430 f.rescheduleComplete(completeTimer) 431 432 case filter := <-f.headerFilter: 433 // Headers arrived from a remote peer. Extract those that were explicitly 434 // requested by the fetcher, and return everything else so it's delivered 435 // to other parts of the system. 436 var task *headerFilterTask 437 select { 438 case task = <-filter: 439 case <-f.quit: 440 return 441 } 442 headerFilterInMeter.Mark(int64(len(task.headers))) 443 444 // Split the batch of headers into unknown ones (to return to the caller), 445 // known incomplete ones (requiring body retrievals) and completed sequencers. 446 unknown, incomplete, complete := []*dagmessage.SequencerHeader{}, []*announce{}, []*types.Sequencer{} 447 for _, header := range task.headers { 448 hash := header.GetHash() 449 450 // Filter fetcher-requested headers from other synchronisation algorithms 451 if announce := f.fetching[hash]; announce != nil && announce.origin == task.peer && f.fetched[hash] == nil && f.completing[hash] == nil && f.queued[hash] == nil { 452 // If the delivered header does not match the promised number, drop the announcer 453 if header.SequencerId() != announce.number { 454 log.WithField("peer", announce.origin).WithField("hash", header.GetHash()).WithField("announced", announce.number).WithField( 455 "provided", header.SequencerId()).Debug("Invalid sequencer number fetched") 456 f.dropPeer(announce.origin) 457 f.forgetHash(hash) 458 continue 459 } 460 // Only keep if not imported by other means 461 if f.getsequencer(hash) == nil { 462 announce.header = header 463 announce.time = task.time 464 465 // Otherwise add to the list of sequencers needing completion 466 incomplete = append(incomplete, announce) 467 } else { 468 log.WithField("peer", announce.origin).WithField("hash", header.GetHash()).WithField( 469 "number", header.SequencerId()).Debug("quencer already imported, discarding header") 470 471 f.forgetHash(hash) 472 } 473 } else { 474 // Fetcher doesn't know about it, add to the return list 475 unknown = append(unknown, header) 476 } 477 } 478 headerFilterOutMeter.Mark(int64(len(unknown))) 479 select { 480 case filter <- &headerFilterTask{headers: unknown, time: task.time}: 481 case <-f.quit: 482 return 483 } 484 // Schedule the retrieved headers for body completion 485 for _, announce := range incomplete { 486 hash := announce.header.GetHash() 487 if _, ok := f.completing[hash]; ok { 488 continue 489 } 490 f.fetched[hash] = append(f.fetched[hash], announce) 491 if len(f.fetched) == 1 { 492 f.rescheduleComplete(completeTimer) 493 } 494 } 495 // Schedule the header-only sequencers for import 496 for _, sequencer := range complete { 497 if announce := f.completing[sequencer.GetHash()]; announce != nil { 498 f.enqueue(announce.origin, sequencer) 499 } 500 } 501 502 case filter := <-f.bodyFilter: 503 // sequencer bodies arrived, extract any explicitly requested sequencers, return the rest 504 var task *bodyFilterTask 505 select { 506 case task = <-filter: 507 case <-f.quit: 508 return 509 } 510 bodyFilterInMeter.Mark(int64(len(task.transactions))) 511 sequencers := []*types.Sequencer{} 512 bodyFilterOutMeter.Mark(int64(len(task.transactions))) 513 select { 514 case filter <- task: 515 case <-f.quit: 516 return 517 } 518 // Schedule the retrieved sequencers for ordered import 519 for _, sequencer := range sequencers { 520 if announce := f.completing[sequencer.GetHash()]; announce != nil { 521 f.enqueue(announce.origin, sequencer) 522 } 523 } 524 } 525 } 526 } 527 528 // rescheduleFetch resets the specified fetch timer to the next announce timeout. 529 func (f *Fetcher) rescheduleFetch(fetch *time.Timer) { 530 // Short circuit if no sequencers are announced 531 if len(f.announced) == 0 { 532 return 533 } 534 // Otherwise find the earliest expiring announcement 535 earliest := time.Now() 536 for _, announces := range f.announced { 537 if earliest.After(announces[0].time) { 538 earliest = announces[0].time 539 } 540 } 541 fetch.Reset(arriveTimeout - time.Since(earliest)) 542 } 543 544 // rescheduleComplete resets the specified completion timer to the next fetch timeout. 545 func (f *Fetcher) rescheduleComplete(complete *time.Timer) { 546 // Short circuit if no headers are fetched 547 if len(f.fetched) == 0 { 548 return 549 } 550 // Otherwise find the earliest expiring announcement 551 earliest := time.Now() 552 for _, announces := range f.fetched { 553 if earliest.After(announces[0].time) { 554 earliest = announces[0].time 555 } 556 } 557 complete.Reset(gatherSlack - time.Since(earliest)) 558 } 559 560 // enqueue schedules a new future import operation, if the sequencer to be imported 561 // has not yet been seen. 562 func (f *Fetcher) enqueue(peer string, sequencer *types.Sequencer) { 563 hash := sequencer.GetHash() 564 565 // Ensure the peer isn't DOSing us 566 count := f.queues[peer] + 1 567 if count > sequencerLimit { 568 log.WithField("peer", peer).WithField("number", sequencer.Number()).WithField("hash", hash).WithField( 569 "limit", sequencerLimit).Debug("Discarded propagated sequencer, exceeded allowance") 570 propBroadcastDOSMeter.Mark(1) 571 f.forgetHash(hash) 572 return 573 } 574 // Discard any past or too distant sequencers 575 if dist := int64(sequencer.Number()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { 576 log.WithField("peer", peer).WithField("number", sequencer.Number()).WithField("hash", hash).WithField("distance", dist) 577 propBroadcastDropMeter.Mark(1) 578 f.forgetHash(hash) 579 return 580 } 581 // Schedule the sequencer for future importing 582 if _, ok := f.queued[hash]; !ok { 583 op := &inject{ 584 origin: peer, 585 sequencer: sequencer, 586 } 587 f.queues[peer] = count 588 f.queued[hash] = op 589 f.queue.Push(op, -float32(sequencer.Number())) 590 if f.queueChangeHook != nil { 591 f.queueChangeHook(op.sequencer.GetHash(), true) 592 } 593 log.WithField("peer", peer).WithField("Number", sequencer.Number()).WithField("hash", hash).WithField( 594 "queued", f.queue.Size()).Debug("Queued propagated sequencer") 595 } 596 } 597 598 // insert spawns a new goroutine to run a sequencer insertion into the chain. If the 599 // sequencer's number is at the same height as the current import phase, it updates 600 // the phase states accordingly. 601 func (f *Fetcher) insert(peer string, sequencer *types.Sequencer, txs types.Txis) { 602 hash := sequencer.GetHash() 603 604 // Run the import on a new thread 605 log.WithField("peer", peer).WithField("number", sequencer.Number()).WithField( 606 "hash", hash).Debug("Importing propagated sequencer") 607 function := func() { 608 defer func() { f.done <- hash }() 609 610 // Run the actual import and log any issues 611 if err := f.insertChain(sequencer, txs); err != nil { 612 log.WithField("peer", peer).WithField("number", sequencer.Number()).WithField( 613 "hash", hash).WithError(err).Debug("Propagated sequencer import failed") 614 return 615 } 616 617 // Invoke the testing hook if needed 618 if f.importedHook != nil { 619 f.importedHook(sequencer) 620 } 621 } 622 goroutine.New(function) 623 } 624 625 // forgetHash removes all traces of a sequencer announcement from the fetcher's 626 // internal state. 627 func (f *Fetcher) forgetHash(hash types2.Hash) { 628 // Remove all pending announces and decrement DOS counters 629 for _, announce := range f.announced[hash] { 630 f.announces[announce.origin]-- 631 if f.announces[announce.origin] == 0 { 632 delete(f.announces, announce.origin) 633 } 634 } 635 delete(f.announced, hash) 636 if f.announceChangeHook != nil { 637 f.announceChangeHook(hash, false) 638 } 639 // Remove any pending fetches and decrement the DOS counters 640 if announce := f.fetching[hash]; announce != nil { 641 f.announces[announce.origin]-- 642 if f.announces[announce.origin] == 0 { 643 delete(f.announces, announce.origin) 644 } 645 delete(f.fetching, hash) 646 } 647 648 // Remove any pending completion requests and decrement the DOS counters 649 for _, announce := range f.fetched[hash] { 650 f.announces[announce.origin]-- 651 if f.announces[announce.origin] == 0 { 652 delete(f.announces, announce.origin) 653 } 654 } 655 delete(f.fetched, hash) 656 657 // Remove any pending completions and decrement the DOS counters 658 if announce := f.completing[hash]; announce != nil { 659 f.announces[announce.origin]-- 660 if f.announces[announce.origin] == 0 { 661 delete(f.announces, announce.origin) 662 } 663 delete(f.completing, hash) 664 } 665 } 666 667 // forgetsequencer removes all traces of a queued sequencer from the fetcher's internal 668 // state. 669 func (f *Fetcher) forgetsequencer(hash types2.Hash) { 670 if insert := f.queued[hash]; insert != nil { 671 f.queues[insert.origin]-- 672 if f.queues[insert.origin] == 0 { 673 delete(f.queues, insert.origin) 674 } 675 delete(f.queued, hash) 676 } 677 }