@@ -35,6 +35,7 @@ type Datastore struct {
3535 maxConcurrency int
3636 shouldWriteBlocks bool
3737 shouldWriteBlockEvents bool
38+ shouldWriteFirstBlockEvent bool
3839 shouldWriteTransactions bool
3940 shouldWriteTransactionEvents bool
4041 shouldWritePeers bool
@@ -127,6 +128,7 @@ type DatastoreOptions struct {
127128 MaxConcurrency int
128129 ShouldWriteBlocks bool
129130 ShouldWriteBlockEvents bool
131+ ShouldWriteFirstBlockEvent bool
130132 ShouldWriteTransactions bool
131133 ShouldWriteTransactionEvents bool
132134 ShouldWritePeers bool
@@ -148,6 +150,7 @@ func NewDatastore(ctx context.Context, opts DatastoreOptions) Database {
148150 maxConcurrency : opts .MaxConcurrency ,
149151 shouldWriteBlocks : opts .ShouldWriteBlocks ,
150152 shouldWriteBlockEvents : opts .ShouldWriteBlockEvents ,
153+ shouldWriteFirstBlockEvent : opts .ShouldWriteFirstBlockEvent ,
151154 shouldWriteTransactions : opts .ShouldWriteTransactions ,
152155 shouldWriteTransactionEvents : opts .ShouldWriteTransactionEvents ,
153156 shouldWritePeers : opts .ShouldWritePeers ,
@@ -231,18 +234,28 @@ func (d *Datastore) WriteBlockHashes(ctx context.Context, peer *enode.Node, hash
231234// WriteBlockHashFirstSeen writes a partial block entry with just the hash
232235// first seen time if the block doesn't exist yet. If it exists, updates the
233236// TimeFirstSeenHash if the new time is earlier.
234- func (d * Datastore ) WriteBlockHashFirstSeen (ctx context.Context , hash common.Hash , tfsh time.Time ) {
235- if d .client == nil || ! d .ShouldWriteBlocks () {
237+ func (d * Datastore ) WriteBlockHashFirstSeen (ctx context.Context , peer * enode. Node , hash common.Hash , tfsh time.Time ) {
238+ if d .client == nil || ( ! d .ShouldWriteBlocks () && ! d . shouldWriteFirstBlockEvent ) {
236239 return
237240 }
238241
239242 d .runAsync (func () {
240- d .writeBlockHashFirstSeen (ctx , hash , tfsh )
243+ d .writeBlockHashFirstSeen (ctx , peer , hash , tfsh )
241244 })
242245}
243246
244247// writeBlockHashFirstSeen performs the actual transaction to write or update the block hash first seen time.
245- func (d * Datastore ) writeBlockHashFirstSeen (ctx context.Context , hash common.Hash , tfsh time.Time ) {
248+ func (d * Datastore ) writeBlockHashFirstSeen (ctx context.Context , peer * enode.Node , hash common.Hash , tfsh time.Time ) {
249+ // Write block event if flag enabled and block events are disabled (mutually exclusive).
250+ // Cache check in protocol.go already verified first-seen.
251+ if d .shouldWriteFirstBlockEvent && ! d .ShouldWriteBlockEvents () && peer != nil {
252+ d .writeEvent (peer , BlockEventsKind , hash , BlocksKind , tfsh )
253+ }
254+
255+ if ! d .shouldWriteBlocks {
256+ return
257+ }
258+
246259 key := datastore .NameKey (BlocksKind , hash .Hex (), nil )
247260
248261 _ , err := d .client .RunInTransaction (ctx , func (tx * datastore.Transaction ) error {
@@ -390,17 +403,8 @@ func (d *Datastore) newDatastoreHeader(header *types.Header, tfs time.Time, isPa
390403 }
391404}
392405
393- // writeFirstSeen updates timing fields on a header and block, preserving earlier timestamps.
394- func (d * Datastore ) writeFirstSeen (header * DatastoreHeader , block * DatastoreBlock , tfs time.Time ) {
395- // Preserve earlier header timing if it exists
396- if block .DatastoreHeader != nil &&
397- ! block .TimeFirstSeen .IsZero () &&
398- block .TimeFirstSeen .Before (tfs ) {
399- header .TimeFirstSeen = block .TimeFirstSeen
400- header .SensorFirstSeen = block .SensorFirstSeen
401- }
402-
403- // Set hash timing if it doesn't exist or if new timestamp is earlier
406+ // writeFirstSeen sets hash timing if it doesn't exist or if new timestamp is earlier.
407+ func (d * Datastore ) writeFirstSeen (block * DatastoreBlock , tfs time.Time ) {
404408 if block .TimeFirstSeenHash .IsZero () || tfs .Before (block .TimeFirstSeenHash ) {
405409 block .TimeFirstSeenHash = tfs
406410 block .SensorFirstSeenHash = d .sensorID
@@ -456,27 +460,27 @@ func (d *Datastore) writeBlock(ctx context.Context, block *types.Block, td *big.
456460 // are nil we will just set them.
457461 _ = tx .Get (key , & dsBlock )
458462
459- shouldWrite := false
463+ modified := false
460464
461465 if dsBlock .DatastoreHeader == nil || tfs .Before (dsBlock .TimeFirstSeen ) {
462- shouldWrite = true
466+ modified = true
463467
464468 // Create new header with current timing
465469 header := d .newDatastoreHeader (block .Header (), tfs , false )
466470
467- // Preserve earlier timestamps from any earlier announcement
468- d .writeFirstSeen (header , & dsBlock , tfs )
471+ // Preserve earliest first-seen timestamp
472+ d .writeFirstSeen (& dsBlock , tfs )
469473
470474 dsBlock .DatastoreHeader = header
471475 }
472476
473477 if len (dsBlock .TotalDifficulty ) == 0 {
474- shouldWrite = true
478+ modified = true
475479 dsBlock .TotalDifficulty = td .String ()
476480 }
477481
478482 if dsBlock .Transactions == nil && len (block .Transactions ()) > 0 {
479- shouldWrite = true
483+ modified = true
480484 if d .shouldWriteTransactions {
481485 d .writeTransactions (ctx , block .Transactions (), tfs )
482486 }
@@ -488,15 +492,15 @@ func (d *Datastore) writeBlock(ctx context.Context, block *types.Block, td *big.
488492 }
489493
490494 if dsBlock .Uncles == nil && len (block .Uncles ()) > 0 {
491- shouldWrite = true
495+ modified = true
492496 dsBlock .Uncles = make ([]* datastore.Key , 0 , len (block .Uncles ()))
493497 for _ , uncle := range block .Uncles () {
494498 d .writeBlockHeader (ctx , uncle , tfs , false )
495499 dsBlock .Uncles = append (dsBlock .Uncles , datastore .NameKey (BlocksKind , uncle .Hash ().Hex (), nil ))
496500 }
497501 }
498502
499- if shouldWrite {
503+ if modified {
500504 _ , err := tx .Put (key , & dsBlock )
501505 return err
502506 }
@@ -568,8 +572,8 @@ func (d *Datastore) writeBlockHeader(ctx context.Context, header *types.Header,
568572 // Create new header with current timing
569573 newHeader := d .newDatastoreHeader (header , tfs , isParent )
570574
571- // Preserve earlier timestamps from any earlier announcement or full block
572- d .writeFirstSeen (newHeader , & block , tfs )
575+ // Preserve earliest first-seen timestamp
576+ d .writeFirstSeen (& block , tfs )
573577
574578 block .DatastoreHeader = newHeader
575579 _ , err = tx .Put (key , & block )
@@ -590,10 +594,10 @@ func (d *Datastore) writeBlockBody(ctx context.Context, body *eth.BlockBody, has
590594 log .Debug ().Err (err ).Str ("hash" , hash .Hex ()).Msg ("Failed to fetch block when writing block body" )
591595 }
592596
593- shouldWrite := false
597+ modified := false
594598
595599 if block .Transactions == nil && len (body .Transactions ) > 0 {
596- shouldWrite = true
600+ modified = true
597601 if d .shouldWriteTransactions {
598602 d .writeTransactions (ctx , body .Transactions , tfs )
599603 }
@@ -605,15 +609,15 @@ func (d *Datastore) writeBlockBody(ctx context.Context, body *eth.BlockBody, has
605609 }
606610
607611 if block .Uncles == nil && len (body .Uncles ) > 0 {
608- shouldWrite = true
612+ modified = true
609613 block .Uncles = make ([]* datastore.Key , 0 , len (body .Uncles ))
610614 for _ , uncle := range body .Uncles {
611615 d .writeBlockHeader (ctx , uncle , tfs , false )
612616 block .Uncles = append (block .Uncles , datastore .NameKey (BlocksKind , uncle .Hash ().Hex (), nil ))
613617 }
614618 }
615619
616- if shouldWrite {
620+ if modified {
617621 _ , err := tx .Put (key , & block )
618622 return err
619623 }
@@ -642,6 +646,10 @@ func (d *Datastore) writeTransactions(ctx context.Context, txs []*types.Transact
642646 }
643647}
644648
649+ func (d * Datastore ) ShouldWriteFirstBlockEvent () bool {
650+ return d .shouldWriteFirstBlockEvent
651+ }
652+
645653func (d * Datastore ) NodeList (ctx context.Context , limit int ) ([]string , error ) {
646654 query := datastore .NewQuery (BlockEventsKind ).Order ("-Time" )
647655 iter := d .client .Run (ctx , query )
0 commit comments