比特币全节点Go语言实现BTCD之挖矿流程及难度计算

释放双眼,带上耳机,听听看~!

全网中每新增2016个区块,全网难度将重新计算,该新难度值将依据前2016个区块的哈希算力而定

If it took fewer than two weeks to generate the 2,016 blocks
, the expected difficulty
value is increased proportionally (by as much as 300%) so that the next 2,016 blocks
should take exactly two weeks to generate if hashes are checked at the same rate.

  • If it took more than two weeks to generate the blocks, the expected difficulty value is decreased proportionally (by as much as 75%) for the same reason.

假设一个分叉的区块都是合格的,通常节点总是接受满足工作量难度的最长链,去掉更短链的没用的块。

下面分析代码:


1
2
3
4
5
1// Start the CPU miner if generation is enabled.
2if cfg.Generate {
3   s.cpuMiner.Start()
4}
5

开始挖矿,方法代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1func (m *CPUMiner) Start() {
2   m.Lock()
3   defer m.Unlock()
4
5   if m.started || m.discreteMining {
6      return
7}
8
9   m.quit = make(chan struct{})
10   m.speedMonitorQuit = make(chan struct{})
11   m.wg.Add(2)
12   go m.speedMonitor()
13   go m.miningWorkerController()
14
15   m.started = true
16log.Infof("CPU miner started")
17}
18

1
2
1go m.miningWorkerController()
2

异步启动挖矿工作线程,代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1func (m *CPUMiner) miningWorkerController() {
2   // launchWorkers groups common code to launch a specified number of
3   // workers for generating blocks.
4   var runningWorkers []chan struct{}
5   launchWorkers := func(numWorkers uint32) {
6      for i := uint32(0); i < numWorkers; i++ {
7         quit := make(chan struct{})
8         runningWorkers = append(runningWorkers, quit)
9
10         m.workerWg.Add(1)
11         go m.generateBlocks(quit)
12      }
13   }
14
15   // Launch the current number of workers by default.
16   runningWorkers = make([]chan struct{}, 0, m.numWorkers)
17   launchWorkers(m.numWorkers)
18
19out:
20   for {
21      select {
22      // Update the number of running workers.
23      case <-m.updateNumWorkers:
24         // No change.
25         numRunning := uint32(len(runningWorkers))
26         if m.numWorkers == numRunning {
27            continue
28}
29
30         // Add new workers.
31         if m.numWorkers > numRunning {
32            launchWorkers(m.numWorkers - numRunning)
33            continue
34}
35
36         // Signal the most recently created goroutines to exit.
37         for i := numRunning - 1; i >= m.numWorkers; i-- {
38            close(runningWorkers[i])
39            runningWorkers[i] = nil
40            runningWorkers = runningWorkers[:i]
41         }
42
43      case <-m.quit:
44         for _, quit := range runningWorkers {
45            close(quit)
46         }
47         break out
48      }
49   }
50
51   // Wait until all workers shut down to stop the speed monitor since
52   // they rely on being able to send updates to it.
53   m.workerWg.Wait()
54   close(m.speedMonitorQuit)
55   m.wg.Done()
56}
57

1
2
1go m.generateBlocks(quit)
2

生成区块,具体怎么生产的?代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1func (m *CPUMiner) generateBlocks(quit chan struct{}) {
2   log.Tracef("Starting generate blocks worker")
3
4   ticker := time.NewTicker(time.Second * hashUpdateSecs)
5   defer ticker.Stop()
6out:
7   for {
8      select {
9      case <-quit:
10         break out
11      default:
12         // Non-blocking select to fall through
13      }
14
15      if m.cfg.ConnectedCount() == 0 {
16         time.Sleep(time.Second)
17         continue
18}
19
20      m.submitBlockLock.Lock()
21      curHeight := m.g.BestSnapshot().Height
22      if curHeight != 0 && !m.cfg.IsCurrent() {
23         m.submitBlockLock.Unlock()
24         time.Sleep(time.Second)
25         continue
26}
27
28      // 从挖矿地址账号随机选择一个地址作为入账地址
29      rand.Seed(time.Now().UnixNano())
30      payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]
31
32      // 创建区块模板
33      template, err := m.g.NewBlockTemplate(payToAddr)
34      m.submitBlockLock.Unlock()
35      if err != nil {
36         errStr := fmt.Sprintf("Failed to create new block "+
37            "template: %v", err)
38         log.Errorf(errStr)
39         continue
40}
41
42      // 开始POW,计算区块的hash符合难度目标
43      if m.solveBlock(template.Block, curHeight+1, ticker, quit) {
44         block := btcutil.NewBlock(template.Block)
45         m.submitBlock(block)
46      }
47   }
48
49   m.workerWg.Done()
50   log.Tracef("Generate blocks worker done")
51}
52

1
2
1template, err := m.g.NewBlockTemplate(payToAddr)
2

创建新的块模板,在NewBlockTemplate方法里有调用:


1
2
1reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)
2

这个方法是每2016个块计算新的难度目标


1
2
1if m.solveBlock(template.Block, curHeight+1, ticker, quit) {
2

随机nonce计算块hash


1
2
3
4
5
1if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
2   m.updateHashes <- hashesCompleted
3   return true
4}
5

满足条件返回true


1
2
1func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {
2

将区块广播到网络。


1
2
1isOrphan, err := m.cfg.ProcessBlock(block, blockchain.BFNone)
2

ProcessBlock是在new server时配置的


1
2
3
4
5
6
7
8
9
1s.cpuMiner = cpuminer.New(&cpuminer.Config{
2   ChainParams:            chainParams,
3   BlockTemplateGenerator: blockTemplateGenerator,
4   MiningAddrs:            cfg.miningAddrs,
5   ProcessBlock:           s.syncManager.ProcessBlock,
6   ConnectedCount:         s.ConnectedCount,
7   IsCurrent:              s.syncManager.IsCurrent,
8})
9

1
2
3
4
5
6
7
1func (sm *SyncManager) ProcessBlock(block *btcutil.Block, flags blockchain.BehaviorFlags) (bool, error) {
2   reply := make(chan processBlockResponse, 1)
3   sm.msgChan <- processBlockMsg{block: block, flags: flags, reply: reply}
4   response := <-reply
5   return response.isOrphan, response.err
6}
7

创建一个processBlockMsg对象放到msgChan通道里。

然后就由一下方法处理块消息


1
2
1func (sm *SyncManager) blockHandler() {
2

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C/C++内存泄漏及检测

2022-1-11 12:36:11

安全技术

JavaScript---网络编程(1)-介绍、变量、运算符与语句

2021-12-21 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索