天天看點

filecoin技術架構分析之十五:filecoin源碼分析之節點運作邏輯

本文作者:楊尉;原創作品,轉載請注明出處

上一篇:filecoin技術架構分析之十四:filecoin源碼分析之服務層鍊同步、共識協定及挖礦

下一篇: filecoin技術架構分析之十六:go-filecoin總結篇–待續

目錄

  • 15.filecoin源碼分析之節點運作邏輯
    • 15.1 前提
    • 15.2 filecoin節點運作邏輯簡析
      • 15.2.1 基本資料結構
      • 15.2.2 建立filecoin節點執行個體
      • 15.2.3 啟動及停止filecoin節點
      • 15.2.4 啟動及停止挖礦
    • 15.3 階段性分析結束說明
分析基于的源碼版本:go-filecoin master a0598a54(2019年3月9日)

15.1 前提

  • 我們在前面的章節已經經過了三個階段的梳理分析
    • 概念階段,包括概念、通用語言了解、開發網絡使用
    • 頂層架構與概念的結合了解
    • 具體源碼的簡析,包括協定層、支撐包、内部api層、服務層
  • 源碼部分的command部分比較容易了解,就不單獨文章贅述了,基本與内部api層都可以對應起來
  • 現在再來看節點的運作邏輯應該會更加清晰了

15.2 filecoin節點運作邏輯簡析

15.2.1 基本資料結構

▼ package
    node

▶ imports

▼ variables
   +ErrNoMinerAddress
   -filecoinDHTProtocol : dhtprotocol.ID
   -log

   // 建立具體的filecoin節點執行個體
▼+Config : struct
    [fields]
    // 設定區塊時間
   +BlockTime : time.Duration
    // 配置節點是否轉發
   +IsRelay : bool
    // libp2p選項
   +Libp2pOpts : []libp2p.Option
    // 在離線模式下,會關閉libp2p
   +OfflineMode : bool
    // 配置資源
   +Repo : repo.Repo
    // 配置區塊獎勵方法
   +Rewarder : consensus.BlockRewarder
    // 配置節點時空證明校驗函數
   +Verifier : proofs.Verifier
    [methods]
    // 建立node執行個體
   +Build(ctx context.Context) : *Node, error
   -buildHost(ctx context.Context, makeDHT func(host host.Host) routing.IpfsRouting, error) : host.Host, error

 +ConfigOpt : func(*Config) error

▼+Node : struct
    [fields]
    // 确認最新區塊,本地持久化并廣播
   +AddNewlyMinedBlock : newBlockFunc
    // 訂閱主題"/fil/blocks"
   +BlockSub : pubsub.Subscription
    // 塊服務接口
   +Blockstore : bstore.Blockstore
    // 維持相關節點連接配接
   +Bootstrapper : *net.Bootstrapper
    // 讀取區塊資訊
   +ChainReader : chain.ReadStore
    // 同時協定
   +Consensus : consensus.Protocol
    // 塊交換,節點間的資料交換
   +Exchange : exchange.Interface
    // new-head 主題
   +HeaviestTipSetCh : chan interface{}
    // 新區塊處理請求
   +HeaviestTipSetHandled : func()
    // hello服務
   +HelloSvc : *hello.Handler
    // 消息訂閱
   +MessageSub : pubsub.Subscription
    // 挖礦排程
   +MiningScheduler : mining.Scheduler
    // 消息池操作
   +MsgPool : *core.MessagePool
    // 離線模式
   +OfflineMode : bool
   +OnlineStore : *hamt.CborIpldStore
    // 對應libp2p中的host
   +PeerHost : host.Host
    // libp2p中的ping service
   +Ping : *ping.PingService
    // 高層api
   +PorcelainAPI : *porcelain.API
    // 功率表
   +PowerTable : consensus.PowerTableView
    // 配置資源
   +Repo : repo.Repo
    // 檢索用戶端
   +RetrievalClient : *retrieval.Client
    // 檢索礦工
   +RetrievalMiner : *retrieval.Miner
    // 路由,libp2p
   +Router : routing.IpfsRouting
    // 存儲礦工
   +StorageMiner : *storage.Miner
    // 存儲客戶
   +StorageMinerClient : *storage.Client
    // 鍊同步
   +Syncer : chain.Syncer
    // 錢包管理
   +Wallet : *wallet.Wallet
   -blockTime : time.Duration
   -blockservice : bserv.BlockService
   -cancelMining : context.CancelFunc
   -cancelSubscriptionsCtx : context.CancelFunc
   -cborStore : *hamt.CborIpldStore
   -host : host.Host
   -lookup : lookup.PeerLookupService
   -mining
   -miningCtx : context.Context
   -miningDoneWg : *sync.WaitGroup
   -sectorBuilder : sectorbuilder.SectorBuilder

    [methods]
   +BlockHeight() : *types.BlockHeight, error
   +BlockService() : bserv.BlockService
   +CborStore() : *hamt.CborIpldStore
   +ChainReadStore() : chain.ReadStore
    // 建立礦工方法
   +CreateMiner(ctx context.Context, accountAddr address.Address, gasPrice types.AttoFIL, gasLimit types.GasUnits, pledge uint64, pid libp2ppeer.ID, collateral *types.AttoFIL) : *address.Address, error
   +GetBlockTime() : time.Duration
   +Host() : host.Host
    // 節點查找方法
   +Lookup() : lookup.PeerLookupService
   +MiningSignerAddress() : address.Address
   +MiningTimes() : time.Duration, time.Duration
    // 建立新的account位址,錢包位址
   +NewAddress() : address.Address, error
   +SectorBuilder() : sectorbuilder.SectorBuilder
   +SetBlockTime(blockTime time.Duration)
    // 啟動節點
   +Start(ctx context.Context) : error
    // 啟動挖礦
   +StartMining(ctx context.Context) : error
    // 停止節點
   +Stop(ctx context.Context)
    // 停止挖礦
   +StopMining(ctx context.Context)
   -addNewlyMinedBlock(ctx context.Context, b *types.Block)
   -cancelSubscriptions()
   -getLastUsedSectorID(ctx context.Context, minerAddr address.Address) : uint64, error
   -getMinerActorPubKey() : []byte, error
   -handleNewHeaviestTipSet(ctx context.Context, head types.TipSet)
   -handleNewMiningOutput(miningOutCh chan mining.Output)
   -handleSubscription(ctx context.Context, f pubSubProcessorFunc, fname string, s pubsub.Subscription, sname string)
   -isMining() : bool
   -miningAddress() : address.Address, error
   -miningOwnerAddress(ctx context.Context, miningAddr address.Address) : address.Address, error
   -saveMinerConfig(minerAddr address.Address, signerAddr address.Address) : error
   -setIsMining(isMining bool)
   -setupHeartbeatServices(ctx context.Context) : error
   -setupMining(ctx context.Context) : error
    [functions]
    // 調用Build建立node執行個體
   +New(ctx context.Context, opts ...ConfigOpt) : *Node, error

▼-blankValidator : struct
    [methods]
   +Select(_ string, _ [][]byte) : int, error
   +Validate(_ string, _ []byte) : error

 -newBlockFunc : func(context.Context, *types.Block)

 -pubSubProcessorFunc : func(ctx context.Context, msg pubsub.Message) error

▼ functions
   +BlockTime(blockTime time.Duration) : ConfigOpt
   +IsRelay() : ConfigOpt
   +Libp2pOptions(opts ...libp2p.Option) : ConfigOpt
   +OfflineMode(offlineMode bool) : ConfigOpt
   +RewarderConfigOption(rewarder consensus.BlockRewarder) : ConfigOpt
   +StartMining(ctx context.Context, node *Node) : error
   +VerifierConfigOption(verifier proofs.Verifier) : ConfigOpt
   -initSectorBuilderForNode(ctx context.Context, node *Node, sectorStoreType proofs.SectorStoreType) : sectorbuilder.SectorBuilder, error
   -initStorageMinerForNode(ctx context.Context, node *Node) : *storage.Miner, error
   -readGenesisCid(ds datastore.Datastore) : cid.Cid, error
           

15.2.2 建立filecoin節點執行個體

  • 執行個體化filecoin節點,簡析見如下添加的注釋
// Build instantiates a filecoin Node from the settings specified in the config.
func (nc *Config) Build(ctx context.Context) (*Node, error) {
	// 建立記憶體資源執行個體
	if nc.Repo == nil {
		nc.Repo = repo.NewInMemoryRepo()
	}

	// 建立塊服務執行個體
	bs := bstore.NewBlockstore(nc.Repo.Datastore())

	validator := blankValidator{}

	var peerHost host.Host
	var router routing.IpfsRouting

	// 帶寬統計執行個體,加入libp2popts
	bandwidthTracker := p2pmetrics.NewBandwidthCounter()
	nc.Libp2pOpts = append(nc.Libp2pOpts, libp2p.BandwidthReporter(bandwidthTracker))

	// 非離線模式才啟用libp2p
	if !nc.OfflineMode {
		makeDHT := func(h host.Host) (routing.IpfsRouting, error) {
			r, err := dht.New(
				ctx,
				h,
				dhtopts.Datastore(nc.Repo.Datastore()),
				dhtopts.NamespacedValidator("v", validator),
				dhtopts.Protocols(filecoinDHTProtocol),
			)
			if err != nil {
				return nil, errors.Wrap(err, "failed to setup routing")
			}
			router = r
			return r, err
		}

		var err error
		// 執行個體化非離線模式libp2p host
		peerHost, err = nc.buildHost(ctx, makeDHT)
		if err != nil {
			return nil, err
		}
	} else {
		// 離線模式處理
		router = offroute.NewOfflineRouter(nc.Repo.Datastore(), validator)
		peerHost = rhost.Wrap(noopLibP2PHost{}, router)
	}

	// ping服務執行個體
	// set up pinger
	pinger := ping.NewPingService(peerHost)

	// bitswap執行個體
	// set up bitswap
	nwork := bsnet.NewFromIpfsHost(peerHost, router)
	//nwork := bsnet.NewFromIpfsHost(innerHost, router)
	bswap := bitswap.New(ctx, nwork, bs)
	bservice := bserv.New(bs, bswap)

	cstOnline := hamt.CborIpldStore{Blocks: bservice}
	cstOffline := hamt.CborIpldStore{Blocks: bserv.New(bs, offline.Exchange(bs))}
	// 擷取創世塊cid
	genCid, err := readGenesisCid(nc.Repo.Datastore())
	if err != nil {
		return nil, err
	}

	// chain.Store執行個體以及功率表
	var chainStore chain.Store = chain.NewDefaultStore(nc.Repo.ChainDatastore(), &cstOffline, genCid)
	powerTable := &consensus.MarketView{}

	// 共識協定processor執行個體
	var processor consensus.Processor
	if nc.Rewarder == nil {
		processor = consensus.NewDefaultProcessor()
	} else {
		processor = consensus.NewConfiguredProcessor(consensus.NewDefaultMessageValidator(), nc.Rewarder)
	}

	// 共識協定執行個體
	var nodeConsensus consensus.Protocol
	if nc.Verifier == nil {
		nodeConsensus = consensus.NewExpected(&cstOffline, bs, processor, powerTable, genCid, &proofs.RustVerifier{})
	} else {
		nodeConsensus = consensus.NewExpected(&cstOffline, bs, processor, powerTable, genCid, nc.Verifier)
	}

	// 鍊同步,鍊讀取,消息池執行個體
	// only the syncer gets the storage which is online connected
	chainSyncer := chain.NewDefaultSyncer(&cstOnline, &cstOffline, nodeConsensus, chainStore)
	chainReader, ok := chainStore.(chain.ReadStore)
	if !ok {
		return nil, errors.New("failed to cast chain.Store to chain.ReadStore")
	}
	msgPool := core.NewMessagePool()

	// Set up libp2p pubsub
	fsub, err := libp2pps.NewFloodSub(ctx, peerHost)
	if err != nil {
		return nil, errors.Wrap(err, "failed to set up pubsub")
	}

	// 錢包服務執行個體
	backend, err := wallet.NewDSBackend(nc.Repo.WalletDatastore())
	if err != nil {
		return nil, errors.Wrap(err, "failed to set up wallet backend")
	}
	fcWallet := wallet.New(backend)

	// 執行個體化高層api
	PorcelainAPI := porcelain.New(plumbing.New(&plumbing.APIDeps{
		Chain:        chainReader,
		Config:       cfg.NewConfig(nc.Repo),
		Deals:        strgdls.New(nc.Repo.DealsDatastore()),
		MsgPool:      msgPool,
		MsgPreviewer: msg.NewPreviewer(fcWallet, chainReader, &cstOffline, bs),
		MsgQueryer:   msg.NewQueryer(nc.Repo, fcWallet, chainReader, &cstOffline, bs),
		MsgSender:    msg.NewSender(fcWallet, chainReader, msgPool, consensus.NewOutboundMessageValidator(), fsub.Publish),
		MsgWaiter:    msg.NewWaiter(chainReader, bs, &cstOffline),
		Network:      net.New(peerHost, pubsub.NewPublisher(fsub), pubsub.NewSubscriber(fsub), net.NewRouter(router), bandwidthTracker),
		SigGetter:    mthdsig.NewGetter(chainReader),
		Wallet:       fcWallet,
	}))

	// 執行個體化node
	nd := &Node{
		blockservice: bservice,
		Blockstore:   bs,
		cborStore:    &cstOffline,
		OnlineStore:  &cstOnline,
		Consensus:    nodeConsensus,
		ChainReader:  chainReader,
		Syncer:       chainSyncer,
		PowerTable:   powerTable,
		PorcelainAPI: PorcelainAPI,
		Exchange:     bswap,
		host:         peerHost,
		MsgPool:      msgPool,
		OfflineMode:  nc.OfflineMode,
		PeerHost:     peerHost,
		Ping:         pinger,
		Repo:         nc.Repo,
		Wallet:       fcWallet,
		blockTime:    nc.BlockTime,
		Router:       router,
	}

	// Bootstrapping network peers.
	periodStr := nd.Repo.Config().Bootstrap.Period
	period, err := time.ParseDuration(periodStr)
	if err != nil {
		return nil, errors.Wrapf(err, "couldn't parse bootstrap period %s", periodStr)
	}

	// 執行個體化Bootstrapper,指定node的該方法
	// Bootstrapper maintains connections to some subset of addresses
	ba := nd.Repo.Config().Bootstrap.Addresses
	bpi, err := net.PeerAddrsToPeerInfos(ba)
	if err != nil {
		return nil, errors.Wrapf(err, "couldn't parse bootstrap addresses [%s]", ba)
	}
	minPeerThreshold := nd.Repo.Config().Bootstrap.MinPeerThreshold
	nd.Bootstrapper = net.NewBootstrapper(bpi, nd.Host(), nd.Host().Network(), nd.Router, minPeerThreshold, period)

	// 執行個體化鍊查找服務,指定node的該方法
	// On-chain lookup service
	defaultAddressGetter := func() (address.Address, error) {
		return nd.PorcelainAPI.GetAndMaybeSetDefaultSenderAddress()
	}
	nd.lookup = lookup.NewChainLookupService(nd.ChainReader, defaultAddressGetter, bs)

	return nd, nil
}
           

15.2.3 啟動及停止filecoin節點

  • 啟動filecoin節點的流程概覽
// Start boots up the node.
func (node *Node) Start(ctx context.Context) error {
	// 加載本地chain資訊
	if err := node.ChainReader.Load(ctx); err != nil {
		return err
	}

	// 如果存在存儲礦工,配置挖礦功能
	// Only set these up if there is a miner configured.
	if _, err := node.miningAddress(); err == nil {
		if err := node.setupMining(ctx); err != nil {
			log.Errorf("setup mining failed: %v", err)
			return err
		}
	}

	// 設定鍊同步回調函數
	// Start up 'hello' handshake service
	syncCallBack := func(pid libp2ppeer.ID, cids []cid.Cid, height uint64) {
		// TODO it is possible the syncer interface should be modified to
		// make use of the additional context not used here (from addr + height).
		// To keep things simple for now this info is not used.
		err := node.Syncer.HandleNewBlocks(context.Background(), cids)
		if err != nil {
			log.Infof("error handling blocks: %s", types.NewSortedCidSet(cids...).String())
		}
	}
	// 執行個體化hello握手協定
	node.HelloSvc = hello.New(node.Host(), node.ChainReader.GenesisCid(), syncCallBack, node.ChainReader.Head)

	// 執行個體化存儲礦工協定
	cni := storage.NewClientNodeImpl(dag.NewDAGService(node.BlockService()), node.Host(), node.GetBlockTime())
	var err error
	node.StorageMinerClient, err = storage.NewClient(cni, node.PorcelainAPI)
	if err != nil {
		return errors.Wrap(err, "Could not make new storage client")
	}

	// 執行個體化檢索客戶及檢索礦工協定
	node.RetrievalClient = retrieval.NewClient(node)
	node.RetrievalMiner = retrieval.NewMiner(node)

	// 訂閱區塊通知
	// subscribe to block notifications
	blkSub, err := node.PorcelainAPI.PubSubSubscribe(BlockTopic)
	if err != nil {
		return errors.Wrap(err, "failed to subscribe to blocks topic")
	}
	node.BlockSub = blkSub

	// 訂閱消息通知
	// subscribe to message notifications
	msgSub, err := node.PorcelainAPI.PubSubSubscribe(msg.Topic)
	if err != nil {
		return errors.Wrap(err, "failed to subscribe to message topic")
	}
	node.MessageSub = msgSub

	cctx, cancel := context.WithCancel(context.Background())
	node.cancelSubscriptionsCtx = cancel

	// 啟用新線程訂閱區塊及消息主題,設定handle回調
	go node.handleSubscription(cctx, node.processBlock, "processBlock", node.BlockSub, "BlockSub")
	go node.handleSubscription(cctx, node.processMessage, "processMessage", node.MessageSub, "MessageSub")

	// 啟用新線程處理新的tipset事件
	node.HeaviestTipSetHandled = func() {}
	node.HeaviestTipSetCh = node.ChainReader.HeadEvents().Sub(chain.NewHeadTopic)
	go node.handleNewHeaviestTipSet(cctx, node.ChainReader.Head())

	// 非離線模式啟動bootstapper服務
	if !node.OfflineMode {
		node.Bootstrapper.Start(context.Background())
	}

	// 啟動心跳服務
	if err := node.setupHeartbeatServices(ctx); err != nil {
		return errors.Wrap(err, "failed to start heartbeat services")
	}

	return nil
}
           
  • 停止filecoin節點的流程概覽
釋放資源,停止相關服務
// Stop initiates the shutdown of the node.
func (node *Node) Stop(ctx context.Context) {
	node.ChainReader.HeadEvents().Unsub(node.HeaviestTipSetCh)
	// 停止挖礦
	node.StopMining(ctx)

	// 取消訂閱
	node.cancelSubscriptions()
	// 停止鍊讀取服務
	node.ChainReader.Stop()

	// 停止密封服務
	if node.SectorBuilder() != nil {
		if err := node.SectorBuilder().Close(); err != nil {
			fmt.Printf("error closing sector builder: %s\n", err)
		}
		node.sectorBuilder = nil
	}

	// 關閉host執行個體
	if err := node.Host().Close(); err != nil {
		fmt.Printf("error closing host: %s\n", err)
	}

	// 關閉資源執行個體
	if err := node.Repo.Close(); err != nil {
		fmt.Printf("error closing repo: %s\n", err)
	}

	// 關閉bootstqpper執行個體
	node.Bootstrapper.Stop()

	fmt.Println("stopping filecoin :(")
}
           

15.2.4 啟動及停止挖礦

  • 啟動挖礦
// StartMining causes the node to start feeding blocks to the mining worker and initializes
// the SectorBuilder for the mining address.
func (node *Node) StartMining(ctx context.Context) error {
	// 如果在挖礦中,退出
	if node.isMining() {
		return errors.New("Node is already mining")
	}
	// 擷取礦工位址
	minerAddr, err := node.miningAddress()
	if err != nil {
		return errors.Wrap(err, "failed to get mining address")
	}

	// 確定密封服務執行個體存在
	// ensure we have a sector builder
	if node.SectorBuilder() == nil {
		if err := node.setupMining(ctx); err != nil {
			return err
		}
	}

	// 擷取位址
	minerOwnerAddr, err := node.miningOwnerAddress(ctx, minerAddr)
	minerSigningAddress := node.MiningSignerAddress()
	if err != nil {
		return errors.Wrapf(err, "failed to get mining owner address for miner %s", minerAddr)
	}

	blockTime, mineDelay := node.MiningTimes()

	// 執行個體化挖礦排程服務
	if node.MiningScheduler == nil {
		getStateFromKey := func(ctx context.Context, tsKey string) (state.Tree, error) {
			tsas, err := node.ChainReader.GetTipSetAndState(ctx, tsKey)
			if err != nil {
				return nil, err
			}
			return state.LoadStateTree(ctx, node.CborStore(), tsas.TipSetStateRoot, builtin.Actors)
		}
		getState := func(ctx context.Context, ts types.TipSet) (state.Tree, error) {
			return getStateFromKey(ctx, ts.String())
		}
		getWeight := func(ctx context.Context, ts types.TipSet) (uint64, error) {
			parent, err := ts.Parents()
			if err != nil {
				return uint64(0), err
			}
			// TODO handle genesis cid more gracefully
			if parent.Len() == 0 {
				return node.Consensus.Weight(ctx, ts, nil)
			}
			pSt, err := getStateFromKey(ctx, parent.String())
			if err != nil {
				return uint64(0), err
			}
			return node.Consensus.Weight(ctx, ts, pSt)
		}
		getAncestors := func(ctx context.Context, ts types.TipSet, newBlockHeight *types.BlockHeight) ([]types.TipSet, error) {
			return chain.GetRecentAncestors(ctx, ts, node.ChainReader, newBlockHeight, consensus.AncestorRoundsNeeded, consensus.LookBackParameter)
		}
		processor := consensus.NewDefaultProcessor()
		worker := mining.NewDefaultWorker(node.MsgPool, getState, getWeight, getAncestors, processor, node.PowerTable,
			node.Blockstore, node.CborStore(), minerAddr, minerOwnerAddr, minerSigningAddress, node.Wallet, blockTime)
		node.MiningScheduler = mining.NewScheduler(worker, mineDelay, node.ChainReader.Head)
	}

	// paranoid check
	// 啟動挖礦服務
	if !node.MiningScheduler.IsStarted() {
		node.miningCtx, node.cancelMining = context.WithCancel(context.Background())
		outCh, doneWg := node.MiningScheduler.Start(node.miningCtx)

		node.miningDoneWg = doneWg
		node.AddNewlyMinedBlock = node.addNewlyMinedBlock
		node.miningDoneWg.Add(1)
		go node.handleNewMiningOutput(outCh)
	}

	// initialize a storage miner
	// 初始化存儲礦工
	storageMiner, err := initStorageMinerForNode(ctx, node)
	if err != nil {
		return errors.Wrap(err, "failed to initialize storage miner")
	}
	node.StorageMiner = storageMiner

	// loop, turning sealing-results into commitSector messages to be included
	// in the chain
	// 新開線程處理,1 密封完成處理;2 接受停止挖礦消息
	go func() {
		for {
			select {
				// 密封完成處理
			case result := <-node.SectorBuilder().SectorSealResults():
				if result.SealingErr != nil {
					log.Errorf("failed to seal sector with id %d: %s", result.SectorID, result.SealingErr.Error())
				} else if result.SealingResult != nil {

					// TODO: determine these algorithmically by simulating call and querying historical prices
					gasPrice := types.NewGasPrice(0)
					gasUnits := types.NewGasUnits(300)

					val := result.SealingResult
					// This call can fail due to, e.g. nonce collisions. Our miners existence depends on this.
					// We should deal with this, but MessageSendWithRetry is problematic.
					_, err := node.PorcelainAPI.MessageSend(
						node.miningCtx,
						minerOwnerAddr,
						minerAddr,
						nil,
						gasPrice,
						gasUnits,
						"commitSector",
						val.SectorID,
						val.CommD[:],
						val.CommR[:],
						val.CommRStar[:],
						val.Proof[:],
					)
					if err != nil {
						log.Errorf("failed to send commitSector message from %s to %s for sector with id %d: %s", minerOwnerAddr, minerAddr, val.SectorID, err)
						continue
					}

					node.StorageMiner.OnCommitmentAddedToChain(val, nil)
				}
				// 挖礦取消
			case <-node.miningCtx.Done():
				return
			}
		}
	}()

	// schedules sealing of staged piece-data
	// 定時密封階段性的碎片資料
	if node.Repo.Config().Mining.AutoSealIntervalSeconds > 0 {
		go func() {
			for {
				select {
					// 取消
				case <-node.miningCtx.Done():
					return
					// 定時密封
				case <-time.After(time.Duration(node.Repo.Config().Mining.AutoSealIntervalSeconds) * time.Second):
					log.Info("auto-seal has been triggered")
					if err := node.SectorBuilder().SealAllStagedSectors(node.miningCtx); err != nil {
						log.Errorf("scheduler received error from node.SectorBuilder.SealAllStagedSectors (%s) - exiting", err.Error())
						return
					}
				}
			}
		}()
	} else {
		log.Debug("auto-seal is disabled")
	}
	// 設定微挖礦狀态
	node.setIsMining(true)

	return nil
}
           
  • 停止挖礦
// StopMining stops mining on new blocks.
func (node *Node) StopMining(ctx context.Context) {
	node.setIsMining(false)

	// 取消挖礦
	if node.cancelMining != nil {
		node.cancelMining()
	}

	// 等待執行中的挖礦任務完成後結束
	if node.miningDoneWg != nil {
		node.miningDoneWg.Wait()
	}

	// TODO: stop node.StorageMiner
}
           

15.3 階段性分析結束說明

至此筆者針對go-filecoin部分的分析快告一個小的段落了
文章因為時間的關系,書面出來隻是将關鍵部分書面表達出來,更多的像是筆者的一個分析筆記,但是我相信對于想分析源碼的朋友有一定幫助
後面會抽空補充一章總結,筆者在第4章中有提到過,薄讀->厚讀->再薄讀,我們還需要一次薄讀,來加深我們對go-filecoin的認識。

上一篇:filecoin技術架構分析之十四:filecoin源碼分析之服務層鍊同步、共識協定及挖礦

下一篇: filecoin技術架構分析之十六:go-filecoin總結篇–待續