[以太坊源码学习] Etherum Backend启动的过程

在上一篇博客 [乙太坊源码学习] 乙太坊node的启动过程 中,我们在其中提到了 Ethereum Backend的启动过程,大体总结一下就是:

(1)以太坊节点注册Ethereum Backend的构造函数

(2)以太坊节点在启动的过程中,调用构造函数,生成Backend,然后启动它。

这是一个很简略和过程,下面我们就详细的学习一下Ethereum Backend及它的启动过程。


1. Ethereum结构体代码

type Ethereum struct {
   config      *Config  //这是配置信息,下面再细说
   chainConfig *params.ChainConfig   //这是区块链的配置信息

   // Channel for shutting down the service
   shutdownChan  chan bool    // 关闭该线程的标志位,通过goroutin+channel的形式实现。当需要关闭该线程时,只需要往该channel中发送一个bool值就行了
   stopDbUpgrade func() error // 这是一个函数句柄,用于关闭该线程时,提示关闭数据库写入的

   // Handlers
   txPool          *core.TxPool    //交易池,用来缓存未处理的交易的
   blockchain      *core.BlockChain    //区块链对象
   protocolManager *ProtocolManager    //协议管理器
   lesServer       LesServer    //暂时不知道是做什么的

   // DB interfaces
   chainDb ethdb.Database // 数据库对象

   eventMux       *event.TypeMux    //事件的收听器和分发器
   engine         consensus.Engqine    //共识算法的引擎,目前用的pow
   accountManager *accounts.Manager    //账户管理器

   bloomRequests chan chan *bloombits.Retrieval // 缓存bloom数据接收请求的管道。Channel receiving bloom data retrieval requests
   bloomIndexer  *core.ChainIndexer             // 对Bloom数据创建索引的工具。 Bloom indexer operating during block imports

   ApiBackend *EthApiBackend  //Backend接口的封装体,其实里面就是一堆函数

   miner     *miner.Miner  //矿工
   gasPrice  *big.Int //gas价格
   etherbase common.Address  //矿工收取奖励的地址

   networkId     uint64  //P2P网络的id
   netRPCService *ethapi.PublicNetAPI    //P2P 服务一些接口的封装体,其实就是一些简单的函数

   lock sync.RWMutex // 对本结构体进行改写的时候,需要加锁。Protects the variadic fields (e.g. gas price and etherbase)
}

通过这个结构体所包含的成员变量来看,Ethereum Backend的功能覆盖了账号管理、共识、挖矿、协议管理、数据库写入等等比较核心的功能环节,可见它是乙太坊的核心程序。

Ethereum Backend其实实现了node/service.go中的Service接口,该接口有三个方法:

type Service interface {
   // Protocols retrieves the P2P protocols the service wishes to start.
   Protocols() []p2p.Protocol

   // APIs retrieves the list of RPC descriptors the service provides
   APIs() []rpc.API

   // Start is called after all services have been constructed and the networking
   // layer was also initialized to spawn any goroutines required by the service.
   Start(server *p2p.Server) error

   // Stop terminates all goroutines belonging to the service, blocking until they
   // are all terminated.
   Stop() error
}

Etherem实现了4个方法,以提供Service的功能。这几个方法,我们稍后会渐渐提到。


2. Ethereum的创建方法New

func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
   log.Info(">>>>>>>>> Will create backend with config: ", "config", config)
   log.Info(">>>>>>>>> Will create backend with context: ", "context", ctx)
   _,file,line,_ := runtime.Caller(2)

   log.Info(">>>>>>>>>> backend.New() Caller: ", "file", file, "line", line)

   if config.SyncMode == downloader.LightSync {
      return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
   }
   if !config.SyncMode.IsValid() {
      return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
   }
   chainDb, err := CreateDB(ctx, config, "chaindata")
   if err != nil {
      return nil, err
   }
   stopDbUpgrade := upgradeDeduplicateData(chainDb)
   chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
   log.Info(">>>>>>>>> Genesis Block created: ", "genesis", genesisHash)

   if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
      return nil, genesisErr
   }
   log.Info("Initialised chain configuration", "config", chainConfig)

   eth := &Ethereum{
      config:         config,
      chainDb:        chainDb,
      chainConfig:    chainConfig,
      eventMux:       ctx.EventMux,
      accountManager: ctx.AccountManager,
      engine:         CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb),
      shutdownChan:   make(chan bool),
      stopDbUpgrade:  stopDbUpgrade,
      networkId:      config.NetworkId,
      gasPrice:       config.GasPrice,
      etherbase:      config.Etherbase,
      bloomRequests:  make(chan chan *bloombits.Retrieval),
      bloomIndexer:   NewBloomIndexer(chainDb, params.BloomBitsBlocks),
   }

   log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)

   log.Info(">>>>>>>>> Backend created: ", "backend", eth)

   if !config.SkipBcVersionCheck {
      bcVersion := core.GetBlockChainVersion(chainDb)
      if bcVersion != core.BlockChainVersion && bcVersion != 0 {
         return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion)
      }
      core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
   }
   var (
      vmConfig    = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
      cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
   )
   log.Info(">>>>>>>>> VM config created: ")
   log.Info(">>>>>>>>> Cache config created: ", "cacheconfig", cacheConfig)


   eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig)
   log.Info(">>>>>>>>> Blockchain created: ")

   if err != nil {
      return nil, err
   }
   // Rewind the chain in case of an incompatible config upgrade.
   if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
      log.Warn("Rewinding chain to upgrade configuration", "err", compat)
      eth.blockchain.SetHead(compat.RewindTo)
      core.WriteChainConfig(chainDb, genesisHash, chainConfig)
   }
   eth.bloomIndexer.Start(eth.blockchain)

   if config.TxPool.Journal != "" {
      config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
      log.Info(">>>>>>>>> TxPool Journal created: ", "journal", config.TxPool.Journal)
   }
   eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)

   log.Info(">>>>>>>>> Txpool created: ", "txpool", eth.txPool)

   if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil {
      return nil, err
   }
   eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)
   eth.miner.SetExtra(makeExtraData(config.ExtraData))
   log.Info(">>>>>>>>> Miner created: ", "miner", eth.miner)

   eth.ApiBackend = &EthApiBackend{eth, nil}
   gpoParams := config.GPO
   if gpoParams.Default == nil {
      gpoParams.Default = config.GasPrice
   }
   eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, gpoParams)
   log.Info(">>>>>>>>> Backend create finished: ", "backend", eth)

   return eth, nil
}

未完待续

你可能感兴趣的:(区块链)