miner用来对worker进行管理, 订阅外部事件,控制worker的启动和停止。
type Miner struct {
mux *event.TypeMux
worker *worker
coinbase common.Address
eth Backend
engine consensus.Engine //共识
exitCh chan struct{}
startCh chan common.Address
stopCh chan struct{}
}
//构造, 创建了一个Miner 启动了miner的update goroutine
func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner {
miner := &Miner{
eth: eth,
mux: mux,
engine: engine,
exitCh: make(chan struct{}),
startCh: make(chan common.Address),
stopCh: make(chan struct{}),
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
}
go miner.update()
return miner
}
update订阅了downloader的事件, goroutine是一个一次性的循环, 只要接收到一次downloader的downloader.DoneEvent或者 downloader.FailedEvent事件, 就会设置canStart为1. 并退出循环, 这是为了避免黑客恶意的 DOS攻击,让你不断的处于异常状态
func (miner *Miner) update() {
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
defer func() {
if !events.Closed() {
events.Unsubscribe()
}
}()
shouldStart := false
canStart := true
dlEventCh := events.Chan()
for {
select {
case ev := <-dlEventCh:
if ev == nil {
// 取消订阅,停止收听
dlEventCh = nil
continue
}
switch ev.Data.(type) {
case downloader.StartEvent:
wasMining := miner.Mining()
miner.worker.stop()
canStart = false
if wasMining {
// 同步完成后继续挖掘
shouldStart = true
log.Info("Mining aborted due to sync")
}
case downloader.FailedEvent:
canStart = true
if shouldStart {
miner.SetEtherbase(miner.coinbase)
miner.worker.start()
}
case downloader.DoneEvent:
canStart = true
//启动worker 开始挖矿
if shouldStart {
miner.SetEtherbase(miner.coinbase)
miner.worker.start()
}
// 停止对同步事件作出反应
events.Unsubscribe()
}
case addr := <-miner.startCh:
miner.SetEtherbase(addr)
//启动worker 开始挖矿
if canStart {
miner.worker.start()
}
shouldStart = true
case <-miner.stopCh:
shouldStart = false
//worker 停止挖矿
miner.worker.stop()
case <-miner.exitCh:
miner.worker.close()
return
}
}
}