code: func (b *BloomTrieIndexerBackend) fetchMissingNodes(ctx context.Context, section uint64, root common.Hash) error {
  	indexCh := make(chan uint, types.BloomBitLength)
  	type res struct {
  		nodes *NodeSet
  		err   error
  	}
  	resCh := make(chan res, types.BloomBitLength)
  	for i := 0; i < 20; i++ {
  		go func() {
  			for bitIndex := range indexCh {
  				r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIndexList: []uint64{section - 1}, Config: b.odr.IndexerConfig()}
  				for {
  					if err := b.odr.Retrieve(ctx, r); err == ErrNoPeers {
  						// if there are no peers to serve, retry later
  						select {
  						case <-ctx.Done():
  							resCh <- res{nil, ctx.Err()}
  							return
  						case <-time.After(time.Second * 10):
  							// stay in the loop and try again
  						}
  					} else {
  						resCh <- res{r.Proofs, err}
  						break
  					}
  				}
  			}
  		}()
  	}
  
  	for i := uint(0); i < types.BloomBitLength; i++ {
  		indexCh <- i
  	}
  	close(indexCh)
  	batch := b.trieTable.NewBatch()
  	for i := uint(0); i < types.BloomBitLength; i++ {
  		res := <-resCh
  		if res.err != nil {
  			return res.err
  		}
  		res.nodes.Store(batch)
  	}
  	return batch.Write()
  }
docs: // fetchMissingNodes tries to retrieve the last entries of the latest trusted bloom trie from the
  // ODR backend in order to be able to add new entries and calculate subsequent root hashes