主页 > imtoken下载最新版本 > Band of Brothers Go语言+区块链技术培训以太坊源码解析(42)Miner挖矿部分源码解析C
Band of Brothers Go语言+区块链技术培训以太坊源码解析(42)Miner挖矿部分源码解析C
Band of Brothers Go语言+区块链技术培训以太坊源码分析(42)矿机挖矿部分源码分析CPU挖矿
## 代理人
Agent是具体执行挖矿的对象。 它执行的过程是接受计算出的区块头,计算mix hash和nonce,返回挖出的区块头。
构造CpuAgent,一般情况下CPU不会被用来挖矿。 一般都是用专用的GPU挖矿,GPU挖矿的代码这里就不体现了。
类型 CpuAgent 结构 {
mu sync.Mutex
workCh chan *Work // 接受挖矿任务的通道
停止陈结构{}
quitCurrentOp 陈结构{}
归来灿灿
chain consensus.ChainReader // 获取区块链信息
engine consensus.Engine // 共识引擎,这里指的是Pow引擎
isMining int32 // isMining 表示agent当前是否在挖矿
}
func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent {
矿工 := &CpuAgent{
链条:链条,
发动机:发动机,
停止:制作(陈结构{},1),
workCh: make(chan *Work, 1),
}
返回矿工
}
设置返回值通道和获取Work通道,方便外界传值和获取返回信息。
func (self *CpuAgent) Work() 陈
func (self *CpuAgent) SetReturnCh(ch chan
启动和消息循环,如果已经开始挖矿则直接退出,否则启动update goroutine
update 从 workCh 接受任务到我的,或者接受退出信息退出。
func (self *CpuAgent) Start() {
如果 !,pareAndSwapInt32(&self.isMining, 0, 1) {
return // 代理已经启动
}
自己去更新()
}
func (self *CpuAgent) update() {
出去:
为了 {
选择 {
个案工作:=
自己。 亩。 锁()
如果 self.quitCurrentOp != nil {
关闭(self.quitCurrentOp)
}
自己。 quitCurrentOp = make(陈结构{})
自己去我的(工作,自我。quitCurrentOp)
自己。 亩。 开锁()
案件
自己。 亩。 锁()
如果 self.quitCurrentOp != nil {
关闭(self.quitCurrentOp)
自己。 quitCurrentOp = 无
}
自己。 亩。 开锁()
爆发
}
}
}
mine,挖矿,调用共识引擎进行挖矿,如果挖矿成功,发送消息给returnCh。
func (self *CpuAgent) mine(work *Work, 停止
如果结果,err := self.engine.Seal(self.chain, work.Block, stop p); 结果!=无{
,("新区块封存成功", "number", result.Number(), "hash", result.Hash())
自己。 返回通道
} 别的 {
如果错误!=无{
log.Warn("封块失败", "err", err)
}
自己。 返回通道
}
}
GetHashRate,该函数返回当前的哈希率。
func (self *CpuAgent) GetHashRate() int64 {
如果战俘,好的:=自我。 引擎。(共识。PoW); 行 {
返回 int64(pow.Hashrate())
}
返回 0
}
## 远程代理
remote_agent提供了一套RPC接口,可以实现远程矿机的挖矿功能。 比如我有一台矿机。 矿机内部没有运行以太坊节点。 矿机首先从remote_agent获取当前任务,然后进行挖矿计算。 挖矿完成后,提交计算结果,完成挖矿。
数据结构和构造
类型 RemoteAgent 结构 {
mu sync.Mutex
quitCh 陈结构{}
workCh chan *Work // 接受任务
归来灿灿
链共识。 链阅读器
引擎 consensus.Engine
currentWork *Work //当前任务
work map[common.Hash]*Work // 尚未提交,正在计算的任务
hashrateMu sync.RWMutex
hashrate map[common.Hash]hashrate // 正在计算的任务的哈希率
running int32 // running 指示代理是否处于活动状态。 原子调用
}
func NewRemoteAgent(chain consensus.ChainReader, engine consensus.Engine) *RemoteAgent {
返回 &RemoteAgent{
链条:链条,
发动机:发动机,
work: make(map[common.Hash]*Work),
哈希率:制作(地图[common.Hash]哈希率),
}
}
开始和停止
func (a *RemoteAgent) Start() {
如果 !,pareAndSwapInt32(&a.running, 0, 1) {
返回
}
一种。 quitCh = make(陈结构{})
a.workCh = make(chan *Work, 1)
去 a.loop(a.workCh, a.quitCh)
}
func (a *RemoteAgent) Stop() {
如果 !,pareAndSwapInt32(&a.running, 1, 0) {
返回
}
关闭(a.quitCh)
关闭(a.workCh)
}
获取输入输出的通道,这个和agent.go是一样的。
func (a *RemoteAgent) Work() 陈
返回 a.workCh
}
func (a *RemoteAgent) SetReturnCh(returnCh chan
一种。 返回 Ch = 返回 Ch
}
loop 方法类似于 agent.go 中所做的工作。 收到任务后,它会存储在 currentWork 字段中。 如果作业在 84 秒内未完成,则删除该作业,如果在 10 秒内未收到哈希率报告,则删除跟踪/。
// 循环监听 work 和 quit 通道上的挖矿事件,更新内部
// rmeote 矿工的状态,直到请求终止。
//
// 注意,work 和 quit 通道作为参数传递的原因是因为
// RemoteAgent.Start() 不断重新创建这些通道cpu挖以太坊,因此循环代码不能
// 假设这些成员字段中的数据稳定。
func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) {
自动收报机:=时间。 NewTicker(5 * time.Second)
推迟行情。 停止()
为了 {
选择 {
案件
返回
个案工作:=
a.mu.Lock()
一种。 当前工作 = 工作
a.mu.Unlock()
案件
//清理
a.mu.Lock()
对于散列,work := range a.work {
如果 time.Since(work.createdAt) > 7*(12*time.Second) {
删除(a.work,散列)
}
}
a.mu.Unlock()
a.hashrateMu.Lock()
对于 id,hashrate := range a.hashrate {
如果 time.Since(hashrate.ping) > 10*time.Second {
删除(a.hashrate,id)
}
}
一种。 算力Mu。 开锁()
}
}
}
GetWork,远程矿工调用该方法获取当前挖矿任务。
func (a *RemoteAgent) GetWork() ([3]string, error) {
a.mu.Lock()
推迟 a.mu.Unlock()
var res [3] 字符串
如果 a.currentWork != nil {
块 := a.currentWork.Block
res[0] = block.HashNoNonce().Hex()
seedHash := ethash.SeedHash(block.NumberU64())
res[1] = common.BytesToHash(seedHash).Hex()
// 计算要返回给外部矿工的“目标”
n := 大。 新整数(1)
n.Lsh(n, 255)
n.Div(n, block.Difficulty())
n.Lsh(n, 1)
res[2] = common.BytesToHash(n.Bytes()).Hex()
a.work[block.HashNoNonce()] = a.currentWork
返回资源,无
}
返回资源,错误。 New("暂无工作,不要惊慌。") }
SubmitWork,远程矿工调用该方法提交挖矿结果。 验证结果后提交给returnCh
// SubmitWork 尝试将 pow 解决方案注入远程代理,返回
// 解决方案是否被接受(not 既可以是坏 pow 也可以是
// 任何其他错误,例如没有待处理的工作)。
func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool {
a.mu.Lock()
推迟 a.mu.Unlock()
// 确保提交的工作存在
工作 := a.work[散列]
如果工作 == 无 {
,("工作已提交但没有待处理", "hash", hash) return false
}
// 确保引擎解决方案确实有效
结果 := work.Block.Header()
结果.Nonce = 随机数
结果。 混合摘要 = 混合摘要
如果错误 := a.engine.VerifySeal(a.chain, result); 错误!=无{
log.Warn("提交的工作量证明无效", "hash", hash, "err", err)
返回假
}
块:= work.Block.WithSeal(结果)
// 解决方案似乎有效,返回给矿工并通知接受
一种。 返回通道
删除(a.work,散列)
返回真
}
SubmitHashrate,提交哈希率
func (a *RemoteAgent) SubmitHashrate(id common.Hash, rate uint64) { a.hashrateMu.Lock()
推迟 a.hashrateMu.Unlock()
a.hashrate[id] = hashrate{time.Now(), rate}
}
## 未确认
unconfirmed是一种数据结构,用于追踪用户本地挖矿信息。 例如,如果挖出一个区块cpu挖以太坊,则等待足够多的后续区块确认(5),然后检查本地挖出的区块是否包含在区块链内部的规范中。
数据结构
// headerRetriever 被未确认块集用来验证之前是否有一个
// 开采的区块是否是规范链的一部分。
// headerRetriever 被未确认的区块组用来验证先前挖掘的区块是否是规范链的一部分。
类型 headerRetriever 接口 {
// GetHeaderByNumber 检索与块号关联的规范标头。
GetHeaderByNumber(number uint64) *types.Header
}
// unconfirmedBlock 是关于本地已开采区块的一小部分元数据集合
// 被放入一个未确认的集合中,用于包括离子跟踪在内的规范链。
// unconfirmedBlock 是本地挖出的区块元数据的一个小集合,用于放入未确认集来跟踪本地挖出的区块是否包含在规范区块链中
输入 unconfirmedBlock 结构 {
indexuint64
散列 common.Hash
}
// unconfirmedBlocks 实现了一个数据结构来维护本地挖掘的块
// 还没有达到足够的成熟度来保证链包含。 这是
// 矿工用来在先前挖出块时向用户提供日志
// 有足够高的保证不会被从规范链中重组出来。
// unconfirmedBlocks 实现了一种数据结构,用于管理尚未获得足够置信度以证明它们已被规范区块链接受的本地挖掘块。 它用于向矿工提供信息,以便他们知道他们之前开采的区块是否包含在规范区块链中。
输入 unconfirmedBlocks 结构 {
chain headerRetriever // 区块链通过验证规范状态 需要验证的区块链使用该接口获取当前规范区块头信息
depth uint // 丢弃之前块的深度 在多少块之后,丢弃之前的块
blocks *ring.Ring // 允许规范链交叉检查的块信息 // 允许规范链交叉检查的块信息
锁定同步。 RWMutex // 保护字段不被并发访问 }
// newUnconfirmedBlocks 返回新的数据结构来跟踪当前未确认的块。
func newUnconfirmedBlocks(chain headerRetriever, depth uint) *uncon firmedBlocks {
返回 &unconfirmedBlocks{
链条:链条,
深度:深度,
}
}
插入跟踪块,当矿工挖到一个块时调用,index为块的高度,hash为块的哈希值。
// Insert 将一个新块添加到未确认块的集合中。
func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) {
// 如果一个新块是在本地开采的,则移出任何足够旧的块块
// 如果本地块被挖出,则移除超过深度的块
放。 移位(索引)
// 将新项目创建为自己的戒指
// 对循环队列的操作。
项目 := 戒指。 新品(1)
物品。 值 = &unconfirmedBlock{
指数:指数,
哈希:哈希,
}
// 设置为初始环或追加到末尾
放。 锁。 锁()
延迟设置。 锁。 开锁()
如果 set.blocks == nil {
set.blocks = 项目
} 别的 {
// 移动到循环队列的最后一个元素插入item
set.blocks.Move(-1).Link(项目)
}
// 为用户显示日志以通知未确认的新开采块
,("