You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Your 0G DA node implements a pruning mechanism that removes old blob data from COL_SLICE based on epoch windows, but fails to prune corresponding status entries from COL_BLOB_STATUS, causing unbounded database growth and state divergence. This creates a scenario where the database tracks blob statuses for epochs whose actual data has been deleted, leading to wasted storage and potential confusion during blob signing operations. While not a direct security vulnerability, this design flaw impacts node operational efficiency and database consistency over time.
Vulnerability Details
Architecture Overview
The node maintains two separate progress trackers in COL_MISC:
SYNC_PROGRESS_KEY (value 0): Tracks block numbers for DA log monitoring
PRUNE_PROGRESS_KEY (value 1): Tracks epoch numbers for data pruning
graph TD
A[start_server] --> B[setup_chain_state]
B --> C[start_da_monitor]
B --> D[start_grpc_server]
A --> E[start_pruner]
C --> F[spawn DA monitor loop]
E --> G[spawn pruner task]
Loading
The server starts both the DA monitor and pruner as concurrent Tokio tasks.
The pruner removes data from COL_SLICE using three prefix deletions:
BLOB_PREFIX (0): Blob metadata
SLICE_PREFIX (1): Compressed slice data
DATA_PREFIX (2): Raw slice data
Critical Gap: No equivalent pruning exists for COL_BLOB_STATUS (column 4) .
3. DA Monitor Execution Flow
graph TD
A[start_da_monitor] --> B[get_sync_progress]
B --> C{progress exists?}
C -->|No| D[put_sync_progress start_block]
C -->|Yes| E[spawn monitoring loop]
E --> F[check_da_logs every 5s]
F --> G[get_sync_progress]
F --> H[get finalized block]
F --> I[check_data_logs from-to]
I --> J[check_data_upload]
I --> K[check_data_verified]
J --> L[get_blob_status]
L --> M{status exists?}
M -->|No| N[put_blob UPLOADED]
M -->|Yes| O[skip]
Loading
The DA monitor processes DataUpload events and writes to COL_BLOB_STATUS without checking if the epoch was pruned.
Analogy: Imagine a library that removes old books from shelves (pruning) but keeps the catalog cards claiming those books still exist. Patrons can request "ghost books" that the catalog says exist but aren't actually on shelves.
Step-by-step execution:
Node goes offline at block 1000, epoch 50
Current epoch advances to 100, epoch_window_size = 10
Node restarts:
Pruner immediately prunes epochs 1-89 from COL_SLICE
DA monitor resumes from block 1000, processes blocks 1000-50000
For each DataUpload event in pruned epochs:
get_blob_status() returns None (new node scenario)
put_blob() writes UPLOADED status to COL_BLOB_STATUS
Result: COL_BLOB_STATUS contains entries for epochs 1-89, but COL_SLICE has no data for those epochs
5. Impact on Signing Flow
The batch_sign function checks blob status before signing:
Brief/Intro
Your 0G DA node implements a pruning mechanism that removes old blob data from
COL_SLICEbased on epoch windows, but fails to prune corresponding status entries fromCOL_BLOB_STATUS, causing unbounded database growth and state divergence. This creates a scenario where the database tracks blob statuses for epochs whose actual data has been deleted, leading to wasted storage and potential confusion during blob signing operations. While not a direct security vulnerability, this design flaw impacts node operational efficiency and database consistency over time.Vulnerability Details
Architecture Overview
The node maintains two separate progress trackers in
COL_MISC:SYNC_PROGRESS_KEY(value 0): Tracks block numbers for DA log monitoringPRUNE_PROGRESS_KEY(value 1): Tracks epoch numbers for data pruninghere
Execution Flow Analysis
1. Startup Sequence
graph TD A[start_server] --> B[setup_chain_state] B --> C[start_da_monitor] B --> D[start_grpc_server] A --> E[start_pruner] C --> F[spawn DA monitor loop] E --> G[spawn pruner task]The server starts both the DA monitor and pruner as concurrent Tokio tasks.
2. Pruner Execution Flow
graph TD A[run_pruner] --> B[get_prune_progress] B --> C{progress exists?} C -->|No| D[put_prune_progress 0] C -->|Yes| E[prune loop] E --> F[get current_epoch] E --> G[get epoch_window_size] E --> H[while pruned + 1 + window < current_epoch] H --> I[db.prune epoch] H --> J[put_prune_progress] I --> K[delete_prefix COL_SLICE]The pruner removes data from
COL_SLICEusing three prefix deletions:BLOB_PREFIX(0): Blob metadataSLICE_PREFIX(1): Compressed slice dataDATA_PREFIX(2): Raw slice dataCritical Gap: No equivalent pruning exists for
COL_BLOB_STATUS(column 4) .3. DA Monitor Execution Flow
graph TD A[start_da_monitor] --> B[get_sync_progress] B --> C{progress exists?} C -->|No| D[put_sync_progress start_block] C -->|Yes| E[spawn monitoring loop] E --> F[check_da_logs every 5s] F --> G[get_sync_progress] F --> H[get finalized block] F --> I[check_data_logs from-to] I --> J[check_data_upload] I --> K[check_data_verified] J --> L[get_blob_status] L --> M{status exists?} M -->|No| N[put_blob UPLOADED] M -->|Yes| O[skip]The DA monitor processes
DataUploadevents and writes toCOL_BLOB_STATUSwithout checking if the epoch was pruned.here
4. Zombie Data Creation Scenario
Analogy: Imagine a library that removes old books from shelves (pruning) but keeps the catalog cards claiming those books still exist. Patrons can request "ghost books" that the catalog says exist but aren't actually on shelves.
Step-by-step execution:
COL_SLICEDataUploadevent in pruned epochs:get_blob_status()returnsNone(new node scenario)put_blob()writesUPLOADEDstatus toCOL_BLOB_STATUSCOL_BLOB_STATUScontains entries for epochs 1-89, butCOL_SLICEhas no data for those epochs5. Impact on Signing Flow
The
batch_signfunction checks blob status before signing:No epoch age validation exists, so requests for ancient epochs with zombie status will pass this check and proceed to signing.
here
Impact Details
Storage Impact
COL_BLOB_STATUSgrows indefinitely - one entry per blob per epoch, foreverRecommendation
SliceDB::prune()to also delete fromCOL_BLOB_STATUS:check_blob_status(), validate epoch is within window: