diff --git a/.changeset/metal-views-start.md b/.changeset/metal-views-start.md
new file mode 100644
index 0000000000..be23169a02
--- /dev/null
+++ b/.changeset/metal-views-start.md
@@ -0,0 +1,5 @@
+---
+"@ensnode/ensnode-sdk": minor
+---
+
+Renamed the `databaseSchemaName` field on `EnsIndexerPublicConfig` type to `ensIndexerSchemaName`.
diff --git a/.changeset/slick-kings-travel.md b/.changeset/slick-kings-travel.md
new file mode 100644
index 0000000000..19dc8699b3
--- /dev/null
+++ b/.changeset/slick-kings-travel.md
@@ -0,0 +1,5 @@
+---
+"ensapi": minor
+---
+
+Renamed environment variable: `DATABASE_URL` to `ENSDB_URL`.
diff --git a/.changeset/slow-readers-pay.md b/.changeset/slow-readers-pay.md
new file mode 100644
index 0000000000..16f769ad49
--- /dev/null
+++ b/.changeset/slow-readers-pay.md
@@ -0,0 +1,5 @@
+---
+"ensadmin": minor
+---
+
+Updated the Connection view to reference "ENSIndexer Schema Name".
diff --git a/.changeset/wide-trams-rule.md b/.changeset/wide-trams-rule.md
new file mode 100644
index 0000000000..f3a90b17a8
--- /dev/null
+++ b/.changeset/wide-trams-rule.md
@@ -0,0 +1,5 @@
+---
+"ensindexer": minor
+---
+
+Renamed environment variables: `DATABASE_URL` to `ENSDB_URL`, and `DATABASE_SCHEMA` to `ENSINDEXER_SCHEMA_NAME`.
diff --git a/.github/workflows/deploy_ensnode_blue_green.yml b/.github/workflows/deploy_ensnode_blue_green.yml
index a437c467dd..1a76900671 100644
--- a/.github/workflows/deploy_ensnode_blue_green.yml
+++ b/.github/workflows/deploy_ensnode_blue_green.yml
@@ -158,7 +158,7 @@ jobs:
#ENSADMIN
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ENSADMIN_SVC_ID} ${{ env.ENSADMIN_DOCKER_IMAGE }}
- # Update DATABASE_SCHEMA for each indexer based on input tag
+ # Update ENSINDEXER_SCHEMA_NAME for each indexer based on input tag
- name: Update shared environment variable
run: |
set_shared_variable() {
@@ -182,6 +182,12 @@ jobs:
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "V2-SEPOLIA_DATABASE_SCHEMA" "v2SepoliaSchema${TAG}"
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "SEPOLIA_DATABASE_SCHEMA" "sepoliaSchema${TAG}"
+ set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "ALPHA_ENSINDEXER_SCHEMA_NAME" "alphaSchema${TAG}"
+ set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "MAINNET_ENSINDEXER_SCHEMA_NAME" "mainnetSchema${TAG}"
+ set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "ALPHA-SEPOLIA_ENSINDEXER_SCHEMA_NAME" "alphaSepoliaSchema${TAG}"
+ set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "V2-SEPOLIA_ENSINDEXER_SCHEMA_NAME" "v2SepoliaSchema${TAG}"
+ set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "SEPOLIA_ENSINDEXER_SCHEMA_NAME" "sepoliaSchema${TAG}"
+
- name: Redeploy ENSNode instances
run: |
redeploy_service() {
diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml
index f14f510614..cfb1dd66fd 100644
--- a/.github/workflows/test_ci.yml
+++ b/.github/workflows/test_ci.yml
@@ -87,7 +87,7 @@ jobs:
fi
echo "OpenAPI spec is in sync with codebase"
- name: Validate OpenAPI spec with Mintlify
- run: pnpm dlx mint@^4.1.0 openapi-check docs/docs.ensnode.io/ensapi-openapi.json
+ run: pnpm dlx --allow-build=keytar mint@^4.1.0 openapi-check docs/docs.ensnode.io/ensapi-openapi.json
graphql-schema-check:
name: "GraphQL Schema Check"
@@ -154,8 +154,8 @@ jobs:
# Public RPC URLs are used as fallbacks for repository forks
# that don't have the relevant secrets configured.
NAMESPACE: mainnet
- DATABASE_URL: postgresql://postgres:password@localhost:5432/postgres
- DATABASE_SCHEMA: public
+ ENSDB_URL: postgresql://postgres:password@localhost:5432/postgres
+ ENSINDEXER_SCHEMA_NAME: ensindexer_test_ci
PLUGINS: subgraph,basenames,lineanames,threedns,protocol-acceleration,registrars,tokenscope
ENSRAINBOW_URL: https://api.ensrainbow.io
ALCHEMY_API_KEY: ${{ secrets.ALCHEMY_API_KEY }}
diff --git a/apps/ensadmin/src/app/mock/config-api.mock.ts b/apps/ensadmin/src/app/mock/config-api.mock.ts
index 71158f69ce..734059e0f9 100644
--- a/apps/ensadmin/src/app/mock/config-api.mock.ts
+++ b/apps/ensadmin/src/app/mock/config-api.mock.ts
@@ -6,7 +6,7 @@ export const ensIndexerPublicConfig = deserializeENSIndexerPublicConfig({
labelSetVersion: 0,
},
indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567],
- databaseSchemaName: "alphaSchema0.34.0",
+ ensIndexerSchemaName: "alphaSchema0.34.0",
ensRainbowPublicConfig: {
version: "0.34.0",
labelSet: {
diff --git a/apps/ensadmin/src/app/mock/config-info/data.json b/apps/ensadmin/src/app/mock/config-info/data.json
index fd9319ecba..43de682f44 100644
--- a/apps/ensadmin/src/app/mock/config-info/data.json
+++ b/apps/ensadmin/src/app/mock/config-info/data.json
@@ -11,7 +11,7 @@
"labelSetVersion": 0
},
"indexedChainIds": [1, 8453, 59144, 10, 42161, 534352, 567],
- "databaseSchemaName": "alphaSchema0.34.0",
+ "ensIndexerSchemaName": "alphaSchema0.34.0",
"ensRainbowPublicConfig": {
"version": "0.34.0",
"labelSet": {
@@ -68,7 +68,7 @@
"protocol-acceleration",
"registrars"
],
- "databaseSchemaName": "alphaSepoliaSchema0.34.0",
+ "ensIndexerSchemaName": "alphaSepoliaSchema0.34.0",
"ensRainbowPublicConfig": {
"version": "0.34.0",
"labelSet": {
@@ -101,7 +101,7 @@
"indexedChainIds": [1],
"namespace": "mainnet",
"plugins": ["subgraph"],
- "databaseSchemaName": "mainnetSchema0.34.0",
+ "ensIndexerSchemaName": "mainnetSchema0.34.0",
"ensRainbowPublicConfig": {
"version": "0.34.0",
"labelSet": {
@@ -134,7 +134,7 @@
"indexedChainIds": [11155111],
"namespace": "sepolia",
"plugins": ["subgraph"],
- "databaseSchemaName": "sepoliaSchema0.34.0",
+ "ensIndexerSchemaName": "sepoliaSchema0.34.0",
"ensRainbowPublicConfig": {
"version": "0.34.0",
"labelSet": {
@@ -167,7 +167,7 @@
"indexedChainIds": [11155111],
"namespace": "sepolia",
"plugins": ["subgraph"],
- "databaseSchemaName": "DeserializationSchema0.34.0",
+ "ensIndexerSchemaName": "DeserializationSchema0.34.0",
"ensRainbowPublicConfig": {
"version": "",
"labelSet": {
diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
index 1e80f88ae1..22f6e23c39 100644
--- a/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
+++ b/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
@@ -297,14 +297,13 @@ function ENSNodeConfigCardContent({
docsLink={new URL("https://ensnode.io/ensapi")}
>
- Postgres
} />
{ensIndexerPublicConfig.databaseSchemaName}
+ {ensIndexerPublicConfig.ensIndexerSchemaName}
}
additionalInfo={
- ENSApi reads indexed data from tables within this Postgres database schema.
+ ENSApi reads indexed data from tables within this ENSIndexer Schema in ENSDb.
}
/>
Postgres} />
{ensIndexerPublicConfig.databaseSchemaName}
+ {ensIndexerPublicConfig.ensIndexerSchemaName}
+ }
+ additionalInfo={
+
+ ENSDb enables devs to build custom services and APIs on top of indexed ENS data in
+ this schema using{" "}
+
+ ensdb-sdk
+
+ .
+
+ }
+ />
+ ensnode}
+ additionalInfo={
+ This database schema stores Metadata about each ENSIndexer schema in ENSDb.
}
+ />
+
+ ponder_sync}
additionalInfo={
- ENSIndexer writes indexed data to tables within this Postgres database schema.
+
+ Ponder manages this database schema to store cached RPC results and is shared across
+ all ENSIndexer instances using this ENSDb.
+
}
/>
@@ -427,14 +451,16 @@ function ENSNodeConfigCardContent({
docsLink={new URL("https://ensnode.io/ensindexer")}
>
- Postgres} />
{ensIndexerPublicConfig.databaseSchemaName}
+ {ensIndexerPublicConfig.ensIndexerSchemaName}
}
additionalInfo={
- ENSIndexer writes indexed data to tables within this Postgres database schema.
+
+ ENSIndexer is the exclusive writer of indexed data to tables within this ENSIndexer
+ Schema in ENSDb.
+
}
/>
:@:/`
#
# See https://ensnode.io/ensindexer/usage/configuration for additional information.
-DATABASE_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database
+ENSDB_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database
# ENSDb: ENSIndexer Schema Name
-# Required. This is a name of the database schema in DATABASE_URL where ENSApi should read indexed data stored by your ENSIndexer.
-# It should match the DATABASE_SCHEMA used by your ENSIndexer.
+# Required. This is the name of the ENSIndexer Schema in ENSDb where ENSApi should read indexed data stored by your ENSIndexer.
+# It should match the ENSINDEXER_SCHEMA_NAME used by your ENSIndexer.
ENSINDEXER_SCHEMA_NAME=ensindexer_0
# ENSApi: RPC Configuration
diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts
index 75b060e68f..01fee8abaf 100644
--- a/apps/ensapi/src/config/config.schema.test.ts
+++ b/apps/ensapi/src/config/config.schema.test.ts
@@ -27,13 +27,13 @@ vi.mock("@/lib/logger", () => ({
const VALID_RPC_URL = "https://eth-sepolia.g.alchemy.com/v2/1234";
const BASE_ENV = {
- DATABASE_URL: "postgresql://user:password@localhost:5432/mydb",
+ ENSDB_URL: "postgresql://user:password@localhost:5432/mydb",
RPC_URL_1: VALID_RPC_URL,
} satisfies EnsApiEnvironment;
const ENSINDEXER_PUBLIC_CONFIG = {
namespace: "mainnet",
- databaseSchemaName: "ensapi",
+ ensIndexerSchemaName: "ensindexer_0",
ensRainbowPublicConfig: {
version: packageJson.version,
labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
@@ -55,12 +55,12 @@ describe("buildConfigFromEnvironment", () => {
it("returns a valid config object using environment variables", async () => {
await expect(buildConfigFromEnvironment(BASE_ENV)).resolves.toStrictEqual({
port: ENSApi_DEFAULT_PORT,
- databaseUrl: BASE_ENV.DATABASE_URL,
+ ensDbUrl: BASE_ENV.ENSDB_URL,
theGraphApiKey: undefined,
ensIndexerPublicConfig: ENSINDEXER_PUBLIC_CONFIG,
namespace: ENSINDEXER_PUBLIC_CONFIG.namespace,
- ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.databaseSchemaName,
+ ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName,
rpcConfigs: new Map([
[
1,
@@ -98,7 +98,7 @@ describe("buildConfigFromEnvironment", () => {
});
const TEST_ENV: EnsApiEnvironment = {
- DATABASE_URL: BASE_ENV.DATABASE_URL,
+ ENSDB_URL: BASE_ENV.ENSDB_URL,
};
it("logs error and exits when CUSTOM_REFERRAL_PROGRAM_EDITIONS is not a valid URL", async () => {
@@ -149,10 +149,10 @@ describe("buildEnsApiPublicConfig", () => {
it("returns a valid ENSApi public config with correct structure", () => {
const mockConfig = {
port: ENSApi_DEFAULT_PORT,
- databaseUrl: BASE_ENV.DATABASE_URL,
+ ensDbUrl: BASE_ENV.ENSDB_URL,
ensIndexerPublicConfig: ENSINDEXER_PUBLIC_CONFIG,
namespace: ENSINDEXER_PUBLIC_CONFIG.namespace,
- ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.databaseSchemaName,
+ ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName,
rpcConfigs: new Map([
[
1,
@@ -180,10 +180,10 @@ describe("buildEnsApiPublicConfig", () => {
it("preserves the complete ENSIndexer public config structure", () => {
const mockConfig = {
port: ENSApi_DEFAULT_PORT,
- databaseUrl: BASE_ENV.DATABASE_URL,
+ ensDbUrl: BASE_ENV.ENSDB_URL,
ensIndexerPublicConfig: ENSINDEXER_PUBLIC_CONFIG,
namespace: ENSINDEXER_PUBLIC_CONFIG.namespace,
- ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.databaseSchemaName,
+ ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName,
rpcConfigs: new Map(),
customReferralProgramEditionConfigSetUrl: undefined,
};
@@ -201,22 +201,22 @@ describe("buildEnsApiPublicConfig", () => {
ENSINDEXER_PUBLIC_CONFIG.isSubgraphCompatible,
);
expect(result.ensIndexerPublicConfig.labelSet).toEqual(ENSINDEXER_PUBLIC_CONFIG.labelSet);
- expect(result.ensIndexerPublicConfig.databaseSchemaName).toBe(
- ENSINDEXER_PUBLIC_CONFIG.databaseSchemaName,
+ expect(result.ensIndexerPublicConfig.ensIndexerSchemaName).toBe(
+ ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName,
);
});
it("includes the theGraphFallback and redacts api key", () => {
const mockConfig = {
port: ENSApi_DEFAULT_PORT,
- databaseUrl: BASE_ENV.DATABASE_URL,
+ ensDbUrl: BASE_ENV.ENSDB_URL,
ensIndexerPublicConfig: {
...ENSINDEXER_PUBLIC_CONFIG,
plugins: ["subgraph"],
isSubgraphCompatible: true,
},
namespace: ENSINDEXER_PUBLIC_CONFIG.namespace,
- ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.databaseSchemaName,
+ ensIndexerSchemaName: ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName,
rpcConfigs: new Map(),
customReferralProgramEditionConfigSetUrl: undefined,
theGraphApiKey: "secret-api-key",
diff --git a/apps/ensapi/src/config/config.schema.ts b/apps/ensapi/src/config/config.schema.ts
index 28a654d182..1fdbe732fb 100644
--- a/apps/ensapi/src/config/config.schema.ts
+++ b/apps/ensapi/src/config/config.schema.ts
@@ -89,11 +89,11 @@ export async function buildConfigFromEnvironment(env: EnsApiEnvironment): Promis
return EnsApiConfigSchema.parse({
port: env.PORT,
- databaseUrl: env.DATABASE_URL,
+ ensDbUrl: env.ENSDB_URL,
theGraphApiKey: env.THEGRAPH_API_KEY,
ensIndexerPublicConfig,
namespace: ensIndexerPublicConfig.namespace,
- ensIndexerSchemaName: ensIndexerPublicConfig.databaseSchemaName,
+ ensIndexerSchemaName: ensIndexerPublicConfig.ensIndexerSchemaName,
rpcConfigs,
customReferralProgramEditionConfigSetUrl: env.CUSTOM_REFERRAL_PROGRAM_EDITIONS,
});
diff --git a/apps/ensapi/src/config/config.singleton.test.ts b/apps/ensapi/src/config/config.singleton.test.ts
index 8e5584a5cb..3e05ce71eb 100644
--- a/apps/ensapi/src/config/config.singleton.test.ts
+++ b/apps/ensapi/src/config/config.singleton.test.ts
@@ -7,14 +7,14 @@ vi.mock("@/lib/logger", () => ({
},
}));
-const VALID_DB_URL = "postgresql://user:password@localhost:5432/mydb";
-const VALID_SCHEMA_NAME = "ensapi";
+const VALID_ENSDB_URL = "postgresql://user:password@localhost:5432/mydb";
+const VALID_ENSINDEXER_SCHEMA_NAME = "ensindexer_test";
describe("ensdb singleton bootstrap", () => {
beforeEach(() => {
vi.resetModules();
- vi.stubEnv("DATABASE_URL", VALID_DB_URL);
- vi.stubEnv("ENSINDEXER_SCHEMA_NAME", VALID_SCHEMA_NAME);
+ vi.stubEnv("ENSDB_URL", VALID_ENSDB_URL);
+ vi.stubEnv("ENSINDEXER_SCHEMA_NAME", VALID_ENSINDEXER_SCHEMA_NAME);
});
afterEach(() => {
@@ -26,18 +26,18 @@ describe("ensdb singleton bootstrap", () => {
// ensDbClient is a lazyProxy — construction is deferred until first property access.
// Accessing a property triggers EnsDbReader construction; verify it succeeds.
- expect(ensDbClient.ensIndexerSchemaName).toBe(VALID_SCHEMA_NAME);
+ expect(ensDbClient.ensIndexerSchemaName).toBe(VALID_ENSINDEXER_SCHEMA_NAME);
expect(ensDb).toBeDefined();
expect(ensIndexerSchema).toBeDefined();
}, 10_000);
- it("exits when DATABASE_URL is missing", async () => {
+ it("exits when ENSDB_URL is missing", async () => {
const mockExit = vi.spyOn(process, "exit").mockImplementation((() => {
throw new Error("process.exit");
}) as never);
const { default: logger } = await import("@/lib/logger");
- vi.stubEnv("DATABASE_URL", "");
+ vi.stubEnv("ENSDB_URL", "");
// ensDbClient is a lazyProxy — import succeeds but first property access triggers construction,
// which calls buildEnsDbConfigFromEnvironment and exits on invalid config.
const { ensDbClient } = await import("@/lib/ensdb/singleton");
diff --git a/apps/ensapi/src/config/ensdb-config.schema.ts b/apps/ensapi/src/config/ensdb-config.schema.ts
index eabf2b0fc0..8dbfdcc854 100644
--- a/apps/ensapi/src/config/ensdb-config.schema.ts
+++ b/apps/ensapi/src/config/ensdb-config.schema.ts
@@ -4,7 +4,7 @@ import { prettifyError, z } from "zod/v4";
import type { EnsApiEnvironment } from "@/config/environment";
import logger from "@/lib/logger";
-export const DatabaseUrlSchema = z.string().refine(
+export const EnsDbUrlSchema = z.string().refine(
(url) => {
try {
if (!url.startsWith("postgresql://") && !url.startsWith("postgres://")) {
@@ -18,7 +18,7 @@ export const DatabaseUrlSchema = z.string().refine(
},
{
error:
- "Invalid PostgreSQL connection string. Expected format: postgresql://username:password@host:port/database",
+ "Invalid PostgreSQL connection string for ENSDb. Expected format: postgresql://username:password@host:port/database",
},
);
@@ -32,7 +32,7 @@ const EnsIndexerSchemaNameSchema = z
});
export const EnsDbConfigSchema = z.object({
- databaseUrl: DatabaseUrlSchema,
+ ensDbUrl: EnsDbUrlSchema,
ensIndexerSchemaName: EnsIndexerSchemaNameSchema,
});
@@ -45,7 +45,7 @@ export type EnsDbConfig = z.infer;
*/
export function buildEnsDbConfigFromEnvironment(env: EnsApiEnvironment): EnsDbConfig {
const ensDbConfig = EnsDbConfigSchema.safeParse({
- databaseUrl: env.DATABASE_URL,
+ ensDbUrl: env.ENSDB_URL,
ensIndexerSchemaName: env.ENSINDEXER_SCHEMA_NAME,
});
diff --git a/apps/ensapi/src/config/environment.ts b/apps/ensapi/src/config/environment.ts
index 305f671b4d..1b191a73c6 100644
--- a/apps/ensapi/src/config/environment.ts
+++ b/apps/ensapi/src/config/environment.ts
@@ -1,5 +1,5 @@
import type {
- EnsApiDatabaseEnvironment,
+ EnsDbEnvironment,
LogLevelEnvironment,
PortEnvironment,
ReferralProgramEditionsEnvironment,
@@ -14,7 +14,7 @@ import type {
* their state in `process.env`. This interface is intended to be the source type which then gets
* mapped/parsed into a structured configuration object like `EnsApiConfig`.
*/
-export type EnsApiEnvironment = EnsApiDatabaseEnvironment &
+export type EnsApiEnvironment = EnsDbEnvironment &
RpcEnvironment &
PortEnvironment &
LogLevelEnvironment &
diff --git a/apps/ensapi/src/config/redact.ts b/apps/ensapi/src/config/redact.ts
index c26730cacc..8676218072 100644
--- a/apps/ensapi/src/config/redact.ts
+++ b/apps/ensapi/src/config/redact.ts
@@ -7,8 +7,13 @@ import type { EnsApiConfig } from "@/config/config.schema";
*/
export function redactEnsApiConfig(config: EnsApiConfig) {
return {
- ...config,
- databaseUrl: redactString(config.databaseUrl),
+ port: config.port,
+ namespace: config.namespace,
+ customReferralProgramEditionConfigSetUrl: config.customReferralProgramEditionConfigSetUrl,
+ ensIndexerPublicConfig: config.ensIndexerPublicConfig,
+ ensDbUrl: redactString(config.ensDbUrl),
rpcConfigs: redactRpcConfigs(config.rpcConfigs),
+ ensIndexerSchemaName: config.ensIndexerSchemaName,
+ theGraphApiKey: config.theGraphApiKey ? redactString(config.theGraphApiKey) : undefined,
};
}
diff --git a/apps/ensapi/src/handlers/subgraph/subgraph-api.ts b/apps/ensapi/src/handlers/subgraph/subgraph-api.ts
index 258537df23..2a83909601 100644
--- a/apps/ensapi/src/handlers/subgraph/subgraph-api.ts
+++ b/apps/ensapi/src/handlers/subgraph/subgraph-api.ts
@@ -59,7 +59,7 @@ app.use(subgraphMetaMiddleware);
// imported without env vars being present (e.g. during OpenAPI generation).
const getSubgraphMiddleware = lazy(() =>
subgraphGraphQLMiddleware({
- databaseUrl: config.databaseUrl,
+ databaseUrl: config.ensDbUrl,
databaseSchema: config.ensIndexerSchemaName,
schema: subgraphSchema,
// describes the polymorphic (interface) relationships in the schema
diff --git a/apps/ensapi/src/lib/ensdb/singleton.ts b/apps/ensapi/src/lib/ensdb/singleton.ts
index b2d4ee481b..0e392fd53a 100644
--- a/apps/ensapi/src/lib/ensdb/singleton.ts
+++ b/apps/ensapi/src/lib/ensdb/singleton.ts
@@ -10,8 +10,8 @@ import { lazyProxy } from "@/lib/lazy";
* Singleton instance of ENSDbReader for the ENSApi application.
*/
export const ensDbClient = lazyProxy(() => {
- const { databaseUrl, ensIndexerSchemaName } = buildEnsDbConfigFromEnvironment(process.env);
- return new EnsDbReader(databaseUrl, ensIndexerSchemaName);
+ const { ensDbUrl, ensIndexerSchemaName } = buildEnsDbConfigFromEnvironment(process.env);
+ return new EnsDbReader(ensDbUrl, ensIndexerSchemaName);
});
/**
diff --git a/apps/ensapi/src/lib/handlers/drizzle.ts b/apps/ensapi/src/lib/handlers/drizzle.ts
deleted file mode 100644
index a5d8f36daf..0000000000
--- a/apps/ensapi/src/lib/handlers/drizzle.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { setDatabaseSchema } from "@ponder/client";
-import { drizzle } from "drizzle-orm/node-postgres";
-
-import { makeLogger } from "@/lib/logger";
-
-type Schema = { [name: string]: unknown };
-
-const logger = makeLogger("drizzle");
-
-/**
- * Makes a Drizzle DB object.
- */
-export const makeDrizzle = ({
- schema,
- databaseUrl,
- databaseSchema,
-}: {
- schema: SCHEMA;
- databaseUrl: string;
- databaseSchema: string;
-}) => {
- // monkeypatch schema onto tables
- setDatabaseSchema(schema, databaseSchema);
-
- return drizzle(databaseUrl, {
- schema,
- casing: "snake_case",
- logger: {
- logQuery: (query, params) => logger.trace({ params }, query),
- },
- });
-};
diff --git a/apps/ensindexer/.env.local.example b/apps/ensindexer/.env.local.example
index 73e819b9ba..cd5b3d948d 100644
--- a/apps/ensindexer/.env.local.example
+++ b/apps/ensindexer/.env.local.example
@@ -166,27 +166,49 @@
# - required if the configured namespace is ens-test-env
# RPC_URL_1337=
-# Database configuration
-# Required. This is a namespace for the tables that the indexer will create to store indexed data.
-# It should be a string that is unique to the running indexer instance.
+# ENSDb config: ENSIndexer Schema Name
+# Required. This is the name of the ENSIndexer Schema in ENSDb where ENSIndexer will create tables to store indexed data.
+# Each ENSIndexer instance is the exclusive writer to its ENSIndexer Schema within an ENSDb.
+# Therefore, this must be a unique ENSIndexer Schema Name for all ENSIndexer instances writing to the same ENSDb.
+# Multiple ENSIndexer instances can write to the same ENSDb, but each requires a distinct ENSIndexer Schema Name.
#
-# Keeping the database schema unique to the indexer instance is important to
-# 1) speed up indexing after a restart
-# 2) prevent data corruption from multiple indexer app instances writing state
-# concurrently to the same db schema
+# ENSIndexer can run in production mode (i.e. with `pnpm -F ensindexer start` command).
+# In production mode, the following rules apply:
+# - For safety, any changes to the indexing behavior in ENSIndexer (including
+# any changes to indexing code or any changes to environment variables that
+# influence indexing behavior) will cause ENSIndexer to refuse to use
+# an ENSIndexer Schema that was already built with different indexing behavior.
+# This is to prevent data corruption from multiple ENSIndexer instances writing
+# state to the same ENSIndexer Schema at the same time.
+# - If you wish to change the indexing behavior of your ENSIndexer (such as
+# upgrading to a new ENSIndexer version or changing environment variables
+# that influence indexing behavior) you must either:
+# - Configure a new ENSIndexer Schema Name
+# - Remove or rename the existing ENSIndexer Schema you previously built
+# - Each time you configure a new ENSIndexer Schema Name there is
+# no automatic "garbage collection" of any ENSIndexer Schemas you may have
+# previously built. Over time, this can result in the consumption of more and
+# more storage space consumption. To solve for this, manually garbage collect
+# any ENSIndexer Schemas you have previously built when they are
+# no longer needed.
+# - If ENSIndexer restarts without changes in the indexing behavior,
+# the indexing will continue from where it left off.
#
-# No two indexer instances can use the same database schema at the same time.
+# ENSIndexer can also run in dev mode (i.e. with `pnpm -F ensindexer dev` command).
+# In dev mode, the following rules apply:
+# - ENSIndexer uses the ENSIndexer Schema Name that is configured inline in the `dev` script in package.json.
+# - Any change to indexing behavior in ENSIndexer results in the ENSIndexer instance being restarted.
+# - Each time ENSIndexer starts in dev mode, the ENSIndexer Schema for
+# the configured ENSIndexer Schema Name is recreated. This means that any existing ENSIndexer Schema with
+# the ENSIndexer Schema Name will be dropped and a new ENSIndexer Schema with the same name will be created.
#
-# Read more about database schema rules here:
-# https://ponder.sh/docs/api-reference/database#database-schema-rules
-#
-# Avoid using the `public` schema as we force that in the `dev` command. Using `public`
-# cause conflicts as you interchange between dev and start commands so use literally
-# anything else.
-DATABASE_SCHEMA=production
-# Required. This is the connection string for the database that the indexer will use to store data.
+# ENSIndexer manages the ENSIndexer Schemas according to the rules of Ponder-managed database schemas.
+# Read more about these rules here:
+# https://ponder.sh/docs/api-reference/ponder/database#database-schema-rules
+ENSINDEXER_SCHEMA_NAME=ensindexer_0
+# Required. This is the connection string for the Postgres database where ENSIndexer will store data.
# It should be in the format of `postgresql://:@:/`
-DATABASE_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database
+ENSDB_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database
# ENS Namespace Configuration
# Required. Must be an ENS namespace's Identifier such as mainnet, sepolia, or ens-test-env.
diff --git a/apps/ensindexer/package.json b/apps/ensindexer/package.json
index 9cbe8a5229..75d0330fb0 100644
--- a/apps/ensindexer/package.json
+++ b/apps/ensindexer/package.json
@@ -12,9 +12,8 @@
},
"homepage": "https://github.com/namehash/ensnode/tree/main/apps/ensindexer",
"scripts": {
- "dev": "DATABASE_SCHEMA=public ponder --root ./ponder dev --disable-ui",
- "start": "ponder --root ./ponder start",
- "serve": "ponder --root ./ponder serve",
+ "dev": "ENSINDEXER_SCHEMA_NAME=ensindexer_temp_dev ponder --root ./ponder dev --disable-ui --schema ensindexer_temp_dev",
+ "start": "ponder --root ./ponder start --schema $ENSINDEXER_SCHEMA_NAME",
"db": "ponder --root ./ponder db",
"codegen": "ponder --root ./ponder codegen",
"test": "vitest",
diff --git a/apps/ensindexer/src/config/config.schema.ts b/apps/ensindexer/src/config/config.schema.ts
index 950a8950e3..fc3286a9d1 100644
--- a/apps/ensindexer/src/config/config.schema.ts
+++ b/apps/ensindexer/src/config/config.schema.ts
@@ -4,8 +4,8 @@ import { prettifyError, ZodError, z } from "zod/v4";
import { buildBlockNumberRange, PluginName, uniq } from "@ensnode/ensnode-sdk";
import {
buildRpcConfigsFromEnv,
- DatabaseSchemaNameSchema,
ENSNamespaceSchema,
+ EnsIndexerSchemaNameSchema,
invariant_isSubgraphCompatibleRequirements,
invariant_rpcConfigsSpecifiedForRootChain,
makeFullyPinnedLabelSetSchema,
@@ -27,7 +27,7 @@ import {
invariant_validContractConfigs,
} from "./validations";
-export const DatabaseUrlSchema = z.string().refine(
+export const EnsDbUrlSchema = z.string().refine(
(url) => {
try {
if (!url.startsWith("postgresql://") && !url.startsWith("postgres://")) {
@@ -41,7 +41,7 @@ export const DatabaseUrlSchema = z.string().refine(
},
{
error:
- "Invalid PostgreSQL connection string. Expected format: postgresql://username:password@host:port/database",
+ "Invalid PostgreSQL connection string for ENSDb. Expected format: postgresql://username:password@host:port/database",
},
);
@@ -106,8 +106,8 @@ const IsSubgraphCompatibleSchema =
const ENSIndexerConfigSchema = z
.object({
- databaseUrl: DatabaseUrlSchema,
- databaseSchemaName: DatabaseSchemaNameSchema,
+ ensDbUrl: EnsDbUrlSchema,
+ ensIndexerSchemaName: EnsIndexerSchemaNameSchema,
rpcConfigs: RpcConfigsSchema,
namespace: ENSNamespaceSchema,
@@ -184,8 +184,8 @@ export function buildConfigFromEnvironment(_env: ENSIndexerEnvironment): EnsInde
// parse/validate with ENSIndexerConfigSchema
return ENSIndexerConfigSchema.parse({
- databaseUrl: env.DATABASE_URL,
- databaseSchemaName: env.DATABASE_SCHEMA,
+ ensDbUrl: env.ENSDB_URL,
+ ensIndexerSchemaName: env.ENSINDEXER_SCHEMA_NAME,
namespace: env.NAMESPACE,
rpcConfigs,
diff --git a/apps/ensindexer/src/config/config.test.ts b/apps/ensindexer/src/config/config.test.ts
index 538bf16371..92596a5eb4 100644
--- a/apps/ensindexer/src/config/config.test.ts
+++ b/apps/ensindexer/src/config/config.test.ts
@@ -23,8 +23,8 @@ const VALID_RPC_WS_URL_ALT = "wss://lb.drpc.org/ethereum/987";
const BASE_ENV: ENSIndexerEnvironment = {
NAMESPACE: "mainnet",
PLUGINS: "subgraph",
- DATABASE_SCHEMA: "ensnode",
- DATABASE_URL: "postgresql://user:password@localhost:5432/mydb",
+ ENSINDEXER_SCHEMA_NAME: "ensindexer_test",
+ ENSDB_URL: "postgresql://user:password@localhost:5432/mydb",
ENSRAINBOW_URL: "http://localhost:3223",
LABEL_SET_ID: "ens-test-env",
LABEL_SET_VERSION: "0",
@@ -66,7 +66,7 @@ describe("config (with base env)", () => {
const config = await getConfig();
expect(config.namespace).toBe("mainnet");
expect(config.globalBlockrange).toEqual(buildBlockNumberRange(undefined, undefined));
- expect(config.databaseSchemaName).toBe("ensnode");
+ expect(config.ensIndexerSchemaName).toBe("ensindexer_test");
expect(config.plugins).toEqual(["subgraph"]);
expect(config.ensRainbowUrl).toStrictEqual(new URL("http://localhost:3223"));
});
@@ -161,29 +161,29 @@ describe("config (with base env)", () => {
});
});
- describe(".databaseSchemaName", () => {
- it("returns the DATABASE_SCHEMA if set", async () => {
- vi.stubEnv("DATABASE_SCHEMA", "someschema");
+ describe(".ensIndexerSchemaName", () => {
+ it("returns the ENSINDEXER_SCHEMA_NAME if set", async () => {
+ vi.stubEnv("ENSINDEXER_SCHEMA_NAME", "ensindexer_test_1");
const config = await getConfig();
- expect(config.databaseSchemaName).toBe("someschema");
+ expect(config.ensIndexerSchemaName).toBe("ensindexer_test_1");
});
- it("throws an error when DATABASE_SCHEMA is not set", async () => {
- vi.stubEnv("DATABASE_SCHEMA", undefined);
- await expect(getConfig()).rejects.toThrow(/DATABASE_SCHEMA is required/);
+ it("throws an error when ENSINDEXER_SCHEMA_NAME is not set", async () => {
+ vi.stubEnv("ENSINDEXER_SCHEMA_NAME", undefined);
+ await expect(getConfig()).rejects.toThrow(/ENSINDEXER_SCHEMA_NAME is required/);
});
- it("throws an error when DATABASE_SCHEMA is empty", async () => {
- vi.stubEnv("DATABASE_SCHEMA", "");
+ it("throws an error when ENSINDEXER_SCHEMA_NAME is empty", async () => {
+ vi.stubEnv("ENSINDEXER_SCHEMA_NAME", "");
await expect(getConfig()).rejects.toThrow(
- /DATABASE_SCHEMA is required and cannot be an empty string/,
+ /ENSINDEXER_SCHEMA_NAME is required and cannot be an empty string/,
);
});
- it("throws an error when DATABASE_SCHEMA is only whitespace", async () => {
- vi.stubEnv("DATABASE_SCHEMA", " ");
+ it("throws an error when ENSINDEXER_SCHEMA_NAME is only whitespace", async () => {
+ vi.stubEnv("ENSINDEXER_SCHEMA_NAME", " ");
await expect(getConfig()).rejects.toThrow(
- /DATABASE_SCHEMA is required and cannot be an empty string/,
+ /ENSINDEXER_SCHEMA_NAME is required and cannot be an empty string/,
);
});
});
@@ -387,56 +387,56 @@ describe("config (with base env)", () => {
});
});
- describe(".databaseUrl", () => {
+ describe(".ensDbUrl", () => {
it("accepts a valid PostgreSQL connection string", async () => {
- vi.stubEnv("DATABASE_URL", "postgresql://user:password@localhost:5432/mydb");
+ vi.stubEnv("ENSDB_URL", "postgresql://user:password@localhost:5432/mydb");
const config = await getConfig();
- expect(config.databaseUrl).toBe("postgresql://user:password@localhost:5432/mydb");
+ expect(config.ensDbUrl).toBe("postgresql://user:password@localhost:5432/mydb");
});
it("accepts a connection string with additional parameters", async () => {
- vi.stubEnv("DATABASE_URL", "postgresql://user:password@localhost:5432/mydb?sslmode=require");
+ vi.stubEnv("ENSDB_URL", "postgresql://user:password@localhost:5432/mydb?sslmode=require");
const config = await getConfig();
- expect(config.databaseUrl).toBe(
+ expect(config.ensDbUrl).toBe(
"postgresql://user:password@localhost:5432/mydb?sslmode=require",
);
});
- it("throws an error if DATABASE_URL is not set", async () => {
- vi.stubEnv("DATABASE_URL", undefined);
+ it("throws an error if ENSDB_URL is not set", async () => {
+ vi.stubEnv("ENSDB_URL", undefined);
await expect(getConfig()).rejects.toThrow(/Invalid input/);
});
- it("throws an error if DATABASE_URL is empty", async () => {
- vi.stubEnv("DATABASE_URL", "");
+ it("throws an error if ENSDB_URL is empty", async () => {
+ vi.stubEnv("ENSDB_URL", "");
await expect(getConfig()).rejects.toThrow(/Invalid PostgreSQL connection string/);
});
- it("throws an error if DATABASE_URL is not a valid postgres connection string", async () => {
- vi.stubEnv("DATABASE_URL", "not-a-postgres-connection-string");
+ it("throws an error if ENSDB_URL is not a valid postgres connection string", async () => {
+ vi.stubEnv("ENSDB_URL", "not-a-postgres-connection-string");
await expect(getConfig()).rejects.toThrow(/Invalid PostgreSQL connection string/);
});
- it("throws an error if DATABASE_URL uses the wrong protocol", async () => {
- vi.stubEnv("DATABASE_URL", "mysql://user:password@localhost:3306/mydb");
+ it("throws an error if ENSDB_URL uses the wrong protocol", async () => {
+ vi.stubEnv("ENSDB_URL", "mysql://user:password@localhost:3306/mydb");
await expect(getConfig()).rejects.toThrow(/Invalid PostgreSQL connection string/);
});
- it("throws an error if DATABASE_URL is missing required components", async () => {
- vi.stubEnv("DATABASE_URL", "postgresql://localhost:5432");
+ it("throws an error if ENSDB_URL is missing required components", async () => {
+ vi.stubEnv("ENSDB_URL", "postgresql://localhost:5432");
await expect(getConfig()).rejects.toThrow(/Invalid PostgreSQL connection string/);
});
it("accepts postgres:// protocol", async () => {
- vi.stubEnv("DATABASE_URL", "postgres://user:password@localhost:5432/mydb");
+ vi.stubEnv("ENSDB_URL", "postgres://user:password@localhost:5432/mydb");
const config = await getConfig();
- expect(config.databaseUrl).toBe("postgres://user:password@localhost:5432/mydb");
+ expect(config.ensDbUrl).toBe("postgres://user:password@localhost:5432/mydb");
});
it("accepts postgresql:// protocol", async () => {
- vi.stubEnv("DATABASE_URL", "postgresql://user:password@localhost:5432/mydb");
+ vi.stubEnv("ENSDB_URL", "postgresql://user:password@localhost:5432/mydb");
const config = await getConfig();
- expect(config.databaseUrl).toBe("postgresql://user:password@localhost:5432/mydb");
+ expect(config.ensDbUrl).toBe("postgresql://user:password@localhost:5432/mydb");
});
});
@@ -647,12 +647,12 @@ describe("config (with base env)", () => {
*/
describe("config (minimal base env)", () => {
beforeEach(() => {
- const { NAMESPACE, ENSRAINBOW_URL, DATABASE_URL, DATABASE_SCHEMA, RPC_URL_1 } = BASE_ENV;
+ const { NAMESPACE, ENSRAINBOW_URL, ENSDB_URL, ENSINDEXER_SCHEMA_NAME, RPC_URL_1 } = BASE_ENV;
stubEnv({
NAMESPACE,
ENSRAINBOW_URL,
- DATABASE_URL,
- DATABASE_SCHEMA,
+ ENSDB_URL,
+ ENSINDEXER_SCHEMA_NAME,
RPC_URL_1,
});
});
diff --git a/apps/ensindexer/src/config/environment.ts b/apps/ensindexer/src/config/environment.ts
index db7338b80a..a764c271c5 100644
--- a/apps/ensindexer/src/config/environment.ts
+++ b/apps/ensindexer/src/config/environment.ts
@@ -1,4 +1,4 @@
-import type { EnsIndexerDatabaseEnvironment, RpcEnvironment } from "@ensnode/ensnode-sdk/internal";
+import type { EnsDbEnvironment, RpcEnvironment } from "@ensnode/ensnode-sdk/internal";
/**
* Represents the raw, unvalidated environment variables for the ENSIndexer application.
@@ -7,7 +7,7 @@ import type { EnsIndexerDatabaseEnvironment, RpcEnvironment } from "@ensnode/ens
* their state in `process.env`. This interface is intended to be the source type which then gets
* mapped/parsed into a structured configuration object like `ENSIndexerConfig`.
*/
-export type ENSIndexerEnvironment = EnsIndexerDatabaseEnvironment &
+export type ENSIndexerEnvironment = EnsDbEnvironment &
RpcEnvironment & {
NAMESPACE?: string;
PLUGINS?: string;
diff --git a/apps/ensindexer/src/config/redact.ts b/apps/ensindexer/src/config/redact.ts
index 91d7376703..04a166314a 100644
--- a/apps/ensindexer/src/config/redact.ts
+++ b/apps/ensindexer/src/config/redact.ts
@@ -8,7 +8,7 @@ import type { ENSIndexerConfig } from "@/config/types";
export function redactENSIndexerConfig(config: ENSIndexerConfig) {
return {
...config,
- databaseUrl: redactString(config.databaseUrl),
+ ensDbUrl: redactString(config.ensDbUrl),
rpcConfigs: redactRpcConfigs(config.rpcConfigs),
};
}
diff --git a/apps/ensindexer/src/config/serialize.ts b/apps/ensindexer/src/config/serialize.ts
index 56ab5c6aaa..637ecb1d5c 100644
--- a/apps/ensindexer/src/config/serialize.ts
+++ b/apps/ensindexer/src/config/serialize.ts
@@ -44,8 +44,8 @@ export function serializeRedactedENSIndexerConfig(
const redactedConfig = redactENSIndexerConfig(config);
return {
- databaseSchemaName: redactedConfig.databaseSchemaName,
- databaseUrl: redactedConfig.databaseUrl,
+ ensIndexerSchemaName: redactedConfig.ensIndexerSchemaName,
+ ensDbUrl: redactedConfig.ensDbUrl,
ensRainbowUrl: serializeUrl(redactedConfig.ensRainbowUrl),
labelSet: redactedConfig.labelSet,
globalBlockrange: redactedConfig.globalBlockrange,
diff --git a/apps/ensindexer/src/config/types.ts b/apps/ensindexer/src/config/types.ts
index d086591743..fc70c9b182 100644
--- a/apps/ensindexer/src/config/types.ts
+++ b/apps/ensindexer/src/config/types.ts
@@ -1,8 +1,8 @@
import type { ENSNamespaceId } from "@ensnode/datasources";
import type { BlockNumberRange, ChainId, PluginName } from "@ensnode/ensnode-sdk";
import {
- type DatabaseSchemaName,
type DatabaseUrl,
+ type EnsIndexerSchemaName,
RpcConfig,
type RpcConfigs,
} from "@ensnode/ensnode-sdk/internal";
@@ -38,27 +38,50 @@ export interface EnsIndexerConfig {
labelSet: Required;
/**
- * A Postgres database schema name. This instance of ENSIndexer will write indexed data to the
- * tables in this schema.
- *
- * The {@link databaseSchemaName} must be unique per running instance of ENSIndexer (ponder will
- * enforce this with database locks). If multiple instances of ENSIndexer with the same
- * {@link databaseSchemaName} are running, only the first will successfully acquire the lock and begin
- * indexing: the rest will crash.
- *
- * If an ENSIndexer instance with the same configuration (including `databaseSchemaName`) is
- * started, and it successfully acquires the lock on this schema, it will continue indexing from
- * the current state.
- *
- * Many clients can read from this Postgres schema during or after indexing.
- *
- * Read more about database schema rules here:
- * @see https://ponder.sh/docs/api-reference/database#database-schema-rules
+ * The name of the ENSIndexer Schema in ENSDb where ENSIndexer will create
+ * tables to store indexed data.
+ *
+ * Each ENSIndexer instance is the exclusive writer to its ENSIndexer Schema
+ * within an ENSDb. Therefore, {@link ensIndexerSchemaName} must be
+ * a unique ENSIndexer Schema Name for all ENSIndexer instances writing to
+ * the same ENSDb. Multiple ENSIndexer instances can write to the same ENSDb,
+ * but each requires a distinct ENSIndexer Schema Name.
+ *
+ * When ENSIndexer runs in production mode, the following rules apply:
+ * - For safety, any changes to the indexing behavior in ENSIndexer (including
+ * any changes to indexing code or any changes to environment variables that
+ * influence indexing behavior) will cause ENSIndexer to refuse to use
+ * an ENSIndexer Schema that was already built with different indexing behavior.
+ * This is to prevent data corruption from multiple ENSIndexer instances writing
+ * state to the same ENSIndexer Schema at the same time.
+ * - If you wish to change the indexing behavior of your ENSIndexer (such as
+ * upgrading to a new ENSIndexer version or changing environment variables
+ * that influence indexing behavior) you must either:
+ * - Configure a new ENSIndexer Schema Name
+ * - Remove or rename the existing ENSIndexer Schema you previously built
+ * - Each time you configure a new ENSIndexer Schema Name there is
+ * no automatic "garbage collection" of any ENSIndexer Schemas you may have
+ * previously built. Over time, this can result in the consumption of more and
+ * more storage space consumption. To solve for this, manually garbage collect
+ * any ENSIndexer Schemas you have previously built when they are
+ * no longer needed.
+ * - If ENSIndexer restarts without changes in the indexing behavior,
+ * the indexing will continue from where it left off.
+ *
+ * When ENSIndexer runs in dev mode, the following rules apply:
+ * - Any change to indexing behavior in ENSIndexer results in the ENSIndexer instance being restarted.
+ * - Each time ENSIndexer starts in dev mode, the ENSIndexer Schema for
+ * the {@link ensIndexerSchemaName} is recreated. This means that any existing ENSIndexer Schema with
+ * the {@link ensIndexerSchemaName} will be dropped and a new ENSIndexer Schema with the same name will be created.
+ *
+ * ENSIndexer manages the ENSIndexer Schemas according to the rules of Ponder-managed database schemas.
+ * Read more about these rules here:
+ * @see https://ponder.sh/docs/api-reference/ponder/database#database-schema-rules
*
* Invariants:
* - Must be a non-empty string that is a valid Postgres database schema identifier.
*/
- databaseSchemaName: DatabaseSchemaName;
+ ensIndexerSchemaName: EnsIndexerSchemaName;
/**
* A set of {@link PluginName}s indicating which plugins to activate.
@@ -91,12 +114,12 @@ export interface EnsIndexerConfig {
indexedChainIds: Set;
/**
- * The database connection string for the indexer.
+ * The Postgres connection string for the ENSDb instance the ENSIndexer instance will use.
*
* Invariants:
* - The URL must be a valid PostgreSQL connection string
*/
- databaseUrl: DatabaseUrl;
+ ensDbUrl: DatabaseUrl;
/**
* Constrains the global blockrange for indexing, useful for testing purposes.
diff --git a/apps/ensindexer/src/lib/__test__/mockConfig.ts b/apps/ensindexer/src/lib/__test__/mockConfig.ts
index 5640cd6e6b..87b0a11cd6 100644
--- a/apps/ensindexer/src/lib/__test__/mockConfig.ts
+++ b/apps/ensindexer/src/lib/__test__/mockConfig.ts
@@ -8,8 +8,8 @@ import { deepClone } from "@/lib/lib-helpers";
// default, non-exported mock configuration template
const _defaultMockConfig = buildConfigFromEnvironment({
- DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/postgres",
- DATABASE_SCHEMA: "test_schema",
+ ENSDB_URL: "postgresql://postgres:postgres@localhost:5432/postgres",
+ ENSINDEXER_SCHEMA_NAME: "ensindexer_0",
NAMESPACE: "mainnet",
PLUGINS: "subgraph",
ENSRAINBOW_URL: "http://localhost:3223",
diff --git a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts
index 59d12277ef..c4d5d48422 100644
--- a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts
+++ b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts
@@ -35,7 +35,7 @@ export const mockVersionInfo: EnsIndexerVersionInfo = {
// Test fixture for EnsIndexerPublicConfig
export const mockPublicConfig: EnsIndexerPublicConfig = {
- databaseSchemaName: "public",
+ ensIndexerSchemaName: "ensindexer_0",
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
ensRainbowPublicConfig: mockEnsRainbowPublicConfig,
indexedChainIds: new Set([1, 8453]),
diff --git a/apps/ensindexer/src/lib/ensdb/singleton.ts b/apps/ensindexer/src/lib/ensdb/singleton.ts
index 1250e4f410..08cd7707fe 100644
--- a/apps/ensindexer/src/lib/ensdb/singleton.ts
+++ b/apps/ensindexer/src/lib/ensdb/singleton.ts
@@ -2,7 +2,7 @@ import config from "@/config";
import { EnsDbWriter } from "@ensnode/ensdb-sdk";
-const { databaseUrl: ensDbUrl, databaseSchemaName: ensIndexerSchemaName } = config;
+const { ensDbUrl, ensIndexerSchemaName } = config;
/**
* Singleton instance of ENSDbWriter for the ENSIndexer application.
diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts
index bffc14f145..56b396976c 100644
--- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts
+++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts
@@ -14,7 +14,7 @@ import { PublicConfigBuilder } from "./public-config-builder";
// Mock the config module
vi.mock("@/config", () => ({
default: {
- databaseSchemaName: "public",
+ ensIndexerSchemaName: "ensindexer_0",
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
indexedChainIds: new Set([1, 8453]),
isSubgraphCompatible: true,
@@ -66,7 +66,7 @@ const mockVersionInfo: EnsIndexerVersionInfo = {
// Helper to create unique mock config objects for each call
function createMockPublicConfig(overrides: Partial = {}) {
return {
- databaseSchemaName: "public",
+ ensIndexerSchemaName: "ensindexer_0",
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
ensRainbowPublicConfig: mockEnsRainbowConfig,
indexedChainIds: new Set([1, 8453]),
@@ -120,7 +120,7 @@ describe("PublicConfigBuilder", () => {
});
expect(validateEnsIndexerPublicConfig).toHaveBeenCalledWith({
- databaseSchemaName: config.databaseSchemaName,
+ ensIndexerSchemaName: config.ensIndexerSchemaName,
ensRainbowPublicConfig: mockEnsRainbowConfig,
labelSet: config.labelSet,
indexedChainIds: config.indexedChainIds,
@@ -293,8 +293,8 @@ describe("PublicConfigBuilder", () => {
describe("Caching behavior", () => {
it("each builder instance has its own independent cache", async () => {
// Arrange - create unique config objects for each builder
- const config1 = createMockPublicConfig({ databaseSchemaName: "schema1" });
- const config2 = createMockPublicConfig({ databaseSchemaName: "schema2" });
+ const config1 = createMockPublicConfig({ ensIndexerSchemaName: "schema1" });
+ const config2 = createMockPublicConfig({ ensIndexerSchemaName: "schema2" });
let callCount = 0;
const ensRainbowClientMock = {
@@ -323,8 +323,8 @@ describe("PublicConfigBuilder", () => {
expect(result1).toBe(config1);
expect(result2).toBe(config2);
expect(result1).not.toBe(result2);
- expect(result1.databaseSchemaName).toBe("schema1");
- expect(result2.databaseSchemaName).toBe("schema2");
+ expect(result1.ensIndexerSchemaName).toBe("schema1");
+ expect(result2.ensIndexerSchemaName).toBe("schema2");
});
it("retries building config on subsequent calls after failure", async () => {
diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts
index 633542ca9b..a34a8465f0 100644
--- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts
+++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts
@@ -51,7 +51,7 @@ export class PublicConfigBuilder {
]);
this.immutablePublicConfig = validateEnsIndexerPublicConfig({
- databaseSchemaName: config.databaseSchemaName,
+ ensIndexerSchemaName: config.ensIndexerSchemaName,
ensRainbowPublicConfig,
labelSet: config.labelSet,
indexedChainIds: config.indexedChainIds,
diff --git a/apps/ensindexer/src/ponder/config.ts b/apps/ensindexer/src/ponder/config.ts
index 18a46f445f..300a499959 100644
--- a/apps/ensindexer/src/ponder/config.ts
+++ b/apps/ensindexer/src/ponder/config.ts
@@ -54,4 +54,13 @@ const ponderConfig = activePlugins.reduce(
// For additional info see: https://ponder.sh/docs/api-reference/ponder/config#guarantees
ponderConfig.ordering = "omnichain";
+// By default, if the `DATABASE_URL` environment variable is set,
+// Ponder will use it for the connection string to the Postgres database.
+// However, we want Ponder to always use the `ENSDB_URL` environment variable instead and so
+// we make explicit use of it here.
+ponderConfig.database = {
+ connectionString: config.ensDbUrl,
+ kind: "postgres",
+};
+
export default ponderConfig;
diff --git a/docker-compose.yml b/docker-compose.yml
index dfc2e3a10c..1f04274da8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,8 +6,8 @@ services:
- "42069:42069"
environment:
# Override environment variables to point to docker instances
- DATABASE_URL: postgresql://postgres:password@postgres:5432/postgres
- DATABASE_SCHEMA: docker_compose_ensindexer_schema
+ ENSDB_URL: postgresql://postgres:password@postgres:5432/postgres
+ ENSINDEXER_SCHEMA_NAME: docker_compose_ensindexer_schema
ENSRAINBOW_URL: http://ensrainbow:3223
env_file:
# NOTE: must define apps/ensindexer/.env.local (see apps/ensindexer/.env.local.example)
@@ -34,7 +34,7 @@ services:
- "4334:4334"
environment:
# Override environment variables to point to docker instances
- DATABASE_URL: postgresql://postgres:password@postgres:5432/postgres
+ ENSDB_URL: postgresql://postgres:password@postgres:5432/postgres
ENSINDEXER_SCHEMA_NAME: docker_compose_ensindexer_schema
env_file:
# NOTE: must define apps/ensapi/.env.local (see apps/ensapi/.env.local.example)
diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json
index 804cb83536..edefe03597 100644
--- a/docs/docs.ensnode.io/ensapi-openapi.json
+++ b/docs/docs.ensnode.io/ensapi-openapi.json
@@ -46,7 +46,7 @@
"ensIndexerPublicConfig": {
"type": "object",
"properties": {
- "databaseSchemaName": { "type": "string", "minLength": 1 },
+ "ensIndexerSchemaName": { "type": "string", "minLength": 1 },
"ensRainbowPublicConfig": {
"type": "object",
"properties": {
@@ -108,7 +108,7 @@
}
},
"required": [
- "databaseSchemaName",
+ "ensIndexerSchemaName",
"ensRainbowPublicConfig",
"indexedChainIds",
"isSubgraphCompatible",
diff --git a/docs/ensnode.io/src/content/docs/docs/contributing/index.mdx b/docs/ensnode.io/src/content/docs/docs/contributing/index.mdx
index f83ba6e9dd..b9beadb5d7 100644
--- a/docs/ensnode.io/src/content/docs/docs/contributing/index.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/contributing/index.mdx
@@ -50,9 +50,9 @@ ENSNode is a suite of services, and some depend on others. Refer to the `docker-
/>
:::
-### 1. Running Postgres
+### 1. Running ENSDb
-Ensure Postgres in the background, providing its connection details to ENSIndexer via `DATABASE_URL`.
+Ensure ENSDb is running in the background, providing its connection details to ENSIndexer via `ENSDB_URL`.
### 2. Running ENSRainbow
diff --git a/docs/ensnode.io/src/content/docs/docs/contributing/releases.mdx b/docs/ensnode.io/src/content/docs/docs/contributing/releases.mdx
index 00d26d9817..3b9e11f418 100644
--- a/docs/ensnode.io/src/content/docs/docs/contributing/releases.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/contributing/releases.mdx
@@ -110,7 +110,7 @@ In particular, when deploying ENSNode to production environments, using the `lat
:::
:::caution
-Each ENSIndexer version update is likely to produce an updated [Ponder Build Id](https://ponder.sh/docs/api-reference/ponder/database). When updating your ENSIndexer version, you should expect to update the `DATABASE_SCHEMA` environment variable to point to a new Postgres Database Schema for a complete reindexing with the new Ponder Build Id. A complete reindexing may take over 24 hours depending on your configuration. ENSNode version updates require special coordination and should not be assumed to be a simple version bump.
+Each ENSIndexer version update is likely to produce an updated [Ponder Build Id](https://ponder.sh/docs/api-reference/ponder/database). When updating your ENSIndexer version, you should expect to update the `ENSINDEXER_SCHEMA_NAME` environment variable to point to a new ENSIndexer Schema in ENSDb for a complete reindexing with the new Ponder Build Id. A complete reindexing may take over 24 hours depending on your configuration. ENSNode version updates require special coordination and should not be assumed to be a simple version bump.
:::
diff --git a/docs/ensnode.io/src/content/docs/docs/usage/api.mdx b/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
index da07742e0c..878dc5bfc3 100644
--- a/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
@@ -100,7 +100,7 @@ The response includes several important configuration categories:
42161,
534352
],
- "databaseSchemaName": "alphaSchema0.35.0",
+ "ensIndexerSchemaName": "alphaSchema0.35.0",
"isSubgraphCompatible": false,
"labelSet": {
"labelSetId": "subgraph",
diff --git a/docs/ensnode.io/src/content/docs/ensindexer/usage/management.mdx b/docs/ensnode.io/src/content/docs/ensindexer/usage/management.mdx
index 51a706457b..3a2bad06f6 100644
--- a/docs/ensnode.io/src/content/docs/ensindexer/usage/management.mdx
+++ b/docs/ensnode.io/src/content/docs/ensindexer/usage/management.mdx
@@ -17,7 +17,7 @@ TODO
### Dropping Orphaned Indexing Schemas
-When re-deploying any Ponder indexer, including ENSNode a new schema is created (via the `DATABASE_SCHEMA` env variable) and the previous schemas are abandoned. They remain available for rollbacks, but take up database space—dropping these schemas once no longer available is useful for reclaiming space in your Postgres instance.
+When re-deploying any Ponder indexer, including ENSNode a new schema is created (via the `ENSINDEXER_SCHEMA_NAME` env variable) and the previous schemas are abandoned. They remain available for rollbacks, but take up database space—dropping these schemas once no longer available is useful for reclaiming space in your Postgres instance.
```sql
DROP SCHEMA CASCADE;
diff --git a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts
index 824c00ec66..926d2ca4f3 100644
--- a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts
+++ b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts
@@ -24,7 +24,7 @@ export const ensDbUrl = "postgres://user:pass@localhost:5432/ensdb";
export const ensIndexerSchemaName = "ensindexer_0";
export const publicConfig = {
- databaseSchemaName: ensIndexerSchemaName,
+ ensIndexerSchemaName,
ensRainbowPublicConfig: {
version: "0.32.0",
labelSet: {
diff --git a/packages/ensnode-sdk/src/ensapi/client.test.ts b/packages/ensnode-sdk/src/ensapi/client.test.ts
index 2f79a5438e..e6d5c910bb 100644
--- a/packages/ensnode-sdk/src/ensapi/client.test.ts
+++ b/packages/ensnode-sdk/src/ensapi/client.test.ts
@@ -77,7 +77,7 @@ const EXAMPLE_CONFIG_RESPONSE = {
labelSetVersion: 0,
},
indexedChainIds: [1, 8453, 59144, 10, 42161, 534352],
- databaseSchemaName: "alphaSchema0.31.0",
+ ensIndexerSchemaName: "alphaSchema0.31.0",
isSubgraphCompatible: false,
namespace: "mainnet",
plugins: [
diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
index 030704e12b..7f4bf6afa1 100644
--- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
+++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
@@ -19,7 +19,7 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = {
},
ensIndexerPublicConfig: {
namespace: ENSNamespaceIds.Mainnet,
- databaseSchemaName: "ensapi",
+ ensIndexerSchemaName: "ensindexer_0",
ensRainbowPublicConfig: {
version: "0.36.0",
labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
@@ -56,7 +56,7 @@ describe("ENSApi Config Serialization/Deserialization", () => {
},
ensIndexerPublicConfig: {
namespace: ENSNamespaceIds.Mainnet,
- databaseSchemaName: "ensapi",
+ ensIndexerSchemaName: "ensindexer_0",
ensRainbowPublicConfig: {
version: "0.36.0",
labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts
index 8bca076dc7..3bfd76b3cd 100644
--- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts
+++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts
@@ -13,7 +13,7 @@ export const configResponseMock = {
labelSetVersion: 0,
},
indexedChainIds: [1, 8453, 59144, 10, 42161, 534352],
- databaseSchemaName: "alphaSchema0.31.0",
+ ensIndexerSchemaName: "alphaSchema0.31.0",
ensRainbowPublicConfig: {
version: "0.31.0",
labelSet: {
diff --git a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
index 2258e2b8de..b38f3769c1 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
@@ -2,7 +2,7 @@ import type { EnsIndexerPublicConfig } from "./types";
export type EnsIndexerPublicConfigCompatibilityCheck = Omit<
EnsIndexerPublicConfig,
- "databaseSchemaName" | "ensRainbowPublicConfig" | "versionInfo"
+ "ensIndexerSchemaName" | "ensRainbowPublicConfig" | "versionInfo"
>;
/**
diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
index 68f8da12f1..4dd5c05493 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
@@ -10,7 +10,7 @@ describe("ENSIndexer: Config", () => {
it("can serialize EnsIndexerPublicConfig", () => {
// arrange
const config = {
- databaseSchemaName: "public",
+ ensIndexerSchemaName: "ensindexer_0",
ensRainbowPublicConfig: {
version: "0.32.0",
labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
@@ -52,7 +52,7 @@ describe("ENSIndexer: Config", () => {
describe("deserialization", () => {
const correctSerializedConfig = {
- databaseSchemaName: "public",
+ ensIndexerSchemaName: "ensindexer_0",
ensRainbowPublicConfig: {
version: "0.32.0",
labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
diff --git a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
index a397f3c861..da32387442 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
@@ -20,7 +20,7 @@ export function serializeEnsIndexerPublicConfig(
config: EnsIndexerPublicConfig,
): SerializedEnsIndexerPublicConfig {
const {
- databaseSchemaName,
+ ensIndexerSchemaName,
ensRainbowPublicConfig,
indexedChainIds,
isSubgraphCompatible,
@@ -31,7 +31,7 @@ export function serializeEnsIndexerPublicConfig(
} = config;
return {
- databaseSchemaName,
+ ensIndexerSchemaName,
ensRainbowPublicConfig,
indexedChainIds: serializeIndexedChainIds(indexedChainIds),
isSubgraphCompatible,
diff --git a/packages/ensnode-sdk/src/ensindexer/config/types.ts b/packages/ensnode-sdk/src/ensindexer/config/types.ts
index 66b2821e3a..0476e7d377 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/types.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/types.ts
@@ -81,14 +81,14 @@ export interface EnsIndexerPublicConfig {
labelSet: Required;
/**
- * A Postgres database schema name. This instance of ENSIndexer will write
- * indexed data to the tables in this schema.
+ * The name of the ENSIndexer Schema in the ENSDb instance,
+ * where the ENSIndexer instance writes indexed data.
*
* Invariants:
* - Must be a non-empty string that is a valid Postgres database schema
* identifier.
*/
- databaseSchemaName: string;
+ ensIndexerSchemaName: string;
/**
* ENSRainbow public config
diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
index 237911773d..97e057544e 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
@@ -5,8 +5,8 @@ import { buildUnvalidatedEnsIndexerPublicConfig } from "./deserialize";
import type { SerializedEnsIndexerPublicConfig } from "./serialized-types";
import { type EnsIndexerVersionInfo, PluginName } from "./types";
import {
- makeDatabaseSchemaNameSchema,
makeEnsIndexerPublicConfigSchema,
+ makeEnsIndexerSchemaNameSchema,
makeEnsIndexerVersionInfoSchema,
makeFullyPinnedLabelSetSchema,
makeIndexedChainIdsSchema,
@@ -21,12 +21,12 @@ describe("ENSIndexer: Config", () => {
describe("Parsing", () => {
it("can parse database schema name values", () => {
- expect(makeDatabaseSchemaNameSchema().parse("public")).toBe("public");
- expect(makeDatabaseSchemaNameSchema().parse("the_schema")).toBe("the_schema");
- expect(makeDatabaseSchemaNameSchema().parse("theSchema")).toBe("theSchema");
+ expect(makeEnsIndexerSchemaNameSchema().parse("public")).toBe("public");
+ expect(makeEnsIndexerSchemaNameSchema().parse("the_schema")).toBe("the_schema");
+ expect(makeEnsIndexerSchemaNameSchema().parse("theSchema")).toBe("theSchema");
- expect(formatParseError(makeDatabaseSchemaNameSchema().safeParse(1))).toContain(
- "Database schema name must be a string",
+ expect(formatParseError(makeEnsIndexerSchemaNameSchema().safeParse(1))).toContain(
+ "ENS Indexer Schema Name must be a string",
);
});
@@ -163,7 +163,7 @@ describe("ENSIndexer: Config", () => {
isSubgraphCompatible: false, // Set to false to bypass isSubgraphCompatible invariant
namespace: "mainnet" as const,
plugins: [PluginName.Subgraph, PluginName.Registrars], // Multiple plugins allowed when not subgraph compatible
- databaseSchemaName: "test_schema",
+ ensIndexerSchemaName: "ensindexer_0",
versionInfo: {
ponder: "0.11.25",
ensDb: "0.32.0",
@@ -217,7 +217,7 @@ describe("ENSIndexer: Config", () => {
isSubgraphCompatible: true,
namespace: "mainnet" as const,
plugins: [PluginName.Subgraph],
- databaseSchemaName: "test_schema",
+ ensIndexerSchemaName: "ensindexer_0",
versionInfo: {
ponder: "0.11.25",
ensDb: "0.32.0",
@@ -263,11 +263,13 @@ describe("ENSIndexer: Config", () => {
describe("Useful error messages", () => {
it("can apply custom value labels", () => {
expect(
- formatParseError(makeDatabaseSchemaNameSchema("databaseSchema").safeParse("")),
- ).toContain("databaseSchema is required and must be a non-empty string.");
+ formatParseError(makeEnsIndexerSchemaNameSchema("ensIndexerSchemaName").safeParse("")),
+ ).toContain("ensIndexerSchemaName is required and must be a non-empty string.");
expect(
- formatParseError(makeDatabaseSchemaNameSchema("DATABASE_SCHEMA env var").safeParse("")),
- ).toContain("DATABASE_SCHEMA env var is required and must be a non-empty string.");
+ formatParseError(
+ makeEnsIndexerSchemaNameSchema("ENSINDEXER_SCHEMA_NAME env var").safeParse(""),
+ ),
+ ).toContain("ENSINDEXER_SCHEMA_NAME env var is required and must be a non-empty string.");
expect(
formatParseError(
diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
index 380b9924ac..3563087181 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
@@ -63,7 +63,7 @@ export const makePluginsListSchema = (valueLabel: string = "Plugins") =>
*
* The name is guaranteed to be a non-empty string.
*/
-export const makeDatabaseSchemaNameSchema = (valueLabel: string = "Database schema name") =>
+export const makeEnsIndexerSchemaNameSchema = (valueLabel: string = "ENS Indexer Schema Name") =>
z
.string({ error: `${valueLabel} must be a string` })
.trim()
@@ -161,7 +161,7 @@ export function invariant_ensRainbowSupportedLabelSetAndVersion(
export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexerPublicConfig") =>
z
.object({
- databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
+ ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),
ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(
`${valueLabel}.ensRainbowPublicConfig`,
),
@@ -193,7 +193,7 @@ export const makeSerializedEnsIndexerPublicConfigSchema = (
valueLabel: string = "Serialized ENSIndexerPublicConfig",
) =>
z.object({
- databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
+ ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),
ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(
`${valueLabel}.ensRainbowPublicConfig`,
),
diff --git a/packages/ensnode-sdk/src/shared/config/environments.ts b/packages/ensnode-sdk/src/shared/config/environments.ts
index 0a3a9c8091..7069400f1f 100644
--- a/packages/ensnode-sdk/src/shared/config/environments.ts
+++ b/packages/ensnode-sdk/src/shared/config/environments.ts
@@ -1,19 +1,11 @@
/**
- * Environment variables for ENSApi database configuration.
+ * Environment variables for ENSDb configuration.
*/
-export interface EnsApiDatabaseEnvironment {
- DATABASE_URL?: string;
+export interface EnsDbEnvironment {
+ ENSDB_URL?: string;
ENSINDEXER_SCHEMA_NAME?: string;
}
-/**
- * Environment variables for ENSIndexer database configuration.
- */
-export interface EnsIndexerDatabaseEnvironment {
- DATABASE_URL?: string;
- DATABASE_SCHEMA?: string;
-}
-
/**
* Environment variables for RPC configuration.
*/
diff --git a/packages/ensnode-sdk/src/shared/config/types.ts b/packages/ensnode-sdk/src/shared/config/types.ts
index 155feb745f..0f2ac4770d 100644
--- a/packages/ensnode-sdk/src/shared/config/types.ts
+++ b/packages/ensnode-sdk/src/shared/config/types.ts
@@ -2,7 +2,7 @@ import type { ChainId, UrlString } from "enssdk";
import type { z } from "zod/v4";
import type {
- DatabaseSchemaNameSchema,
+ EnsIndexerSchemaNameSchema,
PortNumberSchema,
TheGraphApiKeySchema,
} from "./zod-schemas";
@@ -44,7 +44,9 @@ export interface RpcConfig {
export type RpcConfigs = Map;
export type DatabaseUrl = UrlString;
-export type DatabaseSchemaName = z.infer;
+
+export type EnsIndexerSchemaName = z.infer;
+
export type TheGraphApiKey = z.infer;
export type PortNumber = z.infer;
diff --git a/packages/ensnode-sdk/src/shared/config/zod-schemas.ts b/packages/ensnode-sdk/src/shared/config/zod-schemas.ts
index ee15496dd4..272be05c1a 100644
--- a/packages/ensnode-sdk/src/shared/config/zod-schemas.ts
+++ b/packages/ensnode-sdk/src/shared/config/zod-schemas.ts
@@ -12,13 +12,13 @@ import {
invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL,
} from "./validatons";
-export const DatabaseSchemaNameSchema = z
+export const EnsIndexerSchemaNameSchema = z
.string({
- error: "DATABASE_SCHEMA is required.",
+ error: "ENSINDEXER_SCHEMA_NAME is required.",
})
.trim()
.min(1, {
- error: "DATABASE_SCHEMA is required and cannot be an empty string.",
+ error: "ENSINDEXER_SCHEMA_NAME is required and cannot be an empty string.",
});
const RpcConfigSchema = z
diff --git a/packages/integration-test-env/README.md b/packages/integration-test-env/README.md
index 5eb0320fbf..92de243d9b 100644
--- a/packages/integration-test-env/README.md
+++ b/packages/integration-test-env/README.md
@@ -91,13 +91,10 @@ cd apps/ensindexer && pnpm dev
with environment variables:
```env
-DATABASE_SCHEMA=ensindexer_0
NAMESPACE=ens-test-env
PLUGINS=ensv2,protocol-acceleration
```
-`DATABASE_SCHEMA` can be any valid Postgres schema name — just make sure ENSApi uses the same value.
-
#### 5. Start ENSApi
```sh
@@ -107,15 +104,15 @@ cd apps/ensapi && pnpm dev
with environment variables:
```env
-DATABASE_URL=postgresql://ensnode:ensnode@localhost:5432/ensnode
-ENSINDEXER_SCHEMA_NAME=ensindexer_0
+ENSDB_URL=postgresql://ensnode:ensnode@localhost:5432/ensnode
+ENSINDEXER_SCHEMA_NAME=ensindexer_temp_dev
```
-`ENSINDEXER_SCHEMA_NAME` must match the `DATABASE_SCHEMA` used by ENSIndexer above.
+`ENSINDEXER_SCHEMA_NAME` must match the `ENSINDEXER_SCHEMA_NAME` used by ENSIndexer above, and `ensindexer_temp_dev` is the schema name used when running ENSIndexer with `pnpm dev`.
#### 6. Run Integration Tests
-Finally, you can run vitest on the integration tests using:
+Finally, you can run vitest with the integration test suite using:
```sh
pnpm test:integration
diff --git a/packages/integration-test-env/src/orchestrator.ts b/packages/integration-test-env/src/orchestrator.ts
index 5d943248aa..99df9f5f46 100644
--- a/packages/integration-test-env/src/orchestrator.ts
+++ b/packages/integration-test-env/src/orchestrator.ts
@@ -246,7 +246,7 @@ async function main() {
const postgresContainer = composeEnvironment.getContainer("postgres");
const postgresPort = postgresContainer.getMappedPort(5432);
- const DATABASE_URL = `postgresql://postgres:password@localhost:${postgresPort}/postgres`;
+ const ENSDB_URL = `postgresql://postgres:password@localhost:${postgresPort}/postgres`;
log(`Postgres is ready (port ${postgresPort})`);
log("Devnet is ready");
@@ -305,8 +305,8 @@ async function main() {
ENSINDEXER_DIR,
{
NAMESPACE: ENSNamespaceIds.EnsTestEnv,
- DATABASE_URL,
- DATABASE_SCHEMA: ENSINDEXER_SCHEMA_NAME,
+ ENSDB_URL,
+ ENSINDEXER_SCHEMA_NAME,
PLUGINS: "ensv2,protocol-acceleration",
ENSRAINBOW_URL,
LABEL_SET_ID,
@@ -317,7 +317,7 @@ async function main() {
await waitForHealth(`http://localhost:${ENSINDEXER_PORT}/health`, 60_000, "ENSIndexer");
// Phase 4: Wait for indexing to complete
- await pollIndexingStatus(DATABASE_URL, ENSINDEXER_SCHEMA_NAME, 30_000);
+ await pollIndexingStatus(ENSDB_URL, ENSINDEXER_SCHEMA_NAME, 30_000);
// Phase 5: Start ENSApi
log("Starting ENSApi...");
@@ -326,7 +326,7 @@ async function main() {
["start"],
ENSAPI_DIR,
{
- DATABASE_URL,
+ ENSDB_URL,
ENSINDEXER_SCHEMA_NAME,
},
"ensapi",
diff --git a/terraform/main.tf b/terraform/main.tf
index 0c2f538fb6..f2d110fb98 100644
--- a/terraform/main.tf
+++ b/terraform/main.tf
@@ -46,7 +46,7 @@ locals {
sepolia = {
ensnode_indexer_type = "sepolia"
ensnode_environment_name = var.render_environment
- database_schema = "sepoliaSchema-${var.ensnode_version}"
+ ensindexer_schema_name = "sepoliaSchema-${var.ensnode_version}"
plugins = "subgraph"
namespace = "sepolia"
render_instance_plan = "starter"
@@ -57,7 +57,7 @@ locals {
v2-sepolia = {
ensnode_indexer_type = "v2-sepolia"
ensnode_environment_name = var.render_environment
- database_schema = "v2SepoliaSchema-${var.ensnode_version}"
+ ensindexer_schema_name = "v2SepoliaSchema-${var.ensnode_version}"
plugins = "ensv2,protocol-acceleration"
namespace = "sepolia"
render_instance_plan = "starter"
@@ -68,7 +68,7 @@ locals {
mainnet = {
ensnode_indexer_type = "mainnet"
ensnode_environment_name = var.render_environment
- database_schema = "mainnetSchema-${var.ensnode_version}"
+ ensindexer_schema_name = "mainnetSchema-${var.ensnode_version}"
plugins = "subgraph"
namespace = "mainnet"
render_instance_plan = "standard"
@@ -79,7 +79,7 @@ locals {
alpha = {
ensnode_indexer_type = "alpha"
ensnode_environment_name = var.render_environment
- database_schema = "alphaSchema-${var.ensnode_version}"
+ ensindexer_schema_name = "alphaSchema-${var.ensnode_version}"
plugins = "subgraph,basenames,lineanames,threedns,protocol-acceleration,registrars,tokenscope"
namespace = "mainnet"
render_instance_plan = "standard"
@@ -91,7 +91,7 @@ locals {
alpha-sepolia = {
ensnode_indexer_type = "alpha-sepolia"
ensnode_environment_name = var.render_environment
- database_schema = "alphaSepoliaSchema-${var.ensnode_version}"
+ ensindexer_schema_name = "alphaSepoliaSchema-${var.ensnode_version}"
plugins = "subgraph,basenames,lineanames,registrars"
namespace = "sepolia"
render_instance_plan = "starter"
@@ -161,7 +161,7 @@ module "ensindexer" {
ensnode_indexer_type = each.value.ensnode_indexer_type
render_instance_plan = each.value.render_instance_plan
ensnode_environment_name = each.value.ensnode_environment_name
- database_schema = each.value.database_schema
+ ensindexer_schema_name = each.value.ensindexer_schema_name
plugins = each.value.plugins
namespace = each.value.namespace
subgraph_compat = each.value.subgraph_compat
diff --git a/terraform/modules/ensindexer/main.tf b/terraform/modules/ensindexer/main.tf
index 7b9778a571..4f485ed2f8 100644
--- a/terraform/modules/ensindexer/main.tf
+++ b/terraform/modules/ensindexer/main.tf
@@ -1,7 +1,8 @@
locals {
common_variables = {
# Common configuration
- "DATABASE_URL" = { value = var.ensdb_url },
+ "ENSDB_URL" = { value = var.ensdb_url },
+ "ENSINDEXER_SCHEMA_NAME" = { value = var.ensindexer_schema_name },
"ALCHEMY_API_KEY" = { value = var.alchemy_api_key }
"QUICKNODE_API_KEY" = { value = var.quicknode_api_key }
"QUICKNODE_ENDPOINT_NAME" = { value = var.quicknode_endpoint_name }
@@ -28,7 +29,6 @@ resource "render_web_service" "ensindexer" {
}
env_vars = merge(local.common_variables, {
- "DATABASE_SCHEMA" = { value = var.database_schema },
"ENSRAINBOW_URL" = { value = var.ensrainbow_url },
"LABEL_SET_ID" = { value = var.ensindexer_label_set_id },
"LABEL_SET_VERSION" = { value = var.ensindexer_label_set_version },
@@ -59,9 +59,7 @@ resource "render_web_service" "ensapi" {
}
}
- env_vars = merge(local.common_variables, {
- "ENSINDEXER_SCHEMA_NAME" = { value = var.database_schema },
- })
+ env_vars = local.common_variables
# See https://render.com/docs/custom-domains
custom_domains = [
diff --git a/terraform/modules/ensindexer/variables.tf b/terraform/modules/ensindexer/variables.tf
index 392d9c133b..ae0cf95c0f 100644
--- a/terraform/modules/ensindexer/variables.tf
+++ b/terraform/modules/ensindexer/variables.tf
@@ -45,7 +45,7 @@ variable "ensdb_url" {
type = string
}
-variable "database_schema" {
+variable "ensindexer_schema_name" {
type = string
}