Skip to content

Commit d2b94a6

Browse files
committed
Battleship
1 parent 852eafc commit d2b94a6

1 file changed

Lines changed: 270 additions & 0 deletions

File tree

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
---
2+
title: How to Build and Run a Battleship App with Amp
3+
description: tep-by-step guide to deploy and query a live blockchain app using Amp.
4+
slug: build-battleship-with-amp
5+
category: how-to-guide
6+
---
7+
8+
This guide shows how to build and run a live blockchain application using Amp. You'll deploy a fully functional [Battleship game](https://github.com/edgeandnode/battleship?tab=readme-ov-file), and learn how Amp indexes smart contract events and serves them as queryable data without manual event listeners or indexing code required.
9+
10+
By the end, you’ll know how to:
11+
12+
- Configure Amp to extract and store contract events
13+
- Query those events with SQL
14+
- Run the system locally for development and testing
15+
16+
> Tip: The Battleship example is actively maintained to showcase the latest Amp features. Star the repo to track updates.
17+
18+
## Part 1. Concept: The Problem Amp Solves
19+
20+
Building blockchain apps means handling event data. Every contract every contract emits logs that must be parsed, stored, and queried.
21+
22+
Traditionally, you have to:
23+
24+
- Write listeners for each event
25+
- Parse logs manually (ABIs, hex decoding, conversions)
26+
- Maintain schemas, databases, and indexing infrastructure
27+
- Handle reorgs, rate limits, and failures
28+
29+
This creates heavy, repetitive infrastructure work.
30+
31+
### Amp’s Solution
32+
33+
Amp replaces all of this with a configuration-driven model:
34+
35+
- Define a dataset once with your contract ABI
36+
- Amp automatically extracts, decodes, and stores events
37+
- Query them directly using SQL
38+
39+
Your app becomes query-driven, not event-driven.
40+
41+
## Part 2. Build: Configure Amp Infrastructure
42+
43+
Follow these steps to configure Amp for the Battleship game.
44+
45+
### Step 1. Define Your Dataset (amp.config.ts)
46+
47+
Tells Amp which contract events to index.
48+
49+
```ts
50+
import { defineDataset, eventTables } from "@edgeandnode/amp";
51+
import { abi } from "./app/src/lib/abi.ts";
52+
53+
export default defineDataset(() => ({
54+
name: "battleship",
55+
version: "0.1.0",
56+
network: "anvil",
57+
dependencies: {
58+
anvil: { owner: "graphprotocol", name: "anvil", version: "0.1.0" },
59+
},
60+
tables: eventTables(abi),
61+
}));
62+
```
63+
64+
Amp automatically:
65+
66+
- Creates a table for each event in the ABI
67+
- Adds metadata (block number, timestamp, tx hash)
68+
- Makes events queryable via SQL tables
69+
70+
Example query:
71+
72+
```sql
73+
SELECT * FROM battleship.shot_fired WHERE game_id = 123;
74+
```
75+
76+
> **Key insight**: You never write event listeners or database logic—Amp generates schema and indexing automatically.
77+
78+
### Step 2: Configure Core Infrastructure (`infra/amp/config.toml`)
79+
80+
Controls where Amp stores and tracks data.
81+
82+
```toml
83+
data_dir = "data"
84+
providers_dir = "providers"
85+
dataset_defs_dir = "datasets"
86+
metadata_db_url = "postgres://postgres:postgres@postgres:5432/amp?sslmode=disable"
87+
```
88+
89+
Amp separates:
90+
91+
- Parquet files store raw event data
92+
- PostgreSQL metadata DB tracks indexing progress
93+
94+
This allows automatic crash recovery and scalable storage.
95+
96+
**Why Parquet?**
97+
98+
- Compressed and efficient for analytics
99+
- Supports fast column-based queries
100+
- Enables skipping irrelevant files for faster filtering
101+
102+
### Step 3. Define the Blockchain Provider (`infra/amp/providers/anvil.toml`)
103+
104+
Specifies the blockchain data source.
105+
106+
```toml
107+
kind = "evm-rpc"
108+
url = "http://anvil:8545"
109+
network = "anvil"
110+
```
111+
112+
Providers make datasets portable. Use this for local testing, and switch to a production RPC by creating a `mainnet.toml`.
113+
114+
### Step 4. Run Amp Locally (`docker-compose.yaml`)
115+
116+
Start the full Amp stack in development.
117+
118+
```yaml
119+
amp:
120+
image: ghcr.io/edgeandnode/amp:latest
121+
command: ["--config", "/var/lib/amp/config.toml", "dev"]
122+
depends_on: [postgres]
123+
ports:
124+
- 1610:1610 # Admin API
125+
- 1603:1603 # JSON Lines
126+
- 1602:1602 # Arrow Flight
127+
```
128+
129+
In dev mode, Amp runs:
130+
131+
- Controller (schedules jobs)
132+
- Worker (extracts events)
133+
- Query server (serves SQL queries)
134+
135+
> **Scaling Tip**: In production, run these separately to scale horizontally.
136+
137+
## Part 3. Integrate: Use Amp in the Application Layer
138+
139+
### Step 5. Define SQL Queries `queries.ts`
140+
141+
Use SQL to join and aggregate event data instead of listeners:
142+
143+
```ts
144+
const gamesListQuery = `
145+
SELECT gc.*, gs.*, ge.*
146+
FROM battleship.game_created gc
147+
LEFT JOIN battleship.game_started gs ON gc.game_id = gs.game_id
148+
LEFT JOIN battleship.game_ended ge ON gc.game_id = ge.game_id
149+
ORDER BY gs.block_num DESC
150+
```
151+
152+
Amp texposes all events as relational tables, making it easy to join and filter data directly.
153+
154+
> **ELT advantage**: Data is extracted and loaded once. Transformations happen at query time. You can instantly add new derived views without re-indexing.
155+
156+
### Step 6. Connect to Amp (`runtime.ts` )
157+
158+
Establish Arrow Flight connection for high-speed binary queries.
159+
160+
```ts
161+
import { createConnectTransport } from "@connectrpc/connect-web";
162+
import { ArrowFlight } from "@edgeandnode/amp";
163+
import { Atom } from "@effect-atom/atom-react";
164+
165+
const transport = createConnectTransport({ baseUrl: "/amp" });
166+
export const runtime = Atom.runtime(ArrowFlight.layer(transport));
167+
```
168+
169+
**Why Arrow Flight?**
170+
171+
- Binary columnar format (faster than JSON)
172+
- BigInt-safe for EVM values
173+
- Streams results efficiently
174+
175+
### Step 7: Create Reactive Queries with Atoms
176+
177+
Atoms make SQL queries reactive:
178+
179+
```ts
180+
export const gamesListAtom = runtime
181+
.atom(queryGamesList())
182+
.pipe(Atom.withReactivity(["gamesList"]));
183+
```
184+
185+
When Amp indexes new events, atoms update automatically—React components re-render in real time.
186+
187+
**Components**
188+
189+
- `GameList.tsx` subscribes to `gamesListAtom` to render all active games.
190+
- `GameBoard.tsx` combines multiple reactive atoms (`gameDetailsAtom`, `shotsFiredAtom`, etc.) to display live gameplay.
191+
192+
> **Flow**: Blockchain --> Amp --> Atom → React --> Live UI.
193+
194+
## Part 4. Operate: Run and Verify Locally
195+
196+
### Step 8. Run Everything with `just`
197+
198+
Use a single command:
199+
200+
```bash
201+
just dev
202+
```
203+
204+
Starts:
205+
206+
- Frontend (Vite)
207+
- Connect proxy (HTTP -> gRPC)
208+
- Amp in dev mode
209+
210+
Other Commands:
211+
212+
- `just up` to start infra
213+
- `just deploy` to deploy dataset
214+
- `just logs` to view logs
215+
216+
### Step 9. Configure Frontend Proxy (vite.config.ts)
217+
218+
Routes frontend requests to Amp and Anvil:
219+
220+
```ts
221+
proxy: {
222+
"/rpc": { target: "http://localhost:8545" },
223+
"/amp": { target: "http://localhost:8080" },
224+
}
225+
```
226+
227+
> Browsers can’t use gRPC directly, so Vite proxies through Connect RPC before reaching Amp’s query server.
228+
229+
## Part 5. Verify and Extend
230+
231+
### Check Indexing Progress
232+
233+
```bash
234+
docker logs battleship-amp-1
235+
```
236+
237+
**Query Directly**
238+
239+
```bash
240+
pnpm amp query 'SELECT * FROM battleship.game_created LIMIT 5'
241+
```
242+
243+
### Add New Events
244+
245+
1. Add event to your contract
246+
2. Redeploy it
247+
3. Update the ABI in `amp.config.ts`
248+
4. Restart Amp
249+
250+
New event tables appear automatically.
251+
252+
## Part 6. Summary
253+
254+
| Concept | Purpose |
255+
| -------------------- | ------------------------------------------ |
256+
| **Amp** | Converts blockchain events into SQL tables |
257+
| **eventTables(abi)** | Generates schema from contract ABI |
258+
| **Arrow Flight** | High-speed query protocol |
259+
| **Atoms** | Reactive data streams in React |
260+
| **just dev** | Unified local dev command |
261+
262+
## Part 7. Next Steps
263+
264+
To adapt the Battleship template:
265+
266+
1. Replace the ABI with your contract’s ABI.
267+
2. Update the provider configuration for your network.
268+
3. Write new SQL queries.
269+
4. Build reactive UI components with atoms.
270+
5. See `docs/modes.md` for scaling Amp in production.

0 commit comments

Comments
 (0)