github.com/amazechain/amc@v0.1.3/internal/miner/miner.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package miner 18 19 import ( 20 "context" 21 "github.com/amazechain/amc/common" 22 "github.com/amazechain/amc/common/block" 23 "github.com/amazechain/amc/common/types" 24 "github.com/amazechain/amc/conf" 25 "github.com/amazechain/amc/internal/consensus" 26 "github.com/amazechain/amc/log" 27 event "github.com/amazechain/amc/modules/event/v2" 28 "golang.org/x/sync/errgroup" 29 "time" 30 ) 31 32 type Miner struct { 33 coinbase types.Address 34 engine consensus.Engine 35 worker *worker 36 txsPool common.ITxsPool 37 38 startCh chan types.Address 39 stopCh chan struct{} 40 41 ctx context.Context 42 //errCtx context.Context 43 cancel context.CancelFunc 44 45 group *errgroup.Group 46 } 47 48 func NewMiner(ctx context.Context, cfg *conf.Config, bc common.IBlockChain, engine consensus.Engine, txsPool common.ITxsPool, isLocalBlock func(header *block.Header) bool) *Miner { 49 group, errCtx := errgroup.WithContext(ctx) 50 miner := &Miner{ 51 engine: engine, 52 txsPool: txsPool, 53 startCh: make(chan types.Address), 54 stopCh: make(chan struct{}), 55 group: group, 56 ctx: errCtx, 57 worker: newWorker(errCtx, group, cfg.ChainCfg, engine, bc, txsPool, isLocalBlock, false, cfg.Miner), 58 } 59 60 return miner 61 } 62 63 func (m *Miner) Start() { 64 log.Info("start miner", "coinbase", m.coinbase) 65 m.group.Go(func() error { 66 return m.runLoop() 67 }) 68 m.startCh <- m.coinbase 69 } 70 71 func (m *Miner) runLoop() error { 72 defer m.cancel() 73 startCh := make(chan common.DownloaderFinishEvent) 74 doneCh := make(chan common.DownloaderStartEvent) 75 start := event.GlobalEvent.Subscribe(startCh) 76 done := event.GlobalEvent.Subscribe(doneCh) 77 78 defer func() { 79 start.Unsubscribe() 80 done.Unsubscribe() 81 }() 82 83 defer func() { 84 if m.Mining() { 85 m.worker.close() 86 } 87 }() 88 89 canStart := false 90 shouldStart := false 91 92 for { 93 select { 94 case <-m.ctx.Done(): 95 return nil 96 case _, ok := <-startCh: 97 if ok { 98 canStart = true 99 if !m.Mining() && shouldStart { 100 time.Sleep(5 * time.Second) 101 m.SetCoinbase(m.coinbase) 102 m.worker.start() 103 } 104 } 105 case _, ok := <-doneCh: 106 if ok { 107 if m.Mining() { 108 m.worker.stop() 109 } 110 } 111 case err := <-start.Err(): 112 return err 113 case err := <-done.Err(): 114 return err 115 case addr, ok := <-m.startCh: 116 if ok { 117 m.SetCoinbase(addr) 118 if canStart { 119 m.worker.start() 120 } 121 shouldStart = true 122 } 123 case <-m.stopCh: 124 shouldStart = false 125 if m.Mining() { 126 m.worker.stop() 127 } 128 case <-m.ctx.Done(): 129 return m.ctx.Err() 130 } 131 } 132 } 133 134 func (miner *Miner) Close() { 135 //close(miner.exitCh) 136 //miner.wg.Wait() 137 } 138 139 func (m *Miner) Mining() bool { 140 return m.worker.isRunning() 141 } 142 143 func (m *Miner) SetCoinbase(addr types.Address) { 144 m.coinbase = addr 145 m.worker.setCoinbase(addr) 146 } 147 148 func (m *Miner) PendingBlockAndReceipts() (block.IBlock, block.Receipts) { 149 return m.worker.pendingBlockAndReceipts() 150 }