88 "sync"
99 "time"
1010
11+ "github.com/ipfs/go-datastore"
1112 "github.com/rs/zerolog"
1213 "golang.org/x/sync/errgroup"
1314
@@ -187,11 +188,6 @@ func (e *Executor) initializeState() error {
187188 return fmt .Errorf ("failed to initialize chain: %w" , err )
188189 }
189190
190- // Create genesis block
191- if err := e .createGenesisBlock (e .ctx , stateRoot ); err != nil {
192- return fmt .Errorf ("failed to create genesis block: %w" , err )
193- }
194-
195191 state = types.State {
196192 ChainID : e .genesis .ChainID ,
197193 InitialHeight : e .genesis .InitialHeight ,
@@ -215,55 +211,6 @@ func (e *Executor) initializeState() error {
215211 return nil
216212}
217213
218- // createGenesisBlock creates and stores the genesis block
219- func (e * Executor ) createGenesisBlock (ctx context.Context , stateRoot []byte ) error {
220- header := types.Header {
221- AppHash : stateRoot ,
222- DataHash : common .DataHashForEmptyTxs ,
223- ProposerAddress : e .genesis .ProposerAddress ,
224- BaseHeader : types.BaseHeader {
225- ChainID : e .genesis .ChainID ,
226- Height : e .genesis .InitialHeight ,
227- Time : uint64 (e .genesis .StartTime .UnixNano ()),
228- },
229- }
230-
231- if e .signer == nil {
232- return errors .New ("signer cannot be nil" )
233- }
234-
235- pubKey , err := e .signer .GetPublic ()
236- if err != nil {
237- return fmt .Errorf ("failed to get public key: %w" , err )
238- }
239-
240- bz , err := e .options .AggregatorNodeSignatureBytesProvider (& header )
241- if err != nil {
242- return fmt .Errorf ("failed to get signature payload: %w" , err )
243- }
244-
245- sig , err := e .signer .Sign (bz )
246- if err != nil {
247- return fmt .Errorf ("failed to sign header: %w" , err )
248- }
249-
250- var signature types.Signature
251- data := & types.Data {}
252-
253- signature = sig
254-
255- genesisHeader := & types.SignedHeader {
256- Header : header ,
257- Signer : types.Signer {
258- PubKey : pubKey ,
259- Address : e .genesis .ProposerAddress ,
260- },
261- Signature : signature ,
262- }
263-
264- return e .store .SaveBlockData (ctx , genesisHeader , data , & signature )
265- }
266-
267214// executionLoop handles block production and aggregation
268215func (e * Executor ) executionLoop () {
269216 e .logger .Info ().Msg ("starting execution loop" )
@@ -364,20 +311,41 @@ func (e *Executor) produceBlock() error {
364311 }
365312 }
366313
367- // get batch from sequencer
368- batchData , err := e .retrieveBatch (e .ctx )
369- if errors .Is (err , common .ErrNoBatch ) {
370- e .logger .Debug ().Msg ("no batch available" )
371- return nil
372- } else if errors .Is (err , common .ErrNoTransactionsInBatch ) {
373- e .logger .Debug ().Msg ("no transactions in batch" )
374- } else if err != nil {
375- return fmt .Errorf ("failed to retrieve batch: %w" , err )
376- }
314+ var (
315+ header * types.SignedHeader
316+ data * types.Data
317+ )
318+
319+ // Check if there's an already stored block at the newHeight
320+ // If there is use that instead of creating a new block
321+ pendingHeader , pendingData , err := e .store .GetBlockData (e .ctx , newHeight )
322+ if err == nil {
323+ e .logger .Info ().Uint64 ("height" , newHeight ).Msg ("using pending block" )
324+ header = pendingHeader
325+ data = pendingData
326+ } else if ! errors .Is (err , datastore .ErrNotFound ) {
327+ return fmt .Errorf ("failed to get block data: %w" , err )
328+ } else {
329+ // get batch from sequencer
330+ batchData , err := e .retrieveBatch (e .ctx )
331+ if errors .Is (err , common .ErrNoBatch ) {
332+ e .logger .Debug ().Msg ("no batch available" )
333+ return nil
334+ } else if errors .Is (err , common .ErrNoTransactionsInBatch ) {
335+ e .logger .Debug ().Msg ("no transactions in batch" )
336+ } else if err != nil {
337+ return fmt .Errorf ("failed to retrieve batch: %w" , err )
338+ }
377339
378- header , data , err := e .createBlock (e .ctx , newHeight , batchData )
379- if err != nil {
380- return fmt .Errorf ("failed to create block: %w" , err )
340+ header , data , err = e .createBlock (e .ctx , newHeight , batchData )
341+ if err != nil {
342+ return fmt .Errorf ("failed to create block: %w" , err )
343+ }
344+
345+ // saved early for crash recovery, will be overwritten later with the final signature
346+ if err = e .store .SaveBlockData (e .ctx , header , data , & types.Signature {}); err != nil {
347+ return fmt .Errorf ("failed to save block: %w" , err )
348+ }
381349 }
382350
383351 newState , err := e .applyBlock (e .ctx , header .Header , data )
@@ -459,18 +427,28 @@ func (e *Executor) retrieveBatch(ctx context.Context) (*BatchData, error) {
459427// createBlock creates a new block from the given batch
460428func (e * Executor ) createBlock (ctx context.Context , height uint64 , batchData * BatchData ) (* types.SignedHeader , * types.Data , error ) {
461429 currentState := e .GetLastState ()
430+ headerTime := uint64 (e .genesis .StartTime .UnixNano ())
462431
463432 // Get last block info
464433 var lastHeaderHash types.Hash
465434 var lastDataHash types.Hash
435+ var lastSignature types.Signature
466436
467437 if height > e .genesis .InitialHeight {
438+ headerTime = uint64 (batchData .UnixNano ())
439+
468440 lastHeader , lastData , err := e .store .GetBlockData (ctx , height - 1 )
469441 if err != nil {
470442 return nil , nil , fmt .Errorf ("failed to get last block: %w" , err )
471443 }
472444 lastHeaderHash = lastHeader .Hash ()
473445 lastDataHash = lastData .Hash ()
446+
447+ lastSignaturePtr , err := e .store .GetSignature (ctx , height - 1 )
448+ if err != nil {
449+ return nil , nil , fmt .Errorf ("failed to get last signature: %w" , err )
450+ }
451+ lastSignature = * lastSignaturePtr
474452 }
475453
476454 // Get signer info
@@ -479,7 +457,6 @@ func (e *Executor) createBlock(ctx context.Context, height uint64, batchData *Ba
479457 return nil , nil , fmt .Errorf ("failed to get public key: %w" , err )
480458 }
481459
482- // Build validator hash
483460 // Get validator hash
484461 validatorHash , err := e .options .ValidatorHasherProvider (e .genesis .ProposerAddress , pubKey )
485462 if err != nil {
@@ -496,14 +473,15 @@ func (e *Executor) createBlock(ctx context.Context, height uint64, batchData *Ba
496473 BaseHeader : types.BaseHeader {
497474 ChainID : e .genesis .ChainID ,
498475 Height : height ,
499- Time : uint64 ( batchData . UnixNano ()) ,
476+ Time : headerTime ,
500477 },
501478 LastHeaderHash : lastHeaderHash ,
502479 ConsensusHash : make (types.Hash , 32 ),
503480 AppHash : currentState .AppHash ,
504481 ProposerAddress : e .genesis .ProposerAddress ,
505482 ValidatorHash : validatorHash ,
506483 },
484+ Signature : lastSignature ,
507485 Signer : types.Signer {
508486 PubKey : pubKey ,
509487 Address : e .genesis .ProposerAddress ,
@@ -639,6 +617,9 @@ func (e *Executor) sendCriticalError(err error) {
639617
640618// recordBlockMetrics records metrics for the produced block
641619func (e * Executor ) recordBlockMetrics (data * types.Data ) {
620+ if data == nil || data .Metadata == nil {
621+ return
622+ }
642623 e .metrics .NumTxs .Set (float64 (len (data .Txs )))
643624 e .metrics .TotalTxs .Add (float64 (len (data .Txs )))
644625 e .metrics .BlockSizeBytes .Set (float64 (data .Size ()))
0 commit comments