PoW挖矿
代码基于在学习以太坊挖矿以前先来了解几个相关的数据结构作为铺垫:
数据结构1:
type Miner struct {
mux *event.TypeMux // 事件锁,已被feed.mu.lock替代
worker *worker // 干活的人
coinbase common.Address // 结点地址
mining int32 // 代表挖矿进行中的状态
eth Backend // Backend对象,Backend是一个自定义接口封装了所有挖矿所需方法。
engine consensus.Engine // 共识引擎
canStart int32 // 是否能够开始挖矿操作
shouldStart int32 // 同步以后是否应该开始挖矿
}
//实际的工人
type worker struct {
config *params.ChainConfig //链配置
engine consensus.Engine //一致性引擎,ethash或者clique poa(这个目前只在测试网测试)
mu sync.Mutex //锁
// update loop
mux *event.TypeMux
events *event.TypeMuxSubscription
wg sync.WaitGroup
agents map[Agent]struct{
} //agent 是挖矿代理,实际执行挖矿的代理,目前以太坊默认注册cpuagent,矿池应该是自己实现了自己的agent注册到这里
recv chan *Result //这是一个结果通道,挖矿完成以后将结果推送到此通道
eth Backend //以太坊定义
chain *core.BlockChain
proc core.Validator
chainDb ethdb.Database
coinbase common.Address //基础帐户地址
extra []byte
currentMu sync.Mutex
current *Work //实际将每一个区块作为一个工作work推给agent进行挖矿
uncleMu sync.Mutex
possibleUncles map[common.Hash]*types.Block //可能的数块
txQueueMu sync.Mutex
txQueue map[common.Hash]*types.Transaction
unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations
// atomic status counters
mining int32
atWork int32
fullValidation bool
}
//agent接口如下,实现以下接口的 就可作为一个agent
type Agent interface {
Work() chan<- *Work
SetReturnCh(chan<- *Result)
Stop()
Start()
GetHashRate() int64
}
上面记录了要开始学习挖矿的基础结构,其实还有block的header数据结构需要很熟悉,方便后续分析
在backend.go里面New一个ethereum时候,调用了如下语句:
//先单独看如下两句:
engine: CreateConsensusEngine(ctx, config, chainConfig, chainDb),
engine := ethash.New(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk,config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk)
//从上面可以看出来geth启动时候默认的共识引擎为ethash
//下面语句开始New一个miner了
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)
# go-ethereum/miner/miner.go
func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner {
//开始创建miner结构体
miner := &Miner{
eth: eth,
mux: mux,
engine: engine,
worker: newWorker(config, engine, common.Address{
}, eth, mux), //创建了一个工人
canStart: 1,
}
//注册代理
miner.Register(NewCpuAgent(eth.BlockChain(), engine))
go miner.update()
return miner
}
# go-ethereum/miner/worker.go
func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
worker := &worker{
config: config,
engine: engine,
eth: eth,
mux: mux,
chainDb: eth.ChainDb(),
recv: make(chan *Result, resultQueueSize), //结果通道
chain: eth.BlockChain(),
proc: eth.BlockChain().Validator(),
possibleUncles: make(map[common.Hash]*types.Block),
coinbase: coinbase,
txQueue: make(map[common.Hash]*types.Transaction),
agents: make(map[Agent]struct{
}),
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), 5),
fullValidation: false,
}
//worker开始订阅相关三个事件
worker.events = worker.mux.Subscribe(core.ChainHeadEvent{
}, core.ChainSideEvent{
}, core.TxPreEvent{
})
//先来分析一下update()函数
go worker.