code: func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
  	// Sanity check that we have something meaningful to import
  	if len(chain) == 0 {
  		return 0, nil
  	}
  
  	bc.blockProcFeed.Send(true)
  	defer bc.blockProcFeed.Send(false)
  
  	// Remove already known canon-blocks
  	var (
  		block, prev *types.Block
  	)
  	// Do a sanity check that the provided chain is actually ordered and linked
  	for i := 1; i < len(chain); i++ {
  		block = chain[i]
  		prev = chain[i-1]
  		if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() {
  			// Chain broke ancestry, log a message (programming error) and skip insertion
  			log.Error("Non contiguous block insert", "number", block.Number(), "hash", block.Hash(),
  				"parent", block.ParentHash(), "prevnumber", prev.Number(), "prevhash", prev.Hash())
  
  			return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, prev.NumberU64(),
  				prev.Hash().Bytes()[:4], i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4])
  		}
  	}
  	// Pre-checks passed, start the full block imports
  	bc.wg.Add(1)
  	bc.chainmu.Lock()
  	n, events, logs, err := bc.insertChain(chain, true)
  	bc.chainmu.Unlock()
  	bc.wg.Done()
  
  	bc.PostChainEvents(events, logs)
  	return n, err
  }
docs: // InsertChain attempts to insert the given batch of blocks in to the canonical
  // chain or, otherwise, create a fork. If an error is returned it will return
  // the index number of the failing block as well an error describing what went
  // wrong.
  //
  // After insertion is done, all accumulated events will be fired.