8 log "github.com/sirupsen/logrus"
10 "github.com/bytom/vapor/account"
11 "github.com/bytom/vapor/config"
12 "github.com/bytom/vapor/consensus"
13 "github.com/bytom/vapor/event"
14 "github.com/bytom/vapor/proposal"
15 "github.com/bytom/vapor/protocol"
19 logModule = "blockproposer"
26 // BlockProposer propose several block in specified time range
27 type BlockProposer struct {
30 accountManager *account.Manager
31 txPool *protocol.TxPool
34 eventDispatcher *event.Dispatcher
37 // generateBlocks is a worker that is controlled by the proposeWorkerController.
38 // It is self contained in that it creates block templates and attempts to solve
39 // them while detecting when it is performing stale work and reacting
40 // accordingly by generating a new block template. When a block is verified, it
43 // It must be run as a goroutine.
44 func (b *BlockProposer) generateBlocks() {
45 xpub := config.CommonConfig.PrivateKey().XPub()
46 xpubStr := hex.EncodeToString(xpub[:])
47 ticker := time.NewTicker(time.Duration(consensus.ActiveNetParams.BlockTimeInterval) * time.Millisecond)
57 bestBlockHeader := b.chain.BestBlockHeader()
58 bestBlockHash := bestBlockHeader.Hash()
60 now := uint64(time.Now().UnixNano() / 1e6)
62 if now < bestBlockHeader.Timestamp {
63 base = bestBlockHeader.Timestamp
65 minTimeToNextBlock := consensus.ActiveNetParams.BlockTimeInterval - base%consensus.ActiveNetParams.BlockTimeInterval
66 nextBlockTime := base + minTimeToNextBlock
67 if (nextBlockTime - now) < consensus.ActiveNetParams.BlockTimeInterval/10 {
68 nextBlockTime += consensus.ActiveNetParams.BlockTimeInterval
71 blocker, err := b.chain.GetBlocker(&bestBlockHash, nextBlockTime)
73 log.WithFields(log.Fields{"module": logModule, "error": err, "pubKey": xpubStr}).Error("fail on check is next blocker")
77 if xpubStr != blocker {
81 warnDuration := time.Duration(consensus.ActiveNetParams.BlockTimeInterval*warnTimeNum/warnTimeDenom) * time.Millisecond
82 criticalDuration := time.Duration(consensus.ActiveNetParams.BlockTimeInterval*criticalTimeNum/criticalTimeDenom) * time.Millisecond
83 block, err := proposal.NewBlockTemplate(b.chain, b.accountManager, nextBlockTime, warnDuration, criticalDuration)
85 log.WithFields(log.Fields{"module": logModule, "error": err}).Error("failed on create NewBlockTemplate")
89 isOrphan, err := b.chain.ProcessBlock(block)
91 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Error("proposer fail on ProcessBlock")
95 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "isOrphan": isOrphan, "tx": len(block.Transactions)}).Info("proposer processed block")
96 // Broadcast the block and announce chain insertion event
97 if err = b.eventDispatcher.Post(event.NewProposedBlockEvent{Block: *block}); err != nil {
98 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Error("proposer fail on post block")
103 // Start begins the block propose process as well as the speed monitor used to
104 // track hashing metrics. Calling this function when the block proposer has
105 // already been started will have no effect.
107 // This function is safe for concurrent access.
108 func (b *BlockProposer) Start() {
112 // Nothing to do if the miner is already running
117 b.quit = make(chan struct{})
118 go b.generateBlocks()
121 log.Infof("block proposer started")
124 // Stop gracefully stops the proposal process by signalling all workers, and the
125 // speed monitor to quit. Calling this function when the block proposer has not
126 // already been started will have no effect.
128 // This function is safe for concurrent access.
129 func (b *BlockProposer) Stop() {
133 // Nothing to do if the miner is not currently running
140 log.Info("block proposer stopped")
143 // IsProposing returns whether the block proposer has been started.
145 // This function is safe for concurrent access.
146 func (b *BlockProposer) IsProposing() bool {
153 // NewBlockProposer returns a new instance of a block proposer for the provided configuration.
154 // Use Start to begin the proposal process. See the documentation for BlockProposer
155 // type for more details.
156 func NewBlockProposer(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, dispatcher *event.Dispatcher) *BlockProposer {
157 return &BlockProposer{
159 accountManager: accountManager,
161 eventDispatcher: dispatcher,