全网中每新增2016个区块,全网难度将重新计算,该新难度值将依据前2016个区块的哈希算力而定
If it took fewer than two weeks to generate the 2,016 blocks, the expected difficultyvalue is increased proportionally (by as much as 300%) so that the next 2,016 blocksshould 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.
假设一个分叉的区块都是合格的,通常节点总是接受满足工作量难度的最长链,去掉更短链的没用的块。
下面分析代码:
// Start the CPU miner if generation is enabled. if cfg.Generate { s.cpuMiner.Start() }
开始挖矿,方法代码:
func (m *CPUMiner) Start() { m.Lock() defer m.Unlock() if m.started || m.discreteMining { return } m.quit = make(chan struct{}) m.speedMonitorQuit = make(chan struct{}) m.wg.Add(2) go m.speedMonitor() go m.miningWorkerController() m.started = true log.Infof("CPU miner started") }
go m.miningWorkerController()
异步启动挖矿工作线程,代码:
func (m *CPUMiner) miningWorkerController() { // launchWorkers groups common code to launch a specified number of // workers for generating blocks. var runningWorkers []chan struct{} launchWorkers := func(numWorkers uint32) { for i := uint32(0); i < numWorkers; i++ { quit := make(chan struct{}) runningWorkers = append(runningWorkers, quit) m.workerWg.Add(1) go m.generateBlocks(quit) } } // Launch the current number of workers by default. runningWorkers = make([]chan struct{}, 0, m.numWorkers) launchWorkers(m.numWorkers) out: for { select { // Update the number of running workers. case <-m.updateNumWorkers: // No change. numRunning := uint32(len(runningWorkers)) if m.numWorkers == numRunning { continue } // Add new workers. if m.numWorkers > numRunning { launchWorkers(m.numWorkers - numRunning) continue } // Signal the most recently created goroutines to exit. for i := numRunning - 1; i >= m.numWorkers; i-- { close(runningWorkers[i]) runningWorkers[i] = nil runningWorkers = runningWorkers[:i] } case <-m.quit: for _, quit := range runningWorkers { close(quit) } break out } } // Wait until all workers shut down to stop the speed monitor since // they rely on being able to send updates to it. m.workerWg.Wait() close(m.speedMonitorQuit) m.wg.Done() }
go m.generateBlocks(quit)
生成区块,具体怎么生产的?代码:
func (m *CPUMiner) generateBlocks(quit chan struct{}) { log.Tracef("Starting generate blocks worker") ticker := time.NewTicker(time.Second * hashUpdateSecs) defer ticker.Stop() out: for { select { case <-quit: break out default: // Non-blocking select to fall through } if m.cfg.ConnectedCount() == 0 { time.Sleep(time.Second) continue } m.submitBlockLock.Lock() curHeight := m.g.BestSnapshot().Height if curHeight != 0 && !m.cfg.IsCurrent() { m.submitBlockLock.Unlock() time.Sleep(time.Second) continue } // 从挖矿地址账号随机选择一个地址作为入账地址 rand.Seed(time.Now().UnixNano()) payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))] // 创建区块模板 template, err := m.g.NewBlockTemplate(payToAddr) m.submitBlockLock.Unlock() if err != nil { errStr := fmt.Sprintf("Failed to create new block "+ "template: %v", err) log.Errorf(errStr) continue } // 开始POW,计算区块的hash符合难度目标 if m.solveBlock(template.Block, curHeight+1, ticker, quit) { block := btcutil.NewBlock(template.Block) m.submitBlock(block) } } m.workerWg.Done() log.Tracef("Generate blocks worker done") }
template, err := m.g.NewBlockTemplate(payToAddr)
创建新的块模板,在NewBlockTemplate方法里有调用:
reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)
这个方法是每2016个块计算新的难度目标
if m.solveBlock(template.Block, curHeight+1, ticker, quit) {
随机nonce计算块hash
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 { m.updateHashes <- hashesCompleted return true }
满足条件返回true
func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {
将区块广播到网络。
isOrphan, err := m.cfg.ProcessBlock(block, blockchain.BFNone)
ProcessBlock是在new server时配置的
s.cpuMiner = cpuminer.New(&cpuminer.Config{ ChainParams: chainParams, BlockTemplateGenerator: blockTemplateGenerator, MiningAddrs: cfg.miningAddrs, ProcessBlock: s.syncManager.ProcessBlock, ConnectedCount: s.ConnectedCount, IsCurrent: s.syncManager.IsCurrent, })
func (sm *SyncManager) ProcessBlock(block *btcutil.Block, flags blockchain.BehaviorFlags) (bool, error) { reply := make(chan processBlockResponse, 1) sm.msgChan <- processBlockMsg{block: block, flags: flags, reply: reply} response := <-reply return response.isOrphan, response.err }
创建一个processBlockMsg对象放到msgChan通道里。
然后就由一下方法处理块消息
func (sm *SyncManager) blockHandler() {