Skip to content

Commit 6bdc919

Browse files
tac0turtleclaude[bot]tac0turtle
authored
feat: add DA visualization HTTP endpoints (#2544)
Implements comprehensive DA layer visualization with: - Real-time tracking of blob submissions from sequencer - HTML dashboard with auto-refresh showing submission status - JSON API endpoints for programmatic access - Individual blob inspection with hex content preview - Integration with existing submission flow Addresses issue #2104 by providing HTTP endpoints to inspect blobs submitted from sequencer nodes to the DA layer. Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Marko <[email protected]> Co-authored-by: tac0turtle <[email protected]>
1 parent 80d24c4 commit 6bdc919

File tree

16 files changed

+1634
-30
lines changed

16 files changed

+1634
-30
lines changed

apps/grpc/single/README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ Start the Evolve node with:
5555
--root-dir ~/.grpc-single \
5656
--grpc-executor-url http://localhost:50051 \
5757
--da.address http://localhost:7980 \
58-
--da.auth-token your-da-token \
59-
--chain-id your-chain-id
58+
--da.auth-token your-da-token
6059
```
6160

6261
## Command-Line Flags
@@ -93,12 +92,11 @@ Start the Evolve node with:
9392
3. Initialize and run the node:
9493

9594
```bash
96-
./grpc-single init --root-dir ~/.grpc-single
95+
./grpc-single init --root-dir ~/.grpc-single --chain-id test-chain
9796
./grpc-single start \
9897
--root-dir ~/.grpc-single \
9998
--grpc-executor-url http://localhost:50051 \
100-
--da.address http://localhost:7980 \
101-
--chain-id test-chain
99+
--da.address http://localhost:7980
102100
```
103101

104102
## Architecture

block/manager.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/evstack/ev-node/pkg/cache"
2626
"github.com/evstack/ev-node/pkg/config"
2727
"github.com/evstack/ev-node/pkg/genesis"
28+
"github.com/evstack/ev-node/pkg/rpc/server"
2829
"github.com/evstack/ev-node/pkg/signer"
2930
storepkg "github.com/evstack/ev-node/pkg/store"
3031
"github.com/evstack/ev-node/types"
@@ -415,6 +416,16 @@ func NewManager(
415416
return nil, fmt.Errorf("failed to load cache: %w", err)
416417
}
417418

419+
// Initialize DA visualization server if enabled
420+
if config.RPC.EnableDAVisualization {
421+
daVisualizationServer := server.NewDAVisualizationServer(da, logger.With().Str("module", "da_visualization").Logger(), config.Node.Aggregator)
422+
server.SetDAVisualizationServer(daVisualizationServer)
423+
logger.Info().Msg("DA visualization server enabled")
424+
} else {
425+
// Ensure the global server is nil when disabled
426+
server.SetDAVisualizationServer(nil)
427+
}
428+
418429
return m, nil
419430
}
420431

block/submitter.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
coreda "github.com/evstack/ev-node/core/da"
9+
"github.com/evstack/ev-node/pkg/rpc/server"
910
"github.com/evstack/ev-node/types"
1011
"google.golang.org/protobuf/proto"
1112
)
@@ -318,6 +319,12 @@ func handleSubmissionResult[T any](
318319

319320
case coreda.StatusContextCanceled:
320321
m.logger.Info().Int("attempt", retryStrategy.attempt).Msg("DA layer submission canceled due to context cancellation")
322+
323+
// Record canceled submission in DA visualization server
324+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
325+
daVisualizationServer.RecordSubmission(&res, retryStrategy.gasPrice, uint64(len(remaining)))
326+
}
327+
321328
return submissionOutcome[T]{
322329
RemainingItems: remaining,
323330
RemainingMarshal: marshaled,
@@ -347,6 +354,11 @@ func handleSuccessfulSubmission[T any](
347354
remLen := len(remaining)
348355
allSubmitted := res.SubmittedCount == uint64(remLen)
349356

357+
// Record submission in DA visualization server
358+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
359+
daVisualizationServer.RecordSubmission(res, retryStrategy.gasPrice, res.SubmittedCount)
360+
}
361+
350362
m.logger.Info().Str("itemType", itemType).Float64("gasPrice", retryStrategy.gasPrice).Uint64("count", res.SubmittedCount).Msg("successfully submitted items to DA layer")
351363

352364
submitted := remaining[:res.SubmittedCount]
@@ -383,6 +395,11 @@ func handleMempoolFailure[T any](
383395

384396
m.recordDAMetrics("submission", DAModeFail)
385397

398+
// Record failed submission in DA visualization server
399+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
400+
daVisualizationServer.RecordSubmission(res, retryStrategy.gasPrice, uint64(len(remaining)))
401+
}
402+
386403
gasMultiplier := m.getGasMultiplier(ctx)
387404
retryStrategy.BackoffOnMempool(int(m.config.DA.MempoolTTL), m.config.DA.BlockTime.Duration, gasMultiplier)
388405
m.logger.Info().Dur("backoff", retryStrategy.backoff).Float64("gasPrice", retryStrategy.gasPrice).Msg("retrying DA layer submission with")
@@ -409,6 +426,17 @@ func handleTooBigError[T any](
409426

410427
m.recordDAMetrics("submission", DAModeFail)
411428

429+
// Record failed submission in DA visualization server (create a result for TooBig error)
430+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
431+
tooBigResult := &coreda.ResultSubmit{
432+
BaseResult: coreda.BaseResult{
433+
Code: coreda.StatusTooBig,
434+
Message: "blob too big",
435+
},
436+
}
437+
daVisualizationServer.RecordSubmission(tooBigResult, retryStrategy.gasPrice, uint64(len(remaining)))
438+
}
439+
412440
if len(remaining) > 1 {
413441
totalSubmitted, err := submitWithRecursiveSplitting(m, ctx, remaining, marshaled, retryStrategy.gasPrice, postSubmit, itemType, namespace)
414442
if err != nil {
@@ -462,6 +490,12 @@ func handleGenericFailure[T any](
462490
m.logger.Error().Str("error", res.Message).Int("attempt", attempt).Msg("DA layer submission failed")
463491

464492
m.recordDAMetrics("submission", DAModeFail)
493+
494+
// Record failed submission in DA visualization server
495+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
496+
daVisualizationServer.RecordSubmission(res, retryStrategy.gasPrice, uint64(len(remaining)))
497+
}
498+
465499
retryStrategy.BackoffOnFailure()
466500

467501
return submissionOutcome[T]{
@@ -662,12 +696,22 @@ func processBatch[T any](
662696
postSubmit(submitted, &batchRes, gasPrice)
663697
m.logger.Info().Int("batchSize", len(batch.Items)).Uint64("submittedCount", batchRes.SubmittedCount).Msg("successfully submitted batch to DA layer")
664698

699+
// Record successful submission in DA visualization server
700+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
701+
daVisualizationServer.RecordSubmission(&batchRes, gasPrice, batchRes.SubmittedCount)
702+
}
703+
665704
return batchResult[T]{
666705
action: batchActionSubmitted,
667706
submittedCount: int(batchRes.SubmittedCount),
668707
}
669708
}
670709

710+
// Record failed submission in DA visualization server for all error cases
711+
if daVisualizationServer := server.GetDAVisualizationServer(); daVisualizationServer != nil {
712+
daVisualizationServer.RecordSubmission(&batchRes, gasPrice, uint64(len(batch.Items)))
713+
}
714+
671715
if batchRes.Code == coreda.StatusTooBig && len(batch.Items) > 1 {
672716
// Batch is too big - let the caller handle splitting
673717
m.logger.Debug().Int("batchSize", len(batch.Items)).Msg("batch too big, returning to caller for splitting")

docs/guides/da-visualizer.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# DA Visualizer
2+
3+
The Data Availability (DA) Visualizer is a built-in monitoring tool in Evolve that provides real-time insights into blob submissions to the DA layer. It offers a web-based interface for tracking submission statistics, monitoring DA layer health, and analyzing blob details.
4+
5+
**Note**: Only aggregator nodes submit data to the DA layer. Non-aggregator nodes will not display submission data.
6+
7+
## Overview
8+
9+
The DA Visualizer provides:
10+
11+
- Real-time monitoring of blob submissions (last 100 submissions)
12+
- Success/failure statistics and trends
13+
- Gas price tracking and cost analysis
14+
- DA layer health monitoring
15+
- Detailed blob inspection capabilities
16+
- Recent submission history
17+
18+
## Enabling the DA Visualizer
19+
20+
The DA Visualizer is disabled by default. To enable it, use the following configuration:
21+
22+
### Via Command-line Flag
23+
24+
```bash
25+
testapp start --rollkit.rpc.enable_da_visualization
26+
```
27+
28+
### Via Configuration File
29+
30+
Add the following to your `evolve.yaml` configuration file:
31+
32+
```yaml
33+
rpc:
34+
enable_da_visualization: true
35+
```
36+
37+
## Accessing the DA Visualizer
38+
39+
Once enabled, the DA Visualizer is accessible through your node's RPC server. By default, this is:
40+
41+
```
42+
http://localhost:7331/da
43+
```
44+
45+
The visualizer provides several API endpoints and a web interface:
46+
47+
### Web Interface
48+
49+
Navigate to `http://localhost:7331/da` in your web browser to access the interactive dashboard.
50+
51+
### API Endpoints
52+
53+
The following REST API endpoints are available for programmatic access:
54+
55+
#### Get Recent Submissions
56+
57+
```bash
58+
GET /da/submissions
59+
```
60+
61+
Returns the most recent blob submissions (up to 100 kept in memory).
62+
63+
#### Get Blob Details
64+
65+
```bash
66+
GET /da/blob?id={blob_id}
67+
```
68+
69+
Returns detailed information about a specific blob submission.
70+
71+
#### Get DA Statistics
72+
73+
```bash
74+
GET /da/stats
75+
```
76+
77+
Returns aggregated statistics including:
78+
79+
- Total submissions count
80+
- Success/failure rates
81+
- Average gas price
82+
- Total gas spent
83+
- Average blob size
84+
- Submission trends
85+
86+
#### Get DA Health Status
87+
88+
```bash
89+
GET /da/health
90+
```
91+
92+
Returns the current health status of the DA layer including:
93+
94+
- Connection status
95+
- Recent error rates
96+
- Performance metrics
97+
- Last successful submission timestamp
98+
99+
## Features
100+
101+
### Real-time Monitoring
102+
103+
The dashboard automatically updates every 30 seconds, displaying:
104+
105+
- Recent submission feed with status indicators (last 100 submissions)
106+
- Success rate percentage
107+
- Current gas price trends
108+
- Submission history
109+
110+
### Submission Details
111+
112+
Each submission entry shows:
113+
114+
- Timestamp
115+
- Blob ID with link to detailed view
116+
- Number of blobs in the batch
117+
- Submission status (success/failure)
118+
- Gas price used
119+
- Error messages (if any)
120+
121+
### Statistics Dashboard
122+
123+
The statistics section provides:
124+
125+
- **Performance Metrics**: Success rate, average submission time
126+
- **Cost Analysis**: Total gas spent, average gas price over time
127+
- **Volume Metrics**: Total blobs submitted, average blob size
128+
- **Trend Analysis**: Hourly and daily submission patterns
129+
130+
### Health Monitoring
131+
132+
The health status indicator shows:
133+
134+
- 🟢 **Healthy**: DA layer responding normally
135+
- 🟡 **Warning**: Some failures but overall functional
136+
- 🔴 **Critical**: High failure rate or connection issues
137+
138+
## Use Cases
139+
140+
### For Node Operators
141+
142+
- Monitor the reliability of DA submissions
143+
- Track gas costs and optimize gas price settings
144+
- Identify patterns in submission failures
145+
- Ensure DA layer connectivity
146+
147+
### For Developers
148+
149+
- Debug DA submission issues
150+
- Analyze blob data structure
151+
- Monitor application-specific submission patterns
152+
- Test DA layer integration
153+
154+
### For Network Monitoring
155+
156+
- Track overall network DA usage
157+
- Identify congestion periods
158+
- Monitor gas price fluctuations
159+
- Analyze submission patterns across the network
160+
161+
## Configuration Options
162+
163+
When enabling the DA Visualizer, you may want to adjust related RPC settings:
164+
165+
```yaml
166+
rpc:
167+
address: "0.0.0.0:7331" # Bind to all interfaces for remote access
168+
enable_da_visualization: true
169+
```
170+
171+
**Security Note**: If binding to all interfaces (`0.0.0.0`), ensure proper firewall rules are in place to restrict access to trusted sources only.
172+
173+
## Troubleshooting
174+
175+
### Visualizer Not Accessible
176+
177+
1. Verify the DA Visualizer is enabled:
178+
- Check your configuration file or ensure the flag is set
179+
- Look for log entries confirming "DA visualization endpoints registered"
180+
181+
2. Check the RPC server is running:
182+
- Verify the RPC address in logs
183+
- Ensure no port conflicts
184+
185+
3. For remote access:
186+
- Ensure the RPC server is bound to an accessible interface
187+
- Check firewall settings
188+
189+
### No Data Displayed
190+
191+
1. Verify your node is in aggregator mode (only aggregators submit to DA)
192+
2. Check DA layer connectivity in the node logs
193+
3. Ensure transactions are being processed
194+
4. Note that the visualizer only keeps the last 100 submissions in memory
195+
196+
### API Errors
197+
198+
- **404 Not Found**: DA Visualizer not enabled
199+
- **500 Internal Server Error**: Check node logs for DA connection issues
200+
- **Empty responses**: No submissions have been made yet
201+
202+
## Example Usage
203+
204+
### Using curl to access the API
205+
206+
```bash
207+
# Get recent submissions (returns up to 100)
208+
curl http://localhost:7331/da/submissions
209+
210+
# Get specific blob details
211+
curl http://localhost:7331/da/blob?id=abc123...
212+
213+
# Get statistics
214+
curl http://localhost:7331/da/stats
215+
216+
# Check DA health
217+
curl http://localhost:7331/da/health
218+
```
219+
220+
### Monitoring with scripts
221+
222+
```bash
223+
#!/bin/bash
224+
# Simple monitoring script
225+
226+
while true; do
227+
health=$(curl -s http://localhost:7331/da/health | jq -r '.status')
228+
if [ "$health" != "healthy" ]; then
229+
echo "DA layer issue detected: $health"
230+
# Send alert...
231+
fi
232+
sleep 30
233+
done
234+
```
235+
236+
## Related Configuration
237+
238+
For complete DA layer configuration options, see the [Config Reference](../learn/config.md#data-availability-configuration-da).
239+
240+
For metrics and monitoring setup, see the [Metrics Guide](./metrics.md).

0 commit comments

Comments
 (0)