code: func (c *Chain) getInFlightConfChange() *raftpb.ConfChange {
  	if c.confChangeInProgress != nil {
  		return c.confChangeInProgress
  	}
  
  	if c.lastBlock.Header.Number == 0 {
  		return nil // nothing to failover just started the chain
  	}
  
  	if !utils.IsConfigBlock(c.lastBlock) {
  		return nil
  	}
  
  	// Detect if it is a restart right after consensus-type migration. If yes, return early in order to avoid using
  	// the block metadata as etcdraft.BlockMetadata (see below). Right after migration the block metadata will carry
  	// Kafka metadata. The etcdraft.BlockMetadata should be extracted from the ConsensusType.Metadata, instead.
  	if c.detectMigration() {
  		c.logger.Infof("Restarting after consensus-type migration. Type: %s, just starting the chain.", c.support.SharedConfig().ConsensusType())
  		return nil
  	}
  
  	// extracting current Raft configuration state
  	confState := c.Node.ApplyConfChange(raftpb.ConfChange{})
  
  	if len(confState.Nodes) == len(c.opts.BlockMetadata.ConsenterIds) {
  		// Raft configuration change could only add one node or
  		// remove one node at a time, if raft conf state size is
  		// equal to membership stored in block metadata field,
  		// that means everything is in sync and no need to propose
  		// config update.
  		return nil
  	}
  
  	return ConfChange(c.opts.BlockMetadata, confState)
  }
docs: // getInFlightConfChange returns ConfChange in-flight if any.
  // It returns confChangeInProgress if it is not nil. Otherwise
  // it returns ConfChange from the last committed block (might be nil).