diff --git a/block/internal/submitting/da_submitter.go b/block/internal/submitting/da_submitter.go index 8cf741dcd9..f38d2163c8 100644 --- a/block/internal/submitting/da_submitter.go +++ b/block/internal/submitting/da_submitter.go @@ -411,7 +411,7 @@ func submitToDA[T any]( // Record submission result for observability if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil { - daVisualizationServer.RecordSubmission(&res, 0, uint64(len(items))) + daVisualizationServer.RecordSubmission(&res, 0, uint64(len(items)), namespace) } switch res.Code { diff --git a/pkg/rpc/server/da_visualization.go b/pkg/rpc/server/da_visualization.go index ea003c6460..96410d7ace 100644 --- a/pkg/rpc/server/da_visualization.go +++ b/pkg/rpc/server/da_visualization.go @@ -29,6 +29,7 @@ type DASubmissionInfo struct { Message string `json:"message,omitempty"` NumBlobs uint64 `json:"num_blobs"` BlobIDs []string `json:"blob_ids,omitempty"` + Namespace string `json:"namespace,omitempty"` } // DAVisualizationServer provides DA layer visualization endpoints @@ -52,7 +53,7 @@ func NewDAVisualizationServer(da coreda.DA, logger zerolog.Logger, isAggregator // RecordSubmission records a DA submission for visualization // Only keeps the last 100 submissions in memory for the dashboard display -func (s *DAVisualizationServer) RecordSubmission(result *coreda.ResultSubmit, gasPrice float64, numBlobs uint64) { +func (s *DAVisualizationServer) RecordSubmission(result *coreda.ResultSubmit, gasPrice float64, numBlobs uint64, namespace []byte) { s.mutex.Lock() defer s.mutex.Unlock() @@ -72,6 +73,7 @@ func (s *DAVisualizationServer) RecordSubmission(result *coreda.ResultSubmit, ga Message: result.Message, NumBlobs: numBlobs, BlobIDs: blobIDs, + Namespace: hex.EncodeToString(namespace), } // Keep only the last 100 submissions in memory to avoid memory growth @@ -171,8 +173,49 @@ func (s *DAVisualizationServer) handleDABlobDetails(w http.ResponseWriter, r *ht ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second) defer cancel() - // Extract namespace - using empty namespace for now, could be parameterized - namespace := []byte{} + var namespace []byte + found := false + + // 1. Check query parameter first + nsParam := r.URL.Query().Get("namespace") + if nsParam != "" { + if ns, err := coreda.ParseHexNamespace(nsParam); err == nil { + namespace = ns.Bytes() + found = true + } else { + ns := coreda.NamespaceFromString(nsParam) + namespace = ns.Bytes() + found = true + } + } + + // 2. If not provided in query, try to find in recent submissions + if !found { + s.mutex.RLock() + for _, submission := range s.submissions { + for _, subBlobID := range submission.BlobIDs { + if subBlobID == blobID { + if submission.Namespace != "" { + if ns, err := hex.DecodeString(submission.Namespace); err == nil { + namespace = ns + found = true + } + } + break + } + } + if found { + break + } + } + s.mutex.RUnlock() + } + + if !found || len(namespace) == 0 { + http.Error(w, "Namespace required to retrieve blob (not found in recent submissions and not provided in query)", http.StatusBadRequest) + return + } + blobs, err := s.da.Get(ctx, []coreda.ID{id}, namespace) if err != nil { s.logger.Error().Err(err).Str("blob_id", blobID).Msg("Failed to retrieve blob from DA") diff --git a/pkg/rpc/server/da_visualization_test.go b/pkg/rpc/server/da_visualization_test.go index 80b9a1408c..2994dc9552 100644 --- a/pkg/rpc/server/da_visualization_test.go +++ b/pkg/rpc/server/da_visualization_test.go @@ -46,7 +46,7 @@ func TestRecordSubmission(t *testing.T) { }, } - server.RecordSubmission(result, -1, 2) + server.RecordSubmission(result, -1, 2, []byte("test-ns")) assert.Equal(t, 1, len(server.submissions)) submission := server.submissions[0] @@ -58,6 +58,7 @@ func TestRecordSubmission(t *testing.T) { assert.Equal(t, 2, len(submission.BlobIDs)) assert.Equal(t, hex.EncodeToString([]byte("test-id-1")), submission.BlobIDs[0]) assert.Equal(t, hex.EncodeToString([]byte("test-id-2")), submission.BlobIDs[1]) + assert.Equal(t, hex.EncodeToString([]byte("test-ns")), submission.Namespace) } func TestRecordSubmissionMemoryLimit(t *testing.T) { @@ -75,7 +76,7 @@ func TestRecordSubmissionMemoryLimit(t *testing.T) { Timestamp: time.Now(), }, } - server.RecordSubmission(result, float64(i)*0.1, 1) + server.RecordSubmission(result, float64(i)*0.1, 1, []byte{}) } // Should only keep the last 100 submissions @@ -124,9 +125,7 @@ func TestHandleDASubmissions(t *testing.T) { IDs: [][]byte{[]byte("test-id")}, }, } - server.RecordSubmission(result, 0.5, 1) - - // Create test request + server.RecordSubmission(result, 0.5, 1, []byte{}) req, err := http.NewRequest("GET", "/da/submissions", nil) require.NoError(t, err) @@ -197,7 +196,7 @@ func TestHandleDAVisualizationHTML(t *testing.T) { Message: "Test submission", }, } - server.RecordSubmission(result, 0.5, 1) + server.RecordSubmission(result, 0.5, 1, []byte{}) req, err := http.NewRequest("GET", "/da", nil) require.NoError(t, err) @@ -247,7 +246,7 @@ func TestRegisterCustomHTTPEndpointsDAVisualization(t *testing.T) { Timestamp: time.Now(), }, } - server.RecordSubmission(result, 0.5, 1) + server.RecordSubmission(result, 0.5, 1, []byte{}) // Set global server SetDAVisualizationServer(server) diff --git a/pkg/rpc/server/templates/da_visualization.html b/pkg/rpc/server/templates/da_visualization.html index d2167ff67b..7fcce60f52 100644 --- a/pkg/rpc/server/templates/da_visualization.html +++ b/pkg/rpc/server/templates/da_visualization.html @@ -178,8 +178,9 @@

Recent Submissions

{{.NumBlobs}} {{if .BlobIDs}}
+ {{$namespace := .Namespace}} {{range .BlobIDs}} - {{slice . 0 8}}... + {{slice . 0 8}}... {{end}}
{{end}}