resolves #34 Co-authored-by: johba <johba@harb.eth> Reviewed-on: https://codeberg.org/johba/harb/pulls/48
322 lines
9.7 KiB
Text
322 lines
9.7 KiB
Text
# 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_<START_BLOCK>
|
|
|
|
# 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 ✅
|