8 log "github.com/sirupsen/logrus"
10 "github.com/vapor/account"
11 "github.com/vapor/config"
12 "github.com/vapor/consensus"
13 "github.com/vapor/event"
14 "github.com/vapor/proposal"
15 "github.com/vapor/protocol"
19 logModule = "blockproposer"
22 // BlockProposer propose several block in specified time range
23 type BlockProposer struct {
26 accountManager *account.Manager
27 txPool *protocol.TxPool
30 eventDispatcher *event.Dispatcher
33 // generateBlocks is a worker that is controlled by the proposeWorkerController.
34 // It is self contained in that it creates block templates and attempts to solve
35 // them while detecting when it is performing stale work and reacting
36 // accordingly by generating a new block template. When a block is verified, it
39 // It must be run as a goroutine.
40 func (b *BlockProposer) generateBlocks() {
41 xpub := config.CommonConfig.PrivateKey().XPub()
42 xpubStr := hex.EncodeToString(xpub[:])
43 ticker := time.NewTicker(consensus.BlockTimeInterval * time.Millisecond)
53 bestBlockHeader := b.chain.BestBlockHeader()
54 bestBlockHash := bestBlockHeader.Hash()
55 nextBlockTime := uint64(time.Now().UnixNano() / 1e6)
56 if minNextBlockTime := bestBlockHeader.Timestamp + consensus.BlockTimeInterval; nextBlockTime < minNextBlockTime {
57 nextBlockTime = minNextBlockTime
60 if isBlocker, err := b.chain.IsBlocker(&bestBlockHash, xpubStr, nextBlockTime); !isBlocker {
61 log.WithFields(log.Fields{"module": logModule, "error": err, "pubKey": xpubStr}).Debug("fail on check is next blocker")
65 block, err := proposal.NewBlockTemplate(b.chain, b.txPool, b.accountManager, nextBlockTime)
67 log.WithFields(log.Fields{"module": logModule, "error": err}).Error("failed on create NewBlockTemplate")
71 isOrphan, err := b.chain.ProcessBlock(block)
73 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Error("proposer fail on ProcessBlock")
77 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "isOrphan": isOrphan, "tx": len(block.Transactions)}).Info("proposer processed block")
78 // Broadcast the block and announce chain insertion event
79 if err = b.eventDispatcher.Post(event.NewProposedBlockEvent{Block: *block}); err != nil {
80 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Error("proposer fail on post block")
85 // Start begins the block propose process as well as the speed monitor used to
86 // track hashing metrics. Calling this function when the block proposer has
87 // already been started will have no effect.
89 // This function is safe for concurrent access.
90 func (b *BlockProposer) Start() {
94 // Nothing to do if the miner is already running
99 b.quit = make(chan struct{})
100 go b.generateBlocks()
103 log.Infof("block proposer started")
106 // Stop gracefully stops the proposal process by signalling all workers, and the
107 // speed monitor to quit. Calling this function when the block proposer has not
108 // already been started will have no effect.
110 // This function is safe for concurrent access.
111 func (b *BlockProposer) Stop() {
115 // Nothing to do if the miner is not currently running
122 log.Info("block proposer stopped")
125 // IsProposing returns whether the block proposer has been started.
127 // This function is safe for concurrent access.
128 func (b *BlockProposer) IsProposing() bool {
135 // NewBlockProposer returns a new instance of a block proposer for the provided configuration.
136 // Use Start to begin the proposal process. See the documentation for BlockProposer
137 // type for more details.
138 func NewBlockProposer(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, dispatcher *event.Dispatcher) *BlockProposer {
139 return &BlockProposer{
141 accountManager: accountManager,
143 eventDispatcher: dispatcher,