Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
.direnv/

# Generated by TypeScript
dist/
node_modules/
build/
dist/
.tsbuildinfo/
tsconfig.tsbuildinfo

Expand All @@ -17,3 +18,16 @@ node_modules/
scratchpad/**/*.md
scratchpad/**/*.ts
!scratchpad/index.ts

# Generated by foundry
out/
broadcast/
cache/

# Postgres data volume for testing with amp
/infra/postgres/data/
/infra/amp/data
/infra/amp/datasets
/infra/amp/providers/*.toml
/infra/amp/anvil.json
!/infra/amp/providers/anvil.toml
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "contracts/lib/solady"]
path = contracts/lib/solady
url = https://github.com/vectorized/solady
[submodule "contracts/lib/forge-std"]
path = contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
21 changes: 21 additions & 0 deletions RUNNING_AMP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Running Amp

Amp is setup to run with [docker-compose](./docker-compose.yml). It requires:

- `postgres`
- `anvil` - used as a local blockchain/rpc that amp connects to for the local dataset/contracts
- `foundry` - smart contract dev/orchestration framework. builds our contracts. ex: [`Counter.sol`](./contracts/src/Counter.sol)
- once compiled, forge ouputs the ABI into a [`Counter.json`](./contracts/out/Counter.sol/Counter.json).
- `lgtm` - metrics/traces/logs, etc. not required but very handy
- `amp-proxy` - also not required, but handy for running queries, especially in a browser

## Getting started

There is a [`justfile`](./justfile) that has recipes for installing, building and running amp

1. **Install deps** -> `just install`. installs pnpm deps as well as forge deps (for smart contract dev)
2. **Install amp** -> `just ampup`. installs amp through ampup cmd. also installs `ampctl` which is a cli tool for registering Amp datasets.
3. **Starting docker** -> `just up`. runs `docker compose up -d` to spinup the docker compose registered services listed above. With this started, amp is now running on your machine (assuming things started correctly).
4. **Deploy smart contracts** -> `just deploy`. uses forge to deploy the smart contracts such as [`Counter.sol`](./contracts/src/Counter.sol).
5. **Initialize the anvil dataset, start listening** -> `just dev-amp`. this will create an EVM-RPC dataset against the running anvil RPC source. With tabled: blocks, logs, transactions. Dataset can be built from this source.
6. **Kill** -> `just down`. spins down the docker compose services, deletes emphemeral dir.
1 change: 1 addition & 0 deletions contracts/lib/forge-std
Submodule forge-std added at f61e4d
1 change: 1 addition & 0 deletions contracts/lib/solady
Submodule solady added at 90db92
19 changes: 19 additions & 0 deletions contracts/script/DeployCounter.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {console} from "forge-std/Script.sol";
import {Script} from "./utils/Script.sol";
import {Counter} from "../src/Counter.sol";

contract DeployCounter is Script {
function run() public {
vm.startBroadcast();

bytes memory code = abi.encodePacked(type(Counter).creationCode);
address counter = deploy(keccak256("Counter"), code);

console.log("Counter deployed to:", counter);

vm.stopBroadcast();
}
}
14 changes: 14 additions & 0 deletions contracts/script/utils/Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {CREATE3} from "solady/utils/CREATE3.sol";

contract Factory {
function deploy(bytes32 salt, bytes memory creationCode) external payable returns (address deployed) {
return CREATE3.deployDeterministic(msg.value, creationCode, salt);
}

function getDeployed(bytes32 salt) external view returns (address) {
return CREATE3.predictDeterministicAddress(salt, address(this));
}
}
42 changes: 42 additions & 0 deletions contracts/script/utils/Script.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script as ForgeScript} from "forge-std/Script.sol";
import {Factory} from "./Factory.sol";

abstract contract Script is ForgeScript {
bytes32 internal constant SALT = 0;
address internal constant CREATE2 = 0x4e59b44847b379578588920cA78FbF26c0B4956C;

function getOrDeployFactory() internal returns (Factory) {
address factoryAddress = vm.computeCreate2Address(SALT, keccak256(type(Factory).creationCode), CREATE2);

if (factoryAddress.code.length == 0) {
return new Factory{salt: SALT}();
}

return Factory(factoryAddress);
}

function getFactory() internal pure returns (Factory) {
address factoryAddress = vm.computeCreate2Address(SALT, keccak256(type(Factory).creationCode), CREATE2);

return Factory(factoryAddress);
}

function deploy(bytes32 salt, bytes memory creationCode) internal returns (address) {
Factory factory = getOrDeployFactory();
address deployed = factory.getDeployed(salt);

if (deployed.code.length == 0) {
return factory.deploy(salt, creationCode);
}

return deployed;
}

function getDeployed(bytes32 salt) internal view returns (address) {
Factory factory = getFactory();
return factory.getDeployed(salt);
}
}
24 changes: 24 additions & 0 deletions contracts/src/Counter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;

contract Counter {
event Incremented(uint256 count);
event Decremented(uint256 count);

uint256 public count;

constructor() {
count = 0;
}

function increment() public {
count++;
emit Incremented(count);
}

function decrement() public {
require(count > 0, "Counter: count is zero");
count--;
emit Decremented(count);
}
}
73 changes: 73 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: amp-typescript-amp-playground
services:
postgres:
image: postgres:18-alpine
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
environment:
POSTGRES_DB_LIST: amp_typescript_playground
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
- 6435:5432
volumes:
- ./infra/postgres/postgres.conf:/etc/postgresql/postgresql.conf:ro
- ./infra/postgres/init.sh:/docker-entrypoint-initdb.d/init.sh:ro
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

anvil:
image: ghcr.io/foundry-rs/foundry
entrypoint: ["anvil", "--host", "0.0.0.0"]
ports:
- 8545:8545

lgtm:
image: grafana/otel-lgtm
ports:
- 3030:3000 # Grafana UI
- 4317:4317 # OTLP gRPC
- 4318:4318 # OTLP HTTP

# Forwards ConnectRPC Arrow Flight requests to the Amp Arrow Flight gRPC server. This
# is useful if you want to e.g. query Amp directly from the browser.
proxy:
image: ghcr.io/edgeandnode/arrow-flight-proxy:latest
depends_on:
- amp
- lgtm
restart: unless-stopped
ports:
- 8080:8080 # HTTP
environment:
PROXY_UPSTREAM: amp:1602
PROXY_UPSTREAM_INSECURE: true
PROXY_METRICS: lgtm:4317
PROXY_METRICS_INSECURE: true
PROXY_FORWARD_HEADERS: "amp-*,authorization"

# Amp is a data engineering layer for Ethereum.
# https://github.com/edgeandnode/amp
amp:
image: ghcr.io/edgeandnode/amp:latest
command: ["--config", "/var/lib/amp/config.toml", "dev"]
depends_on:
- postgres
volumes:
- ./infra/amp/config.toml:/var/lib/amp/config.toml
- ./infra/amp/providers:/var/lib/amp/providers
- ./infra/amp/datasets:/var/lib/amp/datasets
- ./infra/amp/data:/var/lib/amp/data
restart: unless-stopped
ports:
- 1610:1610 # Admin API
- 1603:1603 # JSON Lines
- 1602:1602 # Arrow Flight

volumes:
postgres_data:
14 changes: 14 additions & 0 deletions foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"contracts/lib/forge-std": {
"tag": {
"name": "v1.14.0",
"rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6"
}
},
"contracts/lib/solady": {
"tag": {
"name": "v0.1.26",
"rev": "acd959aa4bd04720d640bf4e6a5c71037510cc4b"
}
}
}
8 changes: 8 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[profile.default]
src = "contracts/src"
out = "contracts/out"
libs = ["contracts/lib"]
script = "contracts/script"
test = "contracts/test"
broadcast = "contracts/broadcast"
cache_path = "contracts/cache"
37 changes: 37 additions & 0 deletions infra/amp/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Sample of a configuration. Copy this file and edit it. Set the environment variable `AMP_CONFIG`
# to its location. See the CONFIG.md for more context.
#
# Note that using a config file is not mandatory. You can alternatively provide some or all values
# through env vars. See the 'Using env vars' section of CONFIG.md for how to do this.
#
# When using filesystem paths, any relative paths will be resolved from the directory of this file.

# Where the extracted datasets are stored.
data_dir = "data"

# Path to a providers directory. Each provider is configured as a separate toml file in this
# directory. Dataset definitions will reference providers by a relative path to this directory.
providers_dir = "providers"

# Path to a directory containing dataset definition files.
dataset_defs_dir = "datasets"

# Metadata database url.
metadata_db_url = "postgres://postgres:postgres@postgres:5432/amp_typescript_playground?sslmode=disable"

# How much memory the server can use in MB. Setting this to 0 means unlimited
max_mem_mb = 0

# Paths where DataFusion can create temporary files. Setting this to an
# empty array disables spill-to-disk
spill_location = []

# Service addresses (optional - defaults shown below)
# Arrow Flight RPC server address
# flight_addr = "0.0.0.0:1602"

# JSON Lines server address
# jsonl_addr = "0.0.0.0:1603"

# Admin API server address
# admin_api_addr = "0.0.0.0:1610"
3 changes: 3 additions & 0 deletions infra/amp/providers/anvil.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind = "evm-rpc"
url = "http://anvil:8545"
network = "anvil"
18 changes: 18 additions & 0 deletions infra/postgres/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

set -e
set -u

function create_user_and_database() {
local db=$1
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "postgres" <<-EOSQL
CREATE DATABASE $db;
GRANT ALL PRIVILEGES ON DATABASE $db TO $POSTGRES_USER;
EOSQL
}

if [ -n "${POSTGRES_DB_LIST:-}" ]; then
for db in $(echo $POSTGRES_DB_LIST | tr ',' ' '); do
create_user_and_database $db
done
fi
2 changes: 2 additions & 0 deletions infra/postgres/postgres.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
listen_addresses = '*'
wal_level = logical
49 changes: 49 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Support both docker and podman
docker := if `command -v podman >/dev/null 2>&1; echo $?` == "0" { "podman" } else { "docker" }

# Display available commands and their descriptions (default target)
default:
@just --list

# Install dependencies
install:
pnpm install
forge build

# Install amp
ampup:
curl --proto '=https' --tlsv1.2 -sSf https://ampup.sh/install | sh

# Start service dependencies
up *args:
@mkdir -p ./infra/postgres/data
@mkdir -p ./infra/amp/data
@mkdir -p ./infra/amp/datasets
{{docker}} compose up -d --wait {{args}}
just deploy

# Tail logs for service dependencies
logs *args:
{{docker}} compose logs -f --tail 100 {{args}}

# Stop service dependencies
stop *args:
{{docker}} compose stop {{args}}

# Stop all services and remove volumes
down:
{{docker}} compose down --volumes
@rm -rf ./infra/postgres/data
@rm -rf ./infra/amp/data
@rm -rf ./infra/amp/datasets

# Deploy the contract
[working-directory: "contracts"]
deploy:
forge script script/DeployCounter.s.sol --broadcast --rpc-url http://localhost:8545 --private-key "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

# Deploy the dataset and watch for config changes
dev-amp:
ampctl manifest generate --network anvil --kind evm-rpc --out ./infra/amp/anvil.json
ampctl dataset register _/anvil -t 0.0.1 ./infra/amp/anvil.json
ampctl dataset deploy _/anvil@dev