diff --git a/block/internal/da/forced_inclusion_retriever.go b/block/internal/da/forced_inclusion_retriever.go index 7b07b7d5d..9b0ad5529 100644 --- a/block/internal/da/forced_inclusion_retriever.go +++ b/block/internal/da/forced_inclusion_retriever.go @@ -16,8 +16,14 @@ import ( // ErrForceInclusionNotConfigured is returned when the forced inclusion namespace is not configured. var ErrForceInclusionNotConfigured = errors.New("forced inclusion namespace not configured") -// ForcedInclusionRetriever handles retrieval of forced inclusion transactions from DA. -type ForcedInclusionRetriever struct { +// ForcedInclusionRetriever defines the interface for retrieving forced inclusion transactions from DA. +type ForcedInclusionRetriever interface { + RetrieveForcedIncludedTxs(ctx context.Context, daHeight uint64) (*ForcedInclusionEvent, error) + Stop() +} + +// forcedInclusionRetriever handles retrieval of forced inclusion transactions from DA. +type forcedInclusionRetriever struct { client Client logger zerolog.Logger daEpochSize uint64 @@ -40,7 +46,7 @@ func NewForcedInclusionRetriever( logger zerolog.Logger, cfg config.Config, daStartHeight, daEpochSize uint64, -) *ForcedInclusionRetriever { +) ForcedInclusionRetriever { retrieverLogger := logger.With().Str("component", "forced_inclusion_retriever").Logger() // Create async block retriever for background prefetching @@ -54,24 +60,28 @@ func NewForcedInclusionRetriever( ) asyncFetcher.Start() - return &ForcedInclusionRetriever{ + base := &forcedInclusionRetriever{ client: client, logger: retrieverLogger, daStartHeight: daStartHeight, daEpochSize: daEpochSize, asyncFetcher: asyncFetcher, } + if cfg.Instrumentation.IsTracingEnabled() { + return withTracingForcedInclusionRetriever(base) + } + return base } // Stop stops the background prefetcher. -func (r *ForcedInclusionRetriever) Stop() { +func (r *forcedInclusionRetriever) Stop() { r.asyncFetcher.Stop() } // RetrieveForcedIncludedTxs retrieves forced inclusion transactions at the given DA height. // It respects epoch boundaries and only fetches at epoch end. // It tries to get blocks from the async fetcher cache first, then falls back to sync fetching. -func (r *ForcedInclusionRetriever) RetrieveForcedIncludedTxs(ctx context.Context, daHeight uint64) (*ForcedInclusionEvent, error) { +func (r *forcedInclusionRetriever) RetrieveForcedIncludedTxs(ctx context.Context, daHeight uint64) (*ForcedInclusionEvent, error) { // when daStartHeight is not set or no namespace is configured, we retrieve nothing. if !r.client.HasForcedInclusionNamespace() { return nil, ErrForceInclusionNotConfigured diff --git a/block/internal/da/forced_inclusion_tracing.go b/block/internal/da/forced_inclusion_tracing.go new file mode 100644 index 000000000..7e777161f --- /dev/null +++ b/block/internal/da/forced_inclusion_tracing.go @@ -0,0 +1,54 @@ +package da + +import ( + "context" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" +) + +var _ ForcedInclusionRetriever = (*tracedForcedInclusionRetriever)(nil) + +type tracedForcedInclusionRetriever struct { + inner ForcedInclusionRetriever + tracer trace.Tracer +} + +func withTracingForcedInclusionRetriever(inner ForcedInclusionRetriever) ForcedInclusionRetriever { + return &tracedForcedInclusionRetriever{ + inner: inner, + tracer: otel.Tracer("ev-node/forced-inclusion"), + } +} + +func (t *tracedForcedInclusionRetriever) RetrieveForcedIncludedTxs(ctx context.Context, daHeight uint64) (*ForcedInclusionEvent, error) { + ctx, span := t.tracer.Start(ctx, "ForcedInclusionRetriever.RetrieveForcedIncludedTxs", + trace.WithAttributes( + attribute.Int64("da.height", int64(daHeight)), + ), + ) + defer span.End() + + event, err := t.inner.RetrieveForcedIncludedTxs(ctx, daHeight) + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + return event, err + } + + if event != nil { + span.SetAttributes( + attribute.Int64("event.start_da_height", int64(event.StartDaHeight)), + attribute.Int64("event.end_da_height", int64(event.EndDaHeight)), + attribute.Int("event.tx_count", len(event.Txs)), + ) + } + + return event, nil +} + +func (t *tracedForcedInclusionRetriever) Stop() { + t.inner.Stop() +} diff --git a/block/internal/syncing/syncer.go b/block/internal/syncing/syncer.go index 6365c548b..ede86c9a2 100644 --- a/block/internal/syncing/syncer.go +++ b/block/internal/syncing/syncer.go @@ -104,7 +104,7 @@ type Syncer struct { // Handlers daRetriever DARetriever - fiRetriever *da.ForcedInclusionRetriever + fiRetriever da.ForcedInclusionRetriever p2pHandler p2pHandler // Forced inclusion tracking diff --git a/block/public.go b/block/public.go index 54bba68c7..f8586eebc 100644 --- a/block/public.go +++ b/block/public.go @@ -77,6 +77,7 @@ type ForcedInclusionRetriever interface { // NewForcedInclusionRetriever creates a new forced inclusion retriever. // It internally creates and manages an AsyncBlockRetriever for background prefetching. +// Tracing is automatically enabled when configured. func NewForcedInclusionRetriever( client DAClient, cfg config.Config,