Skip to content

Commit

Permalink
Merge branch 'main' into contracts-filter
Browse files Browse the repository at this point in the history
  • Loading branch information
khaidarkairbek authored Dec 29, 2024
2 parents a150566 + 38fa5b5 commit be7a78d
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 34 deletions.
21 changes: 21 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Feature request
description: Request new features or improvements.
body:
- type: markdown
attributes:
value: |
Thanks for completing this feature request form! The more info you provide, the faster we can help you. Before you proceed, please confirm that there isn't [already an issue](https://github.com/ponder-sh/ponder/issues) for this feature request.
- type: textarea
attributes:
label: Problem / use case
description: A description of the problem that the new feature would solve. Please include a real-world example or use case.
validations:
required: true

- type: textarea
attributes:
label: Proposed solution
description: A description of the proposed solution.
validations:
required: false
4 changes: 2 additions & 2 deletions docs/pages/docs/contracts-and-networks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default createConfig({

### Multiple ABIs

It's occasionally useful to provide multiple ABIs for one contract, like when defining a proxy/upgradable contract that has gone through multiple implementation contracts. The [`mergeAbis`](/docs/utilities/abi) utility function safely removes duplicate ABI items and maintains strict types.
It's occasionally useful to provide multiple ABIs for one contract, like when defining a proxy/upgradable contract that has gone through multiple implementation contracts. The [`mergeAbis`](/docs/utilities/merge-abis) utility function safely removes duplicate ABI items and maintains strict types.

```ts filename="ponder.config.ts" {1,14}
import { createConfig, mergeAbis } from "ponder";
Expand Down Expand Up @@ -466,7 +466,7 @@ event ChildCreated(ChildContract child);

### Proxy & upgradable contracts

To index a proxy/upgradable contract, use the proxy contract address in the `address` field. Then, be sure to include the ABIs of all implementation contracts that the proxy has ever had. The implementation ABIs are required to properly identify and decode all historical event logs. To add multiple ABIs safely, use the [`mergeAbis`](/docs/utilities/abi) utility function.
To index a proxy/upgradable contract, use the proxy contract address in the `address` field. Then, be sure to include the ABIs of all implementation contracts that the proxy has ever had. The implementation ABIs are required to properly identify and decode all historical event logs. To add multiple ABIs safely, use the [`mergeAbis`](/docs/utilities/merge-abis) utility function.

<Callout>
Tip: On Etherscan, there is a link to the current implementation contract on the **Contract → Read as Proxy** tab. You can copy all the implementation ABIs as text and paste them into `.ts` files.
Expand Down
14 changes: 14 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# ponder

## 0.8.10

### Patch Changes

- [#1370](https://github.com/ponder-sh/ponder/pull/1370) [`61b0b04c3306929bf2ff1ef781be874f561d8e11`](https://github.com/ponder-sh/ponder/commit/61b0b04c3306929bf2ff1ef781be874f561d8e11) Thanks [@khaidarkairbek](https://github.com/khaidarkairbek)! - Fixed a bug causing future end blocks to error.

## 0.8.9

### Patch Changes

- [#1381](https://github.com/ponder-sh/ponder/pull/1381) [`dae8801ea3ddf732d8284ff84bc7dc21ada22f0e`](https://github.com/ponder-sh/ponder/commit/dae8801ea3ddf732d8284ff84bc7dc21ada22f0e) Thanks [@typedarray](https://github.com/typedarray)! - Fixed a bug where data inserted using raw SQL near the beginning of historical indexing was not found by subsequent `find`, `update`, or `delete` operations using the store/in-memory API.

- [#1375](https://github.com/ponder-sh/ponder/pull/1375) [`1687033a74fb8e7a7d843b4fe1f7f1cd4cf866a9`](https://github.com/ponder-sh/ponder/commit/1687033a74fb8e7a7d843b4fe1f7f1cd4cf866a9) Thanks [@typedarray](https://github.com/typedarray)! - Improved logs for Postgres pool errors.

## 0.8.8

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ponder",
"version": "0.8.8",
"version": "0.8.10",
"description": "An open-source framework for crypto application backends",
"license": "MIT",
"type": "module",
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/_test/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ export async function setupIsolatedDatabase(context: TestContext) {

const client = new pg.Client({ connectionString });
await client.connect();
await client.query(
`
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = $1 AND pid <> pg_backend_pid()
`,
[databaseName],
);
await client.query(`DROP DATABASE IF EXISTS "${databaseName}"`);
await client.query(`CREATE DATABASE "${databaseName}"`);
await client.end();
Expand Down
54 changes: 33 additions & 21 deletions packages/core/src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,27 +216,39 @@ export const createDatabase = ({
: [equalMax, equalMax, equalMax];

driver = {
internal: createPool({
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_internal`,
max: internalMax,
statement_timeout: 10 * 60 * 1000, // 10 minutes to accommodate slow sync store migrations.
}),
user: createPool({
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_user`,
max: userMax,
}),
readonly: createPool({
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_readonly`,
max: readonlyMax,
}),
sync: createPool({
...preBuild.databaseConfig.poolConfig,
application_name: "ponder_sync",
max: syncMax,
}),
internal: createPool(
{
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_internal`,
max: internalMax,
statement_timeout: 10 * 60 * 1000, // 10 minutes to accommodate slow sync store migrations.
},
common.logger,
),
user: createPool(
{
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_user`,
max: userMax,
},
common.logger,
),
readonly: createPool(
{
...preBuild.databaseConfig.poolConfig,
application_name: `${preBuild.namespace}_readonly`,
max: readonlyMax,
},
common.logger,
),
sync: createPool(
{
...preBuild.databaseConfig.poolConfig,
application_name: "ponder_sync",
max: syncMax,
},
common.logger,
),
};

qb = {
Expand Down
35 changes: 35 additions & 0 deletions packages/core/src/indexing-store/historical.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,41 @@ test("sql", async (context) => {
await cleanup();
});

test("sql followed by find", async (context) => {
const schema = {
account: onchainTable("account", (p) => ({
address: p.hex().primaryKey(),
balance: p.bigint().notNull(),
})),
};

const { database, cleanup } = await setupDatabaseServices(context, {
schema,
});

const indexingStore = createHistoricalIndexingStore({
common: context.common,
database,
schema,
initialCheckpoint: encodeCheckpoint(zeroCheckpoint),
});

await indexingStore.sql
.insert(schema.account)
.values({ address: zeroAddress, balance: 10n });

const row = await indexingStore.find(schema.account, {
address: zeroAddress,
});

expect(row).toStrictEqual({
address: zeroAddress,
balance: 10n,
});

await cleanup();
});

test("onchain table", async (context) => {
const { database, cleanup } = await setupDatabaseServices(context);

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/indexing-store/historical.ts
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ export const createHistoricalIndexingStore = ({
await database.createTriggers();
await indexingStore.flush();
await database.removeTriggers();
isDatabaseEmpty = false;

const query: QueryWithTypings = { sql: _sql, params, typings };

Expand Down
18 changes: 14 additions & 4 deletions packages/core/src/sync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
type Transport,
hexToBigInt,
hexToNumber,
toHex,
} from "viem";
import { _eth_getBlockByNumber } from "../utils/rpc.js";
import { type RawEvent, buildEvents } from "./events.js";
Expand Down Expand Up @@ -928,15 +929,24 @@ export const syncDiagnostic = async ({
? undefined
: Math.max(...sources.map(({ filter }) => filter.toBlock!));

const [remoteChainId, startBlock, endBlock, latestBlock] = await Promise.all([
const [remoteChainId, startBlock, latestBlock] = await Promise.all([
requestQueue.request({ method: "eth_chainId" }),
_eth_getBlockByNumber(requestQueue, { blockNumber: start }),
end === undefined
? undefined
: _eth_getBlockByNumber(requestQueue, { blockNumber: end }),
_eth_getBlockByNumber(requestQueue, { blockTag: "latest" }),
]);

const endBlock =
end === undefined
? undefined
: end > hexToBigInt(latestBlock.number)
? ({
number: toHex(end),
hash: "0x",
parentHash: "0x",
timestamp: toHex(maxCheckpoint.blockTimestamp),
} as LightBlock)
: await _eth_getBlockByNumber(requestQueue, { blockNumber: end });

// Warn if the config has a different chainId than the remote.
if (hexToNumber(remoteChainId) !== network.chainId) {
common.logger.warn({
Expand Down
38 changes: 34 additions & 4 deletions packages/core/src/utils/pg.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Logger } from "@/common/logger.js";
import pg, { type PoolConfig } from "pg";
import { prettyPrint } from "./print.js";

Expand Down Expand Up @@ -60,20 +61,49 @@ class ReadonlyClient extends pg.Client {
}
}

export function createPool(config: PoolConfig) {
return new pg.Pool({
function createErrorHandler(logger: Logger) {
return (error: Error) => {
const client = (error as any).client as any | undefined;
const pid = (client?.processID as number | undefined) ?? "unknown";
const applicationName =
(client?.connectionParameters?.application_name as string | undefined) ??
"unknown";

logger.error({
service: "postgres",
msg: `Pool error (application_name: ${applicationName}, pid: ${pid})`,
error,
});

// NOTE: Errors thrown here cause an uncaughtException. It's better to just log and ignore -
// if the underlying problem persists, the process will crash due to downstream effects.
};
}

export function createPool(config: PoolConfig, logger: Logger) {
const pool = new pg.Pool({
// https://stackoverflow.com/questions/59155572/how-to-set-query-timeout-in-relation-to-statement-timeout
statement_timeout: 2 * 60 * 1000, // 2 minutes
...config,
});

const onError = createErrorHandler(logger);
pool.on("error", onError);

return pool;
}

export function createReadonlyPool(config: PoolConfig) {
return new pg.Pool({
export function createReadonlyPool(config: PoolConfig, logger: Logger) {
const pool = new pg.Pool({
// https://stackoverflow.com/questions/59155572/how-to-set-query-timeout-in-relation-to-statement-timeout
statement_timeout: 2 * 60 * 1000, // 2 minutes
// @ts-expect-error: The custom Client is an undocumented option.
Client: ReadonlyClient,
...config,
});

const onError = createErrorHandler(logger);
pool.on("error", onError);

return pool;
}
4 changes: 4 additions & 0 deletions packages/create-ponder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# create-ponder

## 0.8.10

## 0.8.9

## 0.8.8

## 0.8.7
Expand Down
2 changes: 1 addition & 1 deletion packages/create-ponder/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-ponder",
"version": "0.8.8",
"version": "0.8.10",
"type": "module",
"description": "A CLI tool to create Ponder apps",
"license": "MIT",
Expand Down
4 changes: 4 additions & 0 deletions packages/eslint-config-ponder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# eslint-config-ponder

## 0.8.10

## 0.8.9

## 0.8.8

## 0.8.7
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config-ponder/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-ponder",
"version": "0.8.8",
"version": "0.8.10",
"description": "ESLint config for Ponder apps",
"license": "MIT",
"main": "./index.js",
Expand Down

0 comments on commit be7a78d

Please sign in to comment.