Get the App
SLTechnology News&Howtos  ›  Internet Technology  › 

What is the mining process of bytom?

Shulou Source: shulou.com Published: 2022-06-01 10:47:34 09月26日 Update

本篇内容主要讲解"bytom的挖矿流程是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"bytom的挖矿流程是什么"吧!

当我们以bytom init --chain_id=solonet建立比原单机节点用于本地测试时,很快会发现自己将面临一个尴尬的问题:余额为0。就算我们使用bytom node --mining开启挖矿,理论上由于我们是单机状态,本机算力就是全网算力,应该每次都能够挖到,但是不知道为什么,在我尝试的时候发现总是挖不到,所以打算简单研究一下比原的挖矿流程,看看有没有办法能改点什么,给自己单机多挖点BTM以方便后面的测试。

所以在今天我打算通过源代码分析一下比原的挖矿流程,但是考虑到它肯定会涉及到比原的核心,所以太复杂的地方我就会先跳过,那些地方时机成熟的时候会彻底研究一下。

如果我们快速搜索一下,就能发现在比原代码中有一个类型叫CPUMiner,我们围绕着它应该就可以了。

首先还是从比原启动开始,看看CPUMiner是如何被启动的。

下面是bytom node --mining对应的入口函数:

cmd/bytomd/main.go#L54-L57

func main() { cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv(config.DefaultDataDir())) cmd.Execute()}

由于传入了参数node,所以创建Node并启动:

cmd/bytomd/commands/run_node.go#L41-L54

func runNode(cmd *cobra.Command, args []string) error { // Create & start node n := node.NewNode(config) if _, err := n.Start(); err != nil { // ...}

在创建一个Node对象的时候,也会创建CPUMiner对象:

node/node.go#L59-L142

func NewNode(config *cfg.Config) *Node { // ... node.cpuMiner = cpuminer.NewCPUMiner(chain, accounts, txPool, newBlockCh) node.miningPool = miningpool.NewMiningPool(chain, accounts, txPool, newBlockCh) // ... return node}

这里可以看到创建了两个与挖矿相关的东西,一个是NewCPUMiner,另一个是miningPool。我们先看NewCPUMiner对应的代码:

mining/cpuminer/cpuminer.go#L282-L293

func NewCPUMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash) *CPUMiner { return &CPUMiner{ chain: c, accountManager: accountManager, txPool: txPool, numWorkers: defaultNumWorkers, updateNumWorkers: make(chan struct{}), queryHashesPerSec: make(chan float64), updateHashes: make(chan uint64), newBlockCh: newBlockCh, }}

从这里的字段可以看到,CPUMiner在工作的时候:

可能需要用到外部的三个对象分别是:chain(代表本机持有的区块链),accountManager(管理帐户),txPool(交易池)

numWorkers:应该保持几个worker在挖矿,默认值defaultNumWorkers为常量1,也就是说默认只有一个worker。这对于多核cpu来说有点亏,真要挖矿的话可以把它改大点,跟核心数相同(不过用普通电脑不太可能挖到了)

updateNumWorkers:外界如果想改变worker的数量,可以通过向这个通道发消息实现。CPUMiner会监听它,并按要求增减worker

queryHashesPerSec:这个没用上,忽略吧。我发现比原的开发人员很喜欢预先设计,有很多这样没用上的代码

updateHashes: 这个没用上,忽略

newBlockCh: 一个来自外部的通道,用来告诉外面自己成功挖到了块,并且已经放进了本地区块链,其它地方就可以用它了(比如广播出去)

然而这里出现的并不是CPUMiner全部的字段,仅仅是需要特意初始化的几个。完整的在这里:

mining/cpuminer/cpuminer.go#L29-L45

type CPUMiner struct { sync.Mutex chain *protocol.Chain accountManager *account.Manager txPool *protocol.TxPool numWorkers uint64 started bool discreteMining bool wg sync.WaitGroup workerWg sync.WaitGroup updateNumWorkers chan struct{} queryHashesPerSec chan float64 updateHashes chan uint64 speedMonitorQuit chan struct{} quit chan struct{} newBlockCh chan *bc.Hash}

可以看到还多出了几个:

sync.Mutex:为CPUMiner提供了锁,方便在不同的goroutine代码中进行同步

started:记录miner是否启动了

discreteMining:这个在当前代码中没有赋过值,永远是false,我觉得应该删除。已提issue #961

wg和workerWg:都是跟控制goroutine流程相关的

speedMonitorQuit:也没什么用,忽略

quit:外界可以给这个通道发消息来通知CPUMiner退出

再回到n.Start看看cpuMiner是何时启动的:

node/node.go#L169-L180

func (n *Node) OnStart() error { if n.miningEnable { n.cpuMiner.Start() } // ...}

由于我们传入了参数--mining,所以n.miningEnable是true,于是n.cpuMiner.Start会运行:

mining/cpuminer/cpuminer.go#L188-L205

func (m *CPUMiner) Start() { m.Lock() defer m.Unlock() if m.started || m.discreteMining { return } m.quit = make(chan struct{}) m.speedMonitorQuit = make(chan struct{}) m.wg.Add(1) go m.miningWorkerController() m.started = true log.Infof("CPU miner started")}

这段代码没太多需要说的,主要是通过判断m.started保证不会重复启动,然后把真正的工作放在了m.miningWorkerController()中:

mining/cpuminer/cpuminer.go#L126-L125

func (m *CPUMiner) miningWorkerController() { // 1. var runningWorkers []chan struct{} launchWorkers := func(numWorkers uint64) { for i := uint64(0); i

< numWorkers; i++ { quit := make(chan struct{}) runningWorkers = append(runningWorkers, quit) m.workerWg.Add(1) go m.generateBlocks(quit) } } runningWorkers = make([]chan struct{}, 0, m.numWorkers) launchWorkers(m.numWorkers)out: for { select { // 2. case numRunning { launchWorkers(m.numWorkers - numRunning) continue } for i := numRunning - 1; i >

= m.numWorkers; i-- { close(runningWorkers[i]) runningWorkers[i] = nil runningWorkers = runningWorkers[:i] } // 3. case

Tags: Code block method channel place time process work content object time message accounting local machine processing inspection difficulty research stand-alone outside world Apple Docker Huawei Linux macOS MariaDB Microsoft MySQL NVidia OPPO Reno Apple MariaDB OPPO Reno vpn Xiaomi