|
| 1 | +--- |
| 2 | +title: Archive Database Queries |
| 3 | +description: SQL queries and database analysis for Mina Rust archive nodes |
| 4 | +sidebar_position: 7 |
| 5 | +--- |
| 6 | + |
| 7 | +# Archive Database Queries |
| 8 | + |
| 9 | +This guide provides comprehensive SQL queries and analysis techniques for |
| 10 | +querying Mina Rust archive node databases. Archive nodes store complete |
| 11 | +blockchain history in a structured PostgreSQL database with over 45 tables. |
| 12 | + |
| 13 | +## Prerequisites |
| 14 | + |
| 15 | +- Running archive node with PostgreSQL database |
| 16 | +- Database credentials (default: user `postgres`, database `archive`) |
| 17 | +- PostgreSQL client tools installed |
| 18 | + |
| 19 | +## Database Connection |
| 20 | + |
| 21 | +### Direct Connection |
| 22 | + |
| 23 | +```bash |
| 24 | +# Connect using psql (requires PostgreSQL client installed) |
| 25 | +psql -h localhost -p 5432 -U postgres -d archive |
| 26 | + |
| 27 | +# Or connect from within the Docker environment |
| 28 | +# Note: postgres-mina-rust is the container name from the archive node setup |
| 29 | +# See: https://o1-labs.github.io/mina-rust/node-operators/archive-node |
| 30 | +docker exec -it postgres-mina-rust psql -U postgres -d archive |
| 31 | +``` |
| 32 | + |
| 33 | +## Database Schema |
| 34 | + |
| 35 | +### Schema Exploration |
| 36 | + |
| 37 | +```sql |
| 38 | +-- List all tables in the archive database |
| 39 | +\dt |
| 40 | + |
| 41 | +-- Get detailed information about table columns |
| 42 | +\d table_name |
| 43 | + |
| 44 | +-- Example: Get structure of the blocks table |
| 45 | +\d blocks |
| 46 | + |
| 47 | +-- Show all tables with their sizes |
| 48 | +SELECT |
| 49 | + schemaname, |
| 50 | + tablename, |
| 51 | + pg_size_pretty(pg_total_relation_size(tablename::text)) as size |
| 52 | +FROM pg_tables |
| 53 | +WHERE schemaname = 'public' |
| 54 | +ORDER BY pg_total_relation_size(tablename::text) DESC; |
| 55 | +``` |
| 56 | + |
| 57 | +### Key Tables |
| 58 | + |
| 59 | +The archive database contains these primary tables: |
| 60 | + |
| 61 | +- **`blocks`** - Block headers and metadata |
| 62 | +- **`user_commands`** - Payment and delegation transactions |
| 63 | +- **`internal_commands`** - Fee transfers, coinbase rewards |
| 64 | +- **`zkapp_commands`** - zkApp transactions and proof data |
| 65 | +- **`accounts_accessed`** - Account state changes |
| 66 | +- **`accounts_created`** - New account creations |
| 67 | +- **`blocks_user_commands`** - Links blocks to user commands |
| 68 | +- **`blocks_internal_commands`** - Links blocks to internal commands |
| 69 | +- **`public_keys`** - Public key identifiers |
| 70 | +- **`zkapp_*`** - Various zkApp-related tables for smart contract data |
| 71 | + |
| 72 | +### Schema Files |
| 73 | + |
| 74 | +The complete database schema definitions can be found in the repository: |
| 75 | + |
| 76 | +- **Schema file**: |
| 77 | + [`producer-dashboard/docker/init-db/create_schema.sql`](https://github.com/o1-labs/mina-rust/blob/develop/producer-dashboard/docker/init-db/create_schema.sql) |
| 78 | +- **Indexes**: |
| 79 | + [`producer-dashboard/docker/init-db/add_indexes.sql`](https://github.com/o1-labs/mina-rust/blob/develop/producer-dashboard/docker/init-db/add_indexes.sql) |
| 80 | +- **Unique constraints**: |
| 81 | + [`producer-dashboard/docker/init-db/add_unique_constraints.sql`](https://github.com/o1-labs/mina-rust/blob/develop/producer-dashboard/docker/init-db/add_unique_constraints.sql) |
| 82 | +- **zkApp tables**: |
| 83 | + [`producer-dashboard/docker/init-db/zkapp_tables.sql`](https://github.com/o1-labs/mina-rust/blob/develop/producer-dashboard/docker/init-db/zkapp_tables.sql) |
| 84 | +- **Query examples**: |
| 85 | + [`producer-dashboard/src/archive/sql/`](https://github.com/o1-labs/mina-rust/tree/develop/producer-dashboard/src/archive/sql) - |
| 86 | + Pre-built queries for common operations |
| 87 | + |
| 88 | +## Common SQL Queries |
| 89 | + |
| 90 | +### Block Information |
| 91 | + |
| 92 | +```sql |
| 93 | +-- Get recent blocks |
| 94 | +SELECT |
| 95 | + b.height, |
| 96 | + b.state_hash, |
| 97 | + b.parent_hash, |
| 98 | + pk.value as creator, |
| 99 | + b.timestamp |
| 100 | +FROM blocks b |
| 101 | +JOIN public_keys pk ON b.creator_id = pk.id |
| 102 | +ORDER BY b.height DESC |
| 103 | +LIMIT 10; |
| 104 | + |
| 105 | +-- Get block statistics by creator |
| 106 | +SELECT |
| 107 | + pk.value as creator, |
| 108 | + COUNT(*) as blocks_produced, |
| 109 | + MIN(b.height) as first_block, |
| 110 | + MAX(b.height) as latest_block |
| 111 | +FROM blocks b |
| 112 | +JOIN public_keys pk ON b.creator_id = pk.id |
| 113 | +GROUP BY pk.value |
| 114 | +ORDER BY blocks_produced DESC; |
| 115 | +``` |
| 116 | + |
| 117 | +### Transaction Analysis |
| 118 | + |
| 119 | +```sql |
| 120 | +-- Get recent payments |
| 121 | +SELECT |
| 122 | + b.height, |
| 123 | + b.timestamp, |
| 124 | + pk_source.value as source, |
| 125 | + pk_receiver.value as receiver, |
| 126 | + uc.amount, |
| 127 | + uc.fee |
| 128 | +FROM user_commands uc |
| 129 | +JOIN blocks_user_commands buc ON uc.id = buc.user_command_id |
| 130 | +JOIN blocks b ON buc.block_id = b.id |
| 131 | +JOIN public_keys pk_source ON uc.source_id = pk_source.id |
| 132 | +JOIN public_keys pk_receiver ON uc.receiver_id = pk_receiver.id |
| 133 | +WHERE uc.command_type = 'payment' |
| 134 | +ORDER BY b.height DESC |
| 135 | +LIMIT 20; |
| 136 | + |
| 137 | +-- Transaction volume analysis |
| 138 | +SELECT |
| 139 | + DATE(to_timestamp(b.timestamp::bigint / 1000)) as date, |
| 140 | + COUNT(uc.id) as tx_count, |
| 141 | + SUM(uc.amount::bigint) as total_volume, |
| 142 | + AVG(uc.fee::bigint) as avg_fee |
| 143 | +FROM user_commands uc |
| 144 | +JOIN blocks_user_commands buc ON uc.id = buc.user_command_id |
| 145 | +JOIN blocks b ON buc.block_id = b.id |
| 146 | +WHERE uc.command_type = 'payment' |
| 147 | +GROUP BY DATE(to_timestamp(b.timestamp::bigint / 1000)) |
| 148 | +ORDER BY date DESC; |
| 149 | +``` |
| 150 | + |
| 151 | +### Account Analysis |
| 152 | + |
| 153 | +```sql |
| 154 | +-- Most active accounts |
| 155 | +SELECT |
| 156 | + pk.value as public_key, |
| 157 | + COUNT(*) as transaction_count |
| 158 | +FROM user_commands uc |
| 159 | +JOIN public_keys pk ON uc.source_id = pk.id |
| 160 | +GROUP BY pk.value |
| 161 | +ORDER BY transaction_count DESC |
| 162 | +LIMIT 10; |
| 163 | + |
| 164 | +-- Account balance history (requires account state tracking) |
| 165 | +SELECT |
| 166 | + aa.account_identifier_id, |
| 167 | + pk.value as public_key, |
| 168 | + aa.balance, |
| 169 | + b.height, |
| 170 | + b.timestamp |
| 171 | +FROM accounts_accessed aa |
| 172 | +JOIN public_keys pk ON aa.account_identifier_id = pk.id |
| 173 | +JOIN blocks b ON aa.block_id = b.id |
| 174 | +WHERE pk.value = 'YOUR_PUBLIC_KEY_HERE' |
| 175 | +ORDER BY b.height DESC; |
| 176 | +``` |
| 177 | + |
| 178 | +## Analytics and Reporting |
| 179 | + |
| 180 | +### Python Analysis Script |
| 181 | + |
| 182 | +```python |
| 183 | +import psycopg2 |
| 184 | +import pandas as pd |
| 185 | +import matplotlib.pyplot as plt |
| 186 | + |
| 187 | +# Connect to archive database |
| 188 | +conn = psycopg2.connect( |
| 189 | + host="localhost", |
| 190 | + port=5432, |
| 191 | + database="archive", |
| 192 | + user="postgres", |
| 193 | + password="mina" |
| 194 | +) |
| 195 | + |
| 196 | +# Analyze block production over time |
| 197 | +query = """ |
| 198 | +SELECT |
| 199 | + DATE(to_timestamp(timestamp::bigint / 1000)) as date, |
| 200 | + COUNT(*) as blocks_per_day, |
| 201 | + COUNT(DISTINCT creator_id) as unique_producers |
| 202 | +FROM blocks |
| 203 | +WHERE timestamp > extract(epoch from now() - interval '30 days') * 1000 |
| 204 | +GROUP BY date |
| 205 | +ORDER BY date; |
| 206 | +""" |
| 207 | + |
| 208 | +df = pd.read_sql_query(query, conn) |
| 209 | +print(df) |
| 210 | + |
| 211 | +# Plot block production |
| 212 | +df.plot(x='date', y='blocks_per_day', kind='line') |
| 213 | +plt.title('Daily Block Production') |
| 214 | +plt.show() |
| 215 | +``` |
| 216 | + |
| 217 | +### Export Data for Analysis |
| 218 | + |
| 219 | +```bash |
| 220 | +# Export recent transactions to CSV |
| 221 | +docker exec postgres-mina-rust psql -U postgres -d archive -c "\COPY ( |
| 222 | + SELECT |
| 223 | + b.height, |
| 224 | + b.timestamp, |
| 225 | + pk_source.value as source, |
| 226 | + pk_receiver.value as receiver, |
| 227 | + uc.amount, |
| 228 | + uc.fee, |
| 229 | + uc.memo |
| 230 | + FROM user_commands uc |
| 231 | + JOIN blocks_user_commands buc ON uc.id = buc.user_command_id |
| 232 | + JOIN blocks b ON buc.block_id = b.id |
| 233 | + JOIN public_keys pk_source ON uc.source_id = pk_source.id |
| 234 | + JOIN public_keys pk_receiver ON uc.receiver_id = pk_receiver.id |
| 235 | + WHERE uc.command_type = 'payment' |
| 236 | + ORDER BY b.height DESC |
| 237 | + LIMIT 1000 |
| 238 | +) TO STDOUT WITH CSV HEADER" > transactions.csv |
| 239 | +``` |
| 240 | + |
| 241 | +## Database Maintenance |
| 242 | + |
| 243 | +### Backup and Restore |
| 244 | + |
| 245 | +```bash |
| 246 | +# Create database dump |
| 247 | +docker exec postgres-mina-rust pg_dump -U postgres archive > archive_backup.sql |
| 248 | + |
| 249 | +# Restore from backup |
| 250 | +docker exec -i postgres-mina-rust psql -U postgres archive < archive_backup.sql |
| 251 | +``` |
| 252 | + |
| 253 | +### Performance Optimization |
| 254 | + |
| 255 | +```sql |
| 256 | +-- Create indexes for common queries |
| 257 | +CREATE INDEX CONCURRENTLY idx_blocks_height ON blocks(height); |
| 258 | +CREATE INDEX CONCURRENTLY idx_blocks_timestamp ON blocks(timestamp); |
| 259 | +CREATE INDEX CONCURRENTLY idx_user_commands_source ON user_commands(source_id); |
| 260 | +CREATE INDEX CONCURRENTLY idx_user_commands_receiver ON user_commands(receiver_id); |
| 261 | + |
| 262 | +-- Analyze table statistics |
| 263 | +ANALYZE blocks; |
| 264 | +ANALYZE user_commands; |
| 265 | +ANALYZE accounts_accessed; |
| 266 | +``` |
| 267 | + |
| 268 | +### Storage Management |
| 269 | + |
| 270 | +```bash |
| 271 | +# Check database size |
| 272 | +docker exec postgres-mina-rust psql -U postgres -d archive -c " |
| 273 | + SELECT |
| 274 | + schemaname, |
| 275 | + tablename, |
| 276 | + pg_size_pretty(pg_total_relation_size(tablename::text)) as size |
| 277 | + FROM pg_tables |
| 278 | + WHERE schemaname = 'public' |
| 279 | + ORDER BY pg_total_relation_size(tablename::text) DESC; |
| 280 | +" |
| 281 | + |
| 282 | +# Vacuum and analyze for performance |
| 283 | +docker exec postgres-mina-rust psql -U postgres -d archive -c "VACUUM ANALYZE;" |
| 284 | +``` |
| 285 | + |
| 286 | +## Advanced Queries |
| 287 | + |
| 288 | +### Network Statistics |
| 289 | + |
| 290 | +```sql |
| 291 | +-- Block production distribution |
| 292 | +SELECT |
| 293 | + pk.value as producer, |
| 294 | + COUNT(*) as blocks_produced, |
| 295 | + ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as percentage |
| 296 | +FROM blocks b |
| 297 | +JOIN public_keys pk ON b.creator_id = pk.id |
| 298 | +GROUP BY pk.value |
| 299 | +ORDER BY blocks_produced DESC; |
| 300 | + |
| 301 | +-- Transaction fee analysis |
| 302 | +SELECT |
| 303 | + percentile_cont(0.5) WITHIN GROUP (ORDER BY uc.fee::bigint) as median_fee, |
| 304 | + percentile_cont(0.75) WITHIN GROUP (ORDER BY uc.fee::bigint) as p75_fee, |
| 305 | + percentile_cont(0.95) WITHIN GROUP (ORDER BY uc.fee::bigint) as p95_fee, |
| 306 | + AVG(uc.fee::bigint) as avg_fee, |
| 307 | + MIN(uc.fee::bigint) as min_fee, |
| 308 | + MAX(uc.fee::bigint) as max_fee |
| 309 | +FROM user_commands uc |
| 310 | +WHERE uc.command_type = 'payment'; |
| 311 | +``` |
| 312 | + |
| 313 | +### zkApp Analytics |
| 314 | + |
| 315 | +```sql |
| 316 | +-- zkApp transaction volume |
| 317 | +SELECT |
| 318 | + DATE(to_timestamp(b.timestamp::bigint / 1000)) as date, |
| 319 | + COUNT(zc.id) as zkapp_count |
| 320 | +FROM zkapp_commands zc |
| 321 | +JOIN blocks_zkapp_commands bzc ON zc.id = bzc.zkapp_command_id |
| 322 | +JOIN blocks b ON bzc.block_id = b.id |
| 323 | +GROUP BY DATE(to_timestamp(b.timestamp::bigint / 1000)) |
| 324 | +ORDER BY date DESC; |
| 325 | + |
| 326 | +-- Most active zkApp accounts |
| 327 | +SELECT |
| 328 | + pk.value as public_key, |
| 329 | + COUNT(*) as zkapp_transactions |
| 330 | +FROM zkapp_commands zc |
| 331 | +JOIN zkapp_fee_payer_body zfpb ON zc.zkapp_fee_payer_body_id = zfpb.id |
| 332 | +JOIN public_keys pk ON zfpb.public_key_id = pk.id |
| 333 | +GROUP BY pk.value |
| 334 | +ORDER BY zkapp_transactions DESC |
| 335 | +LIMIT 10; |
| 336 | +``` |
| 337 | + |
| 338 | +## Use Cases |
| 339 | + |
| 340 | +1. **Compliance and Auditing**: Track all transactions for regulatory compliance |
| 341 | +2. **Analytics Dashboards**: Build real-time blockchain analytics |
| 342 | +3. **Research**: Analyze network behavior, transaction patterns, and economics |
| 343 | +4. **Block Explorers**: Power blockchain explorer websites |
| 344 | +5. **Tax Reporting**: Generate transaction history for tax purposes |
| 345 | +6. **Network Monitoring**: Track network health and validator performance |
| 346 | + |
| 347 | +## Performance Considerations |
| 348 | + |
| 349 | +- **Complex queries**: Use appropriate indexes and LIMIT clauses |
| 350 | +- **Large result sets**: Consider pagination for web applications |
| 351 | +- **Historical data**: Older data may be slower to query |
| 352 | +- **Concurrent access**: Archive database can handle multiple read connections |
| 353 | +- **Memory usage**: Large analytical queries may require sufficient RAM |
| 354 | + |
| 355 | +## Troubleshooting |
| 356 | + |
| 357 | +### Common Issues |
| 358 | + |
| 359 | +**Connection refused**: |
| 360 | + |
| 361 | +```bash |
| 362 | +# Check if PostgreSQL container is running |
| 363 | +docker ps | grep postgres |
| 364 | + |
| 365 | +# Check container logs |
| 366 | +docker logs postgres-mina-rust |
| 367 | +``` |
| 368 | + |
| 369 | +**Permission denied**: |
| 370 | + |
| 371 | +```bash |
| 372 | +# Ensure proper database credentials |
| 373 | +docker exec postgres-mina-rust psql -U postgres -l |
| 374 | +``` |
| 375 | + |
| 376 | +**Query timeout**: |
| 377 | + |
| 378 | +```sql |
| 379 | +-- Add appropriate indexes for slow queries |
| 380 | +-- Use EXPLAIN ANALYZE to understand query performance |
| 381 | +EXPLAIN ANALYZE SELECT ...; |
| 382 | +``` |
| 383 | + |
| 384 | +## Next Steps |
| 385 | + |
| 386 | +- [GraphQL API Reference](./graphql-api) - Query blockchain data via GraphQL |
| 387 | +- [Node Architecture](./architecture) - Understanding the archive system |
| 388 | +- [Running Archive Nodes](../node-operators/archive-node) - Setting up archive |
| 389 | + infrastructure |
0 commit comments