# Implement Remaining Startup Optimizations ## Problem Three critical startup optimization features remain unimplemented: 1. **Sequential block mining** - Blocks are mined sequentially, blocking service startup 2. **No auto-reset on redeployment** - Ponder doesn't detect contract redeployment, causing block mismatch errors 3. **Missing graceful degradation** - Services crash when insufficient block history exists for ringbuffer calculations ## Tasks ### 1. Parallel Block Mining **File:** `containers/bootstrap.sh` **Change:** Run `prime_chain()` in background to allow services to start while blocks are mined. **Before (lines 190-204):** ```bash main() { log "Waiting for Anvil" wait_for_rpc maybe_set_deployer_from_mnemonic run_forge_script extract_addresses fund_liquidity_manager grant_recenter_access call_recenter seed_application_state prime_chain # <-- Blocks here write_ponder_env write_txn_bot_env fund_txn_bot_wallet log "Bootstrap complete" # ... } ``` **After:** ```bash main() { log "Waiting for Anvil" wait_for_rpc maybe_set_deployer_from_mnemonic run_forge_script extract_addresses fund_liquidity_manager grant_recenter_access call_recenter seed_application_state write_ponder_env # <-- Write configs immediately write_txn_bot_env # <-- Services can start now fund_txn_bot_wallet prime_chain & # <-- Background mining local prime_pid=$! log "Bootstrap complete (mining blocks in background)" log "Kraiken: $KRAIKEN" log "Stake: $STAKE" log "LiquidityManager: $LIQUIDITY_MANAGER" wait $prime_pid # <-- Wait before exiting log "Block mining complete" } ``` --- ### 2. Auto-Reset Ponder Database on Redeployment **File:** `containers/ponder-dev-entrypoint.sh` **Add:** Schema detection and automatic database reset when `START_BLOCK` changes. **Insert after line 13 (`cd "$PONDER_WORKDIR"`):** ```bash # Load contract deployment info source "$CONTRACT_ENV" START_BLOCK=$(grep START_BLOCK "$ROOT_DIR/services/ponder/.env.local" 2>/dev/null | cut -d= -f2 || echo "") EXPECTED_SCHEMA="ponder_local_${START_BLOCK}" # Check if schema changed (contract redeployment detected) if [[ -f .env.local ]]; then CURRENT_SCHEMA=$(grep DATABASE_SCHEMA .env.local 2>/dev/null | cut -d= -f2 || echo "") if [[ -n "$CURRENT_SCHEMA" && "$CURRENT_SCHEMA" != "$EXPECTED_SCHEMA" ]]; then echo "[ponder-entrypoint] Contract redeployment detected (schema changed: $CURRENT_SCHEMA -> $EXPECTED_SCHEMA)" echo "[ponder-entrypoint] Resetting Ponder database..." export PGPASSWORD=ponder_local psql -h postgres -U ponder -d ponder_local -c \ "DROP SCHEMA IF EXISTS \"$CURRENT_SCHEMA\" CASCADE;" 2>/dev/null || true echo "[ponder-entrypoint] Old schema dropped successfully" fi fi ``` --- ### 3. Graceful Degradation for Insufficient Block History **Files:** All Ponder event handlers that reference ringbuffer data **⚠️ IMPORTANT NAMING CORRECTION:** All mentions of "VWAP" in Ponder code are **incorrect**. The data source is the **ringbuffer** in the contracts, not a traditional VWAP calculation. Update all references: - `vwapPrice` → `ringbufferPrice` or `priceFromRingbuffer` - `calculateVWAP()` → `calculateRingbufferPrice()` - Comments mentioning "VWAP" → "ringbuffer price data" **Implementation pattern:** ```typescript import { ponder } from "@/generated"; const MINIMUM_BLOCKS_FOR_RINGBUFFER = 100; ponder.on("Kraiken:Transfer", async ({ event, context }) => { const { Stats } = context.db; // ... existing transfer logic ... // Check block history before calculating ringbuffer-dependent values const currentBlock = event.block.number; const deployBlock = BigInt(context.network.contracts.Kraiken.startBlock); const blocksSinceDeployment = Number(currentBlock - deployBlock); if (blocksSinceDeployment < MINIMUM_BLOCKS_FOR_RINGBUFFER) { // Not enough history - use spot price fallback context.log.warn( `Using spot price fallback (only ${blocksSinceDeployment} blocks available, need ${MINIMUM_BLOCKS_FOR_RINGBUFFER})` ); stats.ringbufferPrice = stats.currentPrice; // Fallback to spot } else { // Normal ringbuffer price calculation stats.ringbufferPrice = await calculateRingbufferPrice(context); } await Stats.update({ id: "0x01", data: stats }); }); ``` **Apply this pattern to:** - All event handlers that read contract ringbuffer data - Any calculations depending on historical block data - GraphQL resolvers that aggregate historical events --- ## Testing Instructions ### Setup ```bash # Clean any existing state ./scripts/dev.sh stop rm -rf tmp/podman .ponder # Ensure kraiken-lib is built ./scripts/build-kraiken-lib.sh ``` ### Test 1: Parallel Block Mining **Verify services start before mining completes** ```bash # Start stack podman-compose up -d # Monitor logs in parallel podman-compose logs -f bootstrap & podman-compose logs -f ponder & # Expected behavior: # 1. Bootstrap writes configs immediately after seeding # 2. Ponder starts installing dependencies WHILE blocks are mining # 3. Bootstrap log shows "Block mining complete" after other services start # 4. Total startup time < 60 seconds ``` **Acceptance:** - [ ] Ponder starts before "Block mining complete" appears in bootstrap logs - [ ] All services healthy within 60 seconds: `podman-compose ps` --- ### Test 2: Auto-Reset on Redeployment **Verify Ponder detects and handles contract redeployment** ```bash # Initial deployment podman-compose up -d podman-compose logs ponder | grep "schema" # Note initial schema name # Wait for healthy until podman-compose exec ponder wget -q -O- http://localhost:42069/ >/dev/null 2>&1; do sleep 2; done # Query initial data curl -X POST http://localhost:42069/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ stats(id:\"0x01\"){kraikenTotalSupply}}"}' # Simulate redeployment: Stop and restart (forces new deployment) ./scripts/dev.sh stop podman volume rm harb-health_postgres-data # Clear DB but keep schema files podman-compose up -d # Check logs podman-compose logs ponder | grep -E "redeployment|schema|Resetting" # Expected output: # [ponder-entrypoint] Contract redeployment detected (schema changed: ponder_local_X -> ponder_local_Y) # [ponder-entrypoint] Resetting Ponder database... # [ponder-entrypoint] Old schema dropped successfully ``` **Acceptance:** - [ ] Log shows "Contract redeployment detected" - [ ] Log shows "Old schema dropped successfully" - [ ] Ponder starts cleanly without block number errors - [ ] GraphQL endpoint returns fresh data (no stale schema) --- ### Test 3: Graceful Degradation **Verify services don't crash with insufficient block history** ```bash # Start stack with default 2000 blocks podman-compose up -d # Monitor Ponder startup logs podman-compose logs -f ponder | grep -E "warn|error|fallback|blocks available" # Expected during early blocks (< 100): # [ponder] WARN: Using spot price fallback (only 45 blocks available, need 100) # Query GraphQL early (before 100 blocks) for i in {1..5}; do curl -s -X POST http://localhost:42069/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ stats(id:\"0x01\"){ringbufferPrice currentPrice}}"}' sleep 2 done # Expected behavior: # 1. Early queries show ringbufferPrice == currentPrice (fallback active) # 2. No crash or error responses # 3. After 100+ blocks, ringbufferPrice diverges from currentPrice (normal calculation) ``` **Acceptance:** - [ ] No service crashes during startup - [ ] Ponder logs show "Using spot price fallback" warnings - [ ] GraphQL returns valid data even with <100 blocks - [ ] After 100+ blocks, ringbuffer calculation activates automatically --- ### Test 4: Full Integration Test **End-to-end verification** ```bash # Clean start ./scripts/dev.sh stop rm -rf tmp/podman .ponder services/ponder/.env.local ./scripts/build-kraiken-lib.sh # Start and time it time podman-compose up -d # Wait for all services ./scripts/dev.sh status # Verify endpoints curl http://localhost:42069/graphql -d '{"query":"{ stats(id:\"0x01\"){kraikenTotalSupply}}"}' curl http://localhost:43069/status curl -I http://localhost:8081/ # Check Ponder schema is correct podman-compose exec ponder bash -c 'echo $DATABASE_SCHEMA' # Should output: ponder_local_ # Verify no errors in logs podman-compose logs | grep -i error ``` **Acceptance:** - [ ] Total startup time < 60 seconds - [ ] All services healthy (0 errors in logs) - [ ] GraphQL returns valid data - [ ] txnBot status endpoint responds - [ ] Landing page loads at port 8081 --- ## Naming Corrections Required **Search and replace across `services/ponder/src/`:** | Incorrect Name | Correct Name | Reason | |----------------|--------------|--------| | `vwapPrice` | `ringbufferPrice` | Data comes from contract ringbuffer, not VWAP | | `calculateVWAP()` | `calculateRingbufferPrice()` | Not a traditional VWAP calculation | | `// VWAP calculation` | `// Ringbuffer price data` | Avoid confusion with traditional VWAP | **Files to audit:** ```bash grep -r "vwap\|VWAP" services/ponder/src/ ``` Update all matches to use `ringbuffer` terminology. --- ## Acceptance Criteria Summary - [ ] `bootstrap.sh` mines blocks in background - [ ] Services start in parallel with block mining - [ ] `ponder-dev-entrypoint.sh` detects schema changes - [ ] Old Ponder schema auto-drops on redeployment - [ ] Ponder event handlers have `MINIMUM_BLOCKS_FOR_RINGBUFFER` check - [ ] Ringbuffer calculations fall back to spot price when insufficient data - [ ] All "VWAP" references renamed to "ringbuffer" - [ ] Full stack startup completes in <60 seconds - [ ] No crashes with insufficient block history - [ ] All integration tests pass ## Dependencies - `postgresql-client` already in `node-dev.Containerfile` ✅ - `podman-compose.yml` already uses `service_started` condition ✅