-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cross-chain-indexing): enable multiple concurrent plugins (#24)
* feat(cross-subname-indexing): allow activating multiple plugins together * feat(cross-subname-indexing): demonstrate retrieving cross-subname index * refactor(handlers): stremline logic * refactor(ponder.config): simplify structure * fix: apply pr feedback * fix: typos * fix: apply pr feedback * feat(plugins): introduce ACTIVE_PLUGINS validation * fix(schema): use proper schema import * feat(utils): import deep merge npm lib * fix(codestyle): apply formatting * docs: apply text edits Apply PR suggestion regarding the in-code documentation Co-authored-by: lightwalker.eth <[email protected]> * feat(database-entites): ensure domain entity exists Create an idepotenet function that takes a domain token ID and makes sure there is a database entity created for it. * fix(upserts): make `ensureDomainExists` to always return a DB entity` -m "Had to replace `.onConflictDoNothing()` with `.onConflictDoUpdate({})` as the former would not return a DB entity if there was a conflict. The later would apply the delta on conflict, but since delta is an empty object, there will be no update at all. And yet, the existing DB entity will be always returned." * docs: update description of `ensureDomainExists` * fix(defaults): make all available plugins active Declare all plugins active with the default `ACTIVE_PLUGINS` env var. * feat(deps): update ponder * docs(handlers): update Registry descriptions * fix(handlers-base.eth): remove dead code * feat(rpc): define env vars with rate limits This change allows defining env vars with rate limtis for selected RPC nodes. * docs: update descriptions as suggested by PR feedback Co-authored-by: lightwalker.eth <[email protected]> * docs: update .env.local.example Organize env vars in logical groups. Also, update the public RPC URLs to be the dRPC ones. * docs(helpers): define default values as named consts Introduce `DEFAULT_RPC_RATE_LIMIT` const to describe a defult rate limit setting. * refactor(db-helpers): rename `upserts into db-helpers The new name describes the file contents better. There are some upsert helpers, but also some idemptent-insert ones. * refactor(db-helpers): drop `ensureDomainExists` Use plain DB inserts and apply conflict resolution method if applicatble. * chore: trigger rebuild with fresh deployment id * fix(readme): update title * refactor(helpers): update `rpcRequestRateLimit` config facotry * docs: typos * docs(helpers): move the docs around * refactor(ponder.config): renames * docs(handlers): update registry setup description * docs: replacements * feat(helpers): introduce `rpcEndpointUrl` factory * fix(codestyle): apply auto-formatting * docs: update descriptions Co-authored-by: lightwalker.eth <[email protected]> * fix(helpers): update env var parsing logic * docs: being more specific and correct * fix(plugin-helpers): rename types * fix: apply pr feedback * docs: update env example
- Loading branch information
Showing
18 changed files
with
351 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,40 @@ | ||
# RPC configuration | ||
# Follow the format: RPC_URL_{chainId}={rpcUrl} | ||
|
||
RPC_URL_1=https://ethereum-rpc.publicnode.com | ||
RPC_URL_8453=https://base-rpc.publicnode.com | ||
RPC_URL_59144=https://linea-rpc.publicnode.com | ||
|
||
# Identify which indexer plugin to activate (see `src/plugins` for available plugins) | ||
|
||
ACTIVE_PLUGIN=base.eth | ||
# For the RPC URL of each chain, follow the format: RPC_URL_{chainId}={rpcUrl} | ||
RPC_URL_1=https://eth.drpc.org | ||
RPC_URL_8453=https://base.drpc.org | ||
RPC_URL_59144=https://linea.drpc.org | ||
# For the RPC rate limits of each chain, follow the format: | ||
# RPC_REQUEST_RATE_LIMIT_{chainId}={rateLimitInRequestsPerSecond} | ||
# The rate limit is the maximum number of requests per second that can be made | ||
# to the RPC endpoint. For public RPC endpoints, it is recommended to set | ||
# a rate limit to low values (i.e. below 30 rps) to avoid being rate limited. | ||
# For private RPC endpoints, the rate limit can be set to higher values, | ||
# depending on the capacity of the endpoint. For example, 500 rps. | ||
# If no rate limit is set for a given chainId, the DEFAULT_RPC_RATE_LIMIT value | ||
# will be applied. | ||
RPC_REQUEST_RATE_LIMIT_1=50 | ||
RPC_REQUEST_RATE_LIMIT_8453=20 | ||
RPC_REQUEST_RATE_LIMIT_59144=20 | ||
|
||
# Database configuration | ||
|
||
# This is where the indexer will create the tables defined in ponder.schema.ts | ||
# No two indexer instances can use the same database schema at the same time. This prevents data corruption. | ||
# @link https://ponder.sh/docs/api-reference/database#database-schema-rules | ||
DATABASE_SCHEMA=subname_index_base.eth | ||
# The indexer will use Postgres with that as the connection string. If not defined, the indexer will use PSlite. | ||
# 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. | ||
# | ||
# 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 | ||
# | ||
# No two indexer instances can use the same database schema at the same time. | ||
# | ||
# Read more about database schema rules here: | ||
# https://ponder.sh/docs/api-reference/database#database-schema-rules | ||
DATABASE_SCHEMA=ens | ||
# This is the connection string for the database that the indexer will use to store data. | ||
# It should be in the format of `postgresql://<username>:<password>@<host>:<port>/<database>` | ||
DATABASE_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database | ||
|
||
# Plugin configuration | ||
# Identify which indexer plugins to activate (see `src/plugins` for available plugins) | ||
# This is a comma separated list of one or more available plugin names (case-sensitive). | ||
ACTIVE_PLUGINS=eth,base.eth,linea.eth |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,33 @@ | ||
import { ACTIVE_PLUGIN } from "./src/lib/plugin-helpers"; | ||
import { deepMergeRecursive } from "./src/lib/helpers"; | ||
import { type MergedTypes, getActivePlugins } from "./src/lib/plugin-helpers"; | ||
import * as baseEthPlugin from "./src/plugins/base.eth/ponder.config"; | ||
import * as ethPlugin from "./src/plugins/eth/ponder.config"; | ||
import * as lineaEthPlugin from "./src/plugins/linea.eth/ponder.config"; | ||
|
||
const plugins = [baseEthPlugin, ethPlugin, lineaEthPlugin] as const; | ||
// list of all available plugins | ||
// any available plugin can be activated at runtime | ||
const availablePlugins = [baseEthPlugin, ethPlugin, lineaEthPlugin] as const; | ||
|
||
// here we export only a single 'plugin's config, by type it as every config | ||
// this makes all of the mapping types happy at typecheck-time, but only the | ||
// relevant config is run at runtime | ||
export default ((): AllConfigs => { | ||
const pluginToActivate = plugins.find((p) => p.ownedName === ACTIVE_PLUGIN); | ||
// merge of all available plugin configs to support correct typechecking | ||
// of the indexing handlers | ||
type AllPluginConfigs = MergedTypes<(typeof availablePlugins)[number]["config"]>; | ||
|
||
if (!pluginToActivate) { | ||
throw new Error(`Unsupported ACTIVE_PLUGIN: ${ACTIVE_PLUGIN}`); | ||
} | ||
// Activates the indexing handlers of activated plugins. | ||
// Statically typed as the merge of all available plugin configs. However at | ||
// runtime returns the merge of all activated plugin configs. | ||
function activatePluginsAndGetConfig(): AllPluginConfigs { | ||
const activePlugins = getActivePlugins(availablePlugins); | ||
|
||
pluginToActivate.activate(); | ||
// load indexing handlers from the active plugins into the runtime | ||
activePlugins.forEach((plugin) => plugin.activate()); | ||
|
||
return pluginToActivate.config as AllConfigs; | ||
})(); | ||
const activePluginsConfig = activePlugins | ||
.map((plugin) => plugin.config) | ||
.reduce((acc, val) => deepMergeRecursive(acc, val), {} as AllPluginConfigs); | ||
|
||
// Helper type to get the intersection of all config types | ||
type IntersectionOf<T> = (T extends any ? (x: T) => void : never) extends (x: infer R) => void | ||
? R | ||
: never; | ||
// The type of the exported default is the intersection of all plugin configs to | ||
// each plugin can be correctly typechecked | ||
type AllConfigs = IntersectionOf<(typeof plugins)[number]["config"]>; | ||
return activePluginsConfig as AllPluginConfigs; | ||
} | ||
|
||
// The type of the default export is a merge of all active plugin configs | ||
// configs so that each plugin can be correctly typechecked | ||
export default activatePluginsAndGetConfig(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.