GO-HPB源码解读--挖矿流程(四)

接着上一章,我们看到了这章来看了go self.mine(work, self.quitCurrentOp)这部分代码,现在来看下具体挖矿算法的流程。
mine方法中调用engine.GenBlockWithSig方法,返回的result结果传递给returnCh通道,而returnCh通道的获取工作是在worker中进行处理的。上一节我们理了一下producer绑定CpuAgent的流程,在worker.New的时候,通过go worker.handlerSelfMinedBlock()这行代码启了一个协程去获取通道里的挖矿结果。

1
2
3
4
5
6
7
8
9
10
11
func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
if result, err := self.engine.GenBlockWithSig(self.chain, work.Block, stop); result != nil {
log.Info("Successfully sealed new block", "number -> ", result.Number(), "hash -> ", result.Hash(),"difficulty -> ",result.Difficulty())
self.returnCh <- &Result{work, result}
} else {
if err != nil {
log.Warn("Block sealing failed", "err", err)
}
self.returnCh <- nil
}
}

生成区块的过程:

  1. 数据合法性校验
  2. 获取签名者signer和签名方法signFn,这两个数据是在挖矿流程(二)中的StartMining方法中设置的,代码是promeengine.Authorize(eb, wallet.SignHash),即signer是当前节点的挖矿地址coinbase,signFn是对应钱包的签名方法,即keystoreWallet类的签名方法
  3. voting.GetHpbNodeSnap是获取高性能节点列表,其中有重新投票节点的过程,投票这个机制单独解读,这里就先不说了。
  4. 设置本地节点类型,是高性能节点还是候选节点
  5. 如果自己的当前节点不是包含在高性能节点中,则返回错误consensus.ErrUnauthorized
  6. 接着要判断一下自己当前节点是否轮到进行签名(挖矿),如果没轮到,需要通过高性能节点列表中自己的位置和正在挖矿的位置两个关键参数计算出自己需要等待的一个时间段,
  7. 时间到了的话就进行签名,签名方法为signFn,这个方法直接使用coinbase对应的私钥进行ECDSA签名
  8. 签名完了之后,把签名结果放置到header.Extra里,并返回最终block
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//生成区块
func (c *Prometheus) GenBlockWithSig(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
header := block.Header()

log.Info("HPB Prometheus Seal is starting")

number := header.Number.Uint64()

if number == 0 {
return nil, consensus.ErrUnknownBlock
}
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
if c.config.Period == 0 && len(block.Transactions()) == 0 {
return nil, consensus.ErrWaitTransactions
}

c.lock.RLock()
signer, signFn := c.signer, c.signFn

log.Debug("GenBlockWithSig-------------+++++ signer's address", "signer", signer.Hex(), "number", number)

c.lock.RUnlock()

snap, err := voting.GetHpbNodeSnap(c.db, c.recents, c.signatures, c.config, chain, number, header.ParentHash, nil)

SetNetNodeType(snap)

if err != nil {
return nil, err
}

if _, authorized := snap.Signers[signer]; !authorized {
return nil, consensus.ErrUnauthorized
}

// 轮到我们的签名
delay := time.Unix(header.Time.Int64(), 0).Sub(time.Now())
if delay < 0 {
delay = 0
header.Time = big.NewInt(time.Now().Unix())
}
// 比较难度值,确定是否为适合的时间
if header.Difficulty.Cmp(diffNoTurn) == 0 {
// // It's not our turn explicitly to sign, delay it a bit
wiggle := time.Duration(len(snap.Signers)/2+1) * wiggleTime
currentminer := new(big.Int).SetBytes(header.HardwareRandom).Uint64() % uint64(len(snap.Signers)) //miner position
//log.Error("-----genblocksig---------test for waiting 8 minutes--------------", "primemineraddr", primemineraddr, "primeoffset", currentminer, "number", number)
myoffset := snap.GetOffset(header.Number.Uint64(), signer)
distance := int(math.Abs(float64(int64(myoffset) - int64(currentminer))))
if distance > len(snap.Signers)/2 {
distance = len(snap.Signers) - distance
}
if distance > len(snap.Signers)/consensus.StepLength { //if signers length is smaller than 3, it means myoffset smaller than currentminer have high priority
delay += time.Duration(len(snap.Signers)-distance+10+rand.Intn(5)) * wiggleTime
} else {
wiggle = time.Duration(1000+rand.Intn(len(snap.Signers))) * wiggleTime
delay += wiggle
}
}

log.Debug("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay), "number", number)

select {
case <-stop:
return nil, nil
case <-time.After(delay):
}

// 地址赋值
header.Coinbase = signer

// 签名交易,signFn为回掉函数
sighash, err := signFn(accounts.Account{Address: signer}, consensus.SigHash(header).Bytes())
if err != nil {
return nil, err
}

//将签名后的结果返给到Extra中
copy(header.Extra[len(header.Extra)-consensus.ExtraSeal:], sighash)

return block.WithSeal(header), nil
}

整个挖矿流程就到此结束了,当然其中会涉及一些其他的功能点,比如P2P,投票机制等,后续单独解读。
这段代码读了很久,被投票那块搞死了,说好的POW呢?怎么没看到呢
😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭