9494 // MintNewBlock creates a new block with given actions
9595 // Note: the coinbase transfer will be added to the given transfers when minting a new block
9696 MintNewBlock (timestamp time.Time ) (* block.Block , error )
97+ // PrepareBlock start to prepares a new block with given previous hash asynchrously
98+ // it can speed up the MintNewBlock
99+ PrepareBlock (height uint64 , prevHash []byte , timestamp time.Time ) error
97100 // CommitBlock validates and appends a block to the chain
98101 CommitBlock (blk * block.Block ) error
99102 // ValidateBlock validates a new block before adding it to the blockchain
@@ -110,6 +113,7 @@ type (
110113 BlockBuilderFactory interface {
111114 // NewBlockBuilder creates block builder
112115 NewBlockBuilder (context.Context , func (action.Envelope ) (* action.SealedEnvelope , error )) (* block.Builder , error )
116+ NewBlockBuilderAt (context.Context , func (action.Envelope ) (* action.SealedEnvelope , error ), []byte ) (* block.Builder , error )
113117 }
114118
115119 // blockchain implements the Blockchain interface
@@ -125,7 +129,8 @@ type (
125129 timerFactory * prometheustimer.TimerFactory
126130
127131 // used by account-based model
128- bbf BlockBuilderFactory
132+ bbf BlockBuilderFactory
133+ prepare * Prepare
129134 }
130135)
131136
@@ -187,6 +192,7 @@ func NewBlockchain(cfg Config, g genesis.Genesis, dao blockdao.BlockDAO, bbf Blo
187192 bbf : bbf ,
188193 clk : clock .New (),
189194 pubSubManager : NewPubSub (cfg .StreamingBlockBufferSize ),
195+ prepare : newPrepare (),
190196 }
191197 for _ , opt := range opts {
192198 if err := opt (chain ); err != nil {
@@ -208,7 +214,7 @@ func NewBlockchain(cfg Config, g genesis.Genesis, dao blockdao.BlockDAO, bbf Blo
208214 }
209215 chain .lifecycle .Add (chain .dao )
210216 chain .lifecycle .Add (chain .pubSubManager )
211-
217+ chain . pubSubManager . AddBlockListener ( chain . prepare )
212218 return chain
213219}
214220
@@ -407,6 +413,41 @@ func (bc *blockchain) context(ctx context.Context, height uint64) (context.Conte
407413 return protocol .WithFeatureWithHeightCtx (ctx ), nil
408414}
409415
416+ func (bc * blockchain ) PrepareBlock (height uint64 , prevHash []byte , timestamp time.Time ) error {
417+ ctx , err := bc .context (context .Background (), height - 1 )
418+ if err != nil {
419+ return err
420+ }
421+ tip := protocol .MustGetBlockchainCtx (ctx ).Tip
422+ ctx = bc .contextWithBlock (ctx , bc .config .ProducerAddress (), height , timestamp , protocol .CalcBaseFee (genesis .MustExtractGenesisContext (ctx ).Blockchain , & tip ), protocol .CalcExcessBlobGas (tip .ExcessBlobGas , tip .BlobGasUsed ))
423+ ctx = protocol .WithFeatureCtx (ctx )
424+ // run execution and update state trie root hash
425+ minterPrivateKey := bc .config .ProducerPrivateKey ()
426+
427+ go bc .prepare .PrepareBlock (prevHash , func () (* block.Block , error ) {
428+ blockBuilder , err := bc .bbf .NewBlockBuilderAt (
429+ ctx ,
430+ func (elp action.Envelope ) (* action.SealedEnvelope , error ) {
431+ return action .Sign (elp , minterPrivateKey )
432+ },
433+ prevHash ,
434+ )
435+ if err != nil {
436+ return nil , errors .Wrapf (err , "failed to create block builder at height %d" , height )
437+ }
438+ blk , err := blockBuilder .SignAndBuild (minterPrivateKey )
439+ if err != nil {
440+ return nil , errors .Wrapf (err , "failed to create block at height %d" , height )
441+ }
442+
443+ _blockMtc .WithLabelValues ("MintGas" ).Set (float64 (blk .GasUsed ()))
444+ _blockMtc .WithLabelValues ("MintActions" ).Set (float64 (len (blk .Actions )))
445+ return & blk , nil
446+ })
447+
448+ return nil
449+ }
450+
410451func (bc * blockchain ) MintNewBlock (timestamp time.Time ) (* block.Block , error ) {
411452 bc .mu .RLock ()
412453 defer bc .mu .RUnlock ()
@@ -422,6 +463,17 @@ func (bc *blockchain) MintNewBlock(timestamp time.Time) (*block.Block, error) {
422463 return nil , err
423464 }
424465 tip := protocol .MustGetBlockchainCtx (ctx ).Tip
466+
467+ // retrieve the draft block if it's prepared
468+ pblk , err := bc .prepare .WaitBlock (tip .Hash [:])
469+ if pblk != nil {
470+ return pblk , nil
471+ }
472+ if err != nil {
473+ log .L ().Error ("Failed to prepare new block" , zap .Error (err ))
474+ }
475+
476+ // create a new block
425477 ctx = bc .contextWithBlock (ctx , bc .config .ProducerAddress (), newblockHeight , timestamp , protocol .CalcBaseFee (genesis .MustExtractGenesisContext (ctx ).Blockchain , & tip ), protocol .CalcExcessBlobGas (tip .ExcessBlobGas , tip .BlobGasUsed ))
426478 ctx = protocol .WithFeatureCtx (ctx )
427479 // run execution and update state trie root hash
0 commit comments