主页 > 官网imtoken钱包苹果版下载 > 以太坊挖矿返回null源码分析

以太坊挖矿返回null源码分析

在以太坊1.7.3版本中,无论是dev环境还是公链环境,在控制台执行miner.start()总是返回null,而不是预期的true。 为什么是这样? 本文将带你从源码中寻找原因。 在这个过程中,我们会学到更多的底层知识。

采矿入门程序

先看调用挖矿的程序。 在控制台中,我们执行:

miner.start()
##或
miner.start(n)

参数n是系统CPU的核心数。 go语言中对应的方法是:

miner.Start(threads *rpc.HexNumber) (bool, error)

该方法对应的api调用在eth/api.go文件中,具体代码如下:

// Start the miner with the given number of threads. If threads is nil the number
// of workers started is equal to the number of logical CPUs that are usable by
// this process. If mining is already running, this method adjust the number of
// threads allowed to use.
func (api *PrivateMinerAPI) Start(threads *int) error {
    // Set the number of threads if the seal engine supports it
    if threads == nil {
        threads = new(int)
    } else if *threads == 0 {
        *threads = -1 // Disable the miner from within
    }
    type threaded interface {
        SetThreads(threads int)
    }
    if th, ok := api.e.engine.(threaded); ok {
        log.Info("Updated mining threads", "threads", *threads)
        th.SetThreads(*threads)
    }
    // Start the miner and return
    if !api.e.IsMining() {
        // Propagate the initial price point to the transaction pool
        api.e.lock.RLock()
        price := api.e.gasPrice
        api.e.lock.RUnlock()
        api.e.txPool.SetGasPrice(price)
        return api.e.StartMining(true)
    }
    return nil
}

通过这段代码我们可以分析出以下几点:

- 挖矿时传递的参数是系统CPU的核心数,可以指定。 如果未指定,则默认为系统的核心数。

- 如果您已经在挖矿,请执行挖矿程序以更改使用的 CPU 内核数。

- 如果系统已经在挖矿,返回结果为nil(null)。

- 如果没有开始挖矿,执行api.e.StartMining(true)方法。

执行挖矿

看一下api.e.StartMining(true)方法对应的代码内容:

func (s *Ethereum) StartMining(local bool) error {
    eb, err := s.Etherbase()
    if err != nil {
        log.Error("Cannot start mining without etherbase", "err", err)
        return fmt.Errorf("etherbase missing: %v", err)
    }
    if clique, ok := s.engine.(*clique.Clique); ok {
        wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
        if wallet == nil || err != nil {
            log.Error("Etherbase account unavailable locally", "err", err)
            return fmt.Errorf("signer missing: %v", err)
        }
        clique.Authorize(eb, wallet.SignHash)
    }
    if local {
        // If local (CPU) mining is started, we can disable the transaction rejection
        // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous
        // so noone will ever hit this path, whereas marking sync done on CPU mining
        // will ensure that private networks work in single miner mode too.
        atomic.StoreUint32(&s.protocolManager.acceptTxs, 1)
    }
    go s.miner.Start(eb)
    return nil
}

通过上面的代码我们可以分析得到:

- 成功挖矿的前提是存在有效的coinbase账户;

- 即使挖矿成功(执行go s.miner.Start(eb))以太坊年底停止挖矿以太坊年底停止挖矿,该方法返回的结果也是nil(null)。

因此,通过以上两段代码分析,在这个版本中,无论挖矿成功还是挖矿失败,返回的结果都是null。 这就是为什么在这个版本中无法通过返回值判断是否开启挖矿成功。

挖矿代码渐进分析

仔细看看 s.miner.Start(eb) 中的代码:

func (self *Miner) Start(coinbase common.Address) {
    atomic.StoreInt32(&self.shouldStart, 1)
    self.worker.setEtherbase(coinbase)
    self.coinbase = coinbase
    if atomic.LoadInt32(&self.canStart) == 0 {
        log.Info("Network syncing, will start miner afterwards")
        return
    }
    atomic.StoreInt32(&self.mining, 1)
    log.Info("Starting mining operation")
    self.worker.start()
    self.worker.commitNewWork()
}

这段代码的基本实现是设置一些相关的参数项,然后开始挖矿。 通过这段代码,我们可以获取到一条日志信息来判断是否开始挖矿——“Starting mining operation”,所以如果日志中有这行输出,可以作为确认挖矿已经开始的必要和不充分条件开始了。

停止功能

对应的停止函数不同:

// Stop the miner
func (api *PrivateMinerAPI) Stop() bool {
    type threaded interface {
        SetThreads(threads int)
    }
    if th, ok := api.e.engine.(threaded); ok {
        th.SetThreads(-1)
    }
    api.e.StopMining()
    return true
}

显然,无论stop是否执行成功,或者当前是否在挖矿,只要执行了stop,就会一直返回true。

总结

通过上面的分析,我们得到了一些经验和常识,也告诉我们在这个版本中调用miner.start()返回null并没有任何意义。 挖矿可能已经开始,也可能没有。

原文链接: