From b916e277518a4a162d92a3190e2d6175a0f212e3 Mon Sep 17 00:00:00 2001 From: tate Date: Wed, 13 Dec 2023 11:30:50 +1100 Subject: [PATCH] feat: test-env graphman passthrough + more --- packages/ens-test-env/package.json | 3 +- packages/ens-test-env/src/config.toml | 19 ++++ packages/ens-test-env/src/docker-compose.yml | 2 + packages/ens-test-env/src/execute.cjs | 23 +++++ packages/ens-test-env/src/execute.d.ts | 8 ++ packages/ens-test-env/src/execute.js | 24 +++++ packages/ens-test-env/src/index.js | 1 + packages/ens-test-env/src/manager.js | 1 + .../deploy/02_get_contract_addresses.cjs | 7 +- packages/ensjs/jest.config.js | 2 + packages/ensjs/src/test/usage/helper.ts | 70 +++++++++++++++ .../src/test/usage/ownership.e2e.test.ts | 3 +- .../src/test/usage/registerName.e2e.test.ts | 6 +- .../src/test/usage/setRecords.e2e.test.ts | 87 ++++++++++--------- 14 files changed, 208 insertions(+), 48 deletions(-) create mode 100644 packages/ens-test-env/src/config.toml create mode 100644 packages/ens-test-env/src/execute.cjs create mode 100644 packages/ens-test-env/src/execute.d.ts create mode 100644 packages/ens-test-env/src/execute.js diff --git a/packages/ens-test-env/package.json b/packages/ens-test-env/package.json index 8668e184..8f730efb 100644 --- a/packages/ens-test-env/package.json +++ b/packages/ens-test-env/package.json @@ -5,7 +5,8 @@ "files": [ "src" ], - "types": "src/index.d.ts", + "types": "src/execute.d.ts", + "module": "src/execute.js", "scripts": { "prepublish": "cp ../../LICENSE ./", "ver": "pnpm version --no-workspaces-update" diff --git a/packages/ens-test-env/src/config.toml b/packages/ens-test-env/src/config.toml new file mode 100644 index 00000000..80cd8dc3 --- /dev/null +++ b/packages/ens-test-env/src/config.toml @@ -0,0 +1,19 @@ +[store] +[store.primary] +connection = "postgresql://graph-node:let-me-in@postgres:5432/graph-node" +pool_size = 10 + +[deployment] +[[deployment.rule]] +indexers = ["index_node_1"] + +[chains] +ingestor = "index_0" +[chains.mainnet] +shard = "primary" +provider = [ + { label = "mainnet-rpc-0", url = "http://anvil:8545", features = [ + "archive", + "traces", + ] }, +] diff --git a/packages/ens-test-env/src/docker-compose.yml b/packages/ens-test-env/src/docker-compose.yml index 3cf5c7fa..104f799f 100644 --- a/packages/ens-test-env/src/docker-compose.yml +++ b/packages/ens-test-env/src/docker-compose.yml @@ -31,6 +31,8 @@ services: GRAPH_ETHEREUM_CLEANUP_BLOCKS: 'true' extra_hosts: - 'host.docker.internal:host-gateway' + volumes: + - $GRAPH_CONFIG_FILE:/opt/graph-node/config.toml ipfs: image: ipfs/kubo:v0.16.0 ports: diff --git a/packages/ens-test-env/src/execute.cjs b/packages/ens-test-env/src/execute.cjs new file mode 100644 index 00000000..4b2bd352 --- /dev/null +++ b/packages/ens-test-env/src/execute.cjs @@ -0,0 +1,23 @@ +/* eslint-disable */ +const compose = require('docker-compose') +const path = require('path') + +const rewindSubgraph = async ({ blockNumber, blockHash }) => { + const dockerComposeFile = path.resolve(__dirname, './docker-compose.yml') + const composeOpts = { + log: true, + composeOptions: ['-p', 'ens-test-env'], + config: dockerComposeFile, + } + const items = await compose.ps({ ...composeOpts, log: false }) + if (items.data.services.length === 0) { + throw new Error('No services running') + } + await compose.exec( + 'graph-node', + `graphman --config /opt/graph-node/config.toml rewind ${blockHash} ${blockNumber} graphprotocol/ens --force --sleep 1`, + composeOpts, + ) +} + +module.exports.rewindSubgraph = rewindSubgraph diff --git a/packages/ens-test-env/src/execute.d.ts b/packages/ens-test-env/src/execute.d.ts new file mode 100644 index 00000000..a6e477ca --- /dev/null +++ b/packages/ens-test-env/src/execute.d.ts @@ -0,0 +1,8 @@ +/* eslint-disable */ +export const rewindSubgraph = async ({ + blockNumber, + blockHash, +}: { + blockNumber: number + blockHash: `0x${string}` +}) => Promise diff --git a/packages/ens-test-env/src/execute.js b/packages/ens-test-env/src/execute.js new file mode 100644 index 00000000..0d913903 --- /dev/null +++ b/packages/ens-test-env/src/execute.js @@ -0,0 +1,24 @@ +/* eslint-disable */ +import compose from 'docker-compose' +import path from 'path' +import { URL as URLClass } from 'url' + +const __dirname = new URLClass('.', import.meta.url).pathname + +export const rewindSubgraph = async ({ blockNumber, blockHash }) => { + const dockerComposeFile = path.resolve(__dirname, './docker-compose.yml') + const composeOpts = { + log: true, + composeOptions: ['-p', 'ens-test-env'], + config: dockerComposeFile, + } + const items = await compose.ps({ ...composeOpts, log: false }) + if (items.data.services.length === 0) { + throw new Error('No services running') + } + await compose.exec( + 'graph-node', + `graphman --config /opt/graph-node/config.toml rewind ${blockHash} ${blockNumber} graphprotocol/ens --force --sleep 1`, + composeOpts, + ) +} diff --git a/packages/ens-test-env/src/index.js b/packages/ens-test-env/src/index.js index 9e3aa3df..0436f789 100755 --- a/packages/ens-test-env/src/index.js +++ b/packages/ens-test-env/src/index.js @@ -56,6 +56,7 @@ program data: path.resolve(cwd, './data'), archive: path.resolve(cwd, './archive'), composeFile: path.resolve(__dirname, './docker-compose.yml'), + graphConfigFile: path.resolve(__dirname, './config.toml'), } const configPaths = config.paths || {} for (const [key, value] of Object.entries(configPaths)) { diff --git a/packages/ens-test-env/src/manager.js b/packages/ens-test-env/src/manager.js index 7fd9bb40..4e60560f 100644 --- a/packages/ens-test-env/src/manager.js +++ b/packages/ens-test-env/src/manager.js @@ -159,6 +159,7 @@ export const main = async (_config, _options, justKill) => { opts.env = { ...process.env, DATA_FOLDER: config.paths.data, + GRAPH_CONFIG_FILE: config.paths.graphConfigFile, GRAPH_LOG_LEVEL: 'info', ANVIL_EXTRA_ARGS: '', BLOCK_TIMESTAMP: Math.floor(new Date().getTime() / 1000), diff --git a/packages/ensjs/deploy/02_get_contract_addresses.cjs b/packages/ensjs/deploy/02_get_contract_addresses.cjs index c090f8da..f47cf0e3 100644 --- a/packages/ensjs/deploy/02_get_contract_addresses.cjs +++ b/packages/ensjs/deploy/02_get_contract_addresses.cjs @@ -14,9 +14,14 @@ const func = async function (hre) { ]), ) + const block = await hre.ethers.provider.getBlock() + await writeFile( resolve(__dirname, '../.env.local'), - `DEPLOYMENT_ADDRESSES='${JSON.stringify(deploymentAddressMap)}'`, + `DEPLOYMENT_ADDRESSES='${JSON.stringify(deploymentAddressMap)}' +DEPLOYMENT_FINISHED_AT_BLOCK=${block.number} +DEPLOYMENT_FINISHED_AT_HASH=${block.hash} +`, ) console.log('Wrote contract addresses to .env.local') diff --git a/packages/ensjs/jest.config.js b/packages/ensjs/jest.config.js index f0dcc98e..4006f31f 100644 --- a/packages/ensjs/jest.config.js +++ b/packages/ensjs/jest.config.js @@ -12,6 +12,8 @@ const config = { '^(\\.{1,2}/.*)\\.js$': '$1', '^multiformats$': '/node_modules/multiformats/src/index.js', '^multiformats/(.*)$': '/node_modules/multiformats/src/$1', + '^@ensdomains/ens-test-env$': + '/node_modules/@ensdomains/ens-test-env/src/execute.cjs', }, } diff --git a/packages/ensjs/src/test/usage/helper.ts b/packages/ensjs/src/test/usage/helper.ts index 9ad640f9..09242cfa 100644 --- a/packages/ensjs/src/test/usage/helper.ts +++ b/packages/ensjs/src/test/usage/helper.ts @@ -1,6 +1,8 @@ +import { rewindSubgraph } from '@ensdomains/ens-test-env' import getPrice from '../../functions/public/getPrice.js' import commitName from '../../functions/wallet/commitName.js' import registerName from '../../functions/wallet/registerName.js' +import { createSubgraphClient } from '../../subgraph.js' import type { RegistrationParameters } from '../../utils/registerHelpers.js' import { publicClient, @@ -49,3 +51,71 @@ export const wait = (ms: number) => new Promise((resolve) => { setTimeout(resolve, ms) }) + +const subgraphClient = createSubgraphClient({ client: publicClient }) + +export const getSubgraphBlock = ( + { depth }: { depth: number } = { depth: 0 }, +): Promise => + subgraphClient + .request<{ + _meta: { + block: { + number: number + } + } + }>( + ` + { + _meta { + block { + number + } + } + } +`, + ) + .then((res) => res._meta.block.number) + .catch(async (e) => { + console.error(e) + await wait(1000) + if (depth > 5) throw new Error('Could not get subgraph block') + return getSubgraphBlock({ depth: depth + 1 }) + }) + +export const getCurrentBlock = () => + publicClient.getBlockNumber().then((b) => Number(b)) + +export const syncSubgraphBlock = async ( + { + depth, + changes, + prevSubgraphBlock, + }: { depth: number; changes: number; prevSubgraphBlock: number } = { + depth: 0, + changes: 0, + prevSubgraphBlock: 0, + }, +): Promise => { + const subgraphBlock = await getSubgraphBlock() + const currentBlock = await getCurrentBlock() + if (subgraphBlock < currentBlock) { + const params = { + depth: depth + 1, + changes: changes + (subgraphBlock !== prevSubgraphBlock ? 1 : 0), + prevSubgraphBlock: subgraphBlock, + } + await wait(1000) + return syncSubgraphBlock(params) + } + if (subgraphBlock >= currentBlock && depth === 0) { + const blockNumber = parseInt( + process.env.DEPLOYMENT_FINISHED_AT_BLOCK as string, + ) + const blockHash = process.env.DEPLOYMENT_FINISHED_AT_HASH as `0x${string}` + await rewindSubgraph({ blockNumber, blockHash }) + await wait(1000) + return syncSubgraphBlock() + } + return +} diff --git a/packages/ensjs/src/test/usage/ownership.e2e.test.ts b/packages/ensjs/src/test/usage/ownership.e2e.test.ts index 57fcead8..3d38ccab 100644 --- a/packages/ensjs/src/test/usage/ownership.e2e.test.ts +++ b/packages/ensjs/src/test/usage/ownership.e2e.test.ts @@ -14,7 +14,7 @@ import { } from '../../test/addTestContracts.js' import { encodeAbi } from '../../utils/index.js' import type { RegistrationParameters } from '../../utils/registerHelpers.js' -import { commitAndRegisterName } from './helper.js' +import { commitAndRegisterName, syncSubgraphBlock } from './helper.js' let snapshot: Hex let accounts: Address[] @@ -27,6 +27,7 @@ beforeAll(async () => { beforeEach(async () => { snapshot = await testClient.snapshot() + await syncSubgraphBlock() }) afterEach(async () => { diff --git a/packages/ensjs/src/test/usage/registerName.e2e.test.ts b/packages/ensjs/src/test/usage/registerName.e2e.test.ts index 2d8c81ca..74943ad2 100644 --- a/packages/ensjs/src/test/usage/registerName.e2e.test.ts +++ b/packages/ensjs/src/test/usage/registerName.e2e.test.ts @@ -31,7 +31,7 @@ import { import { encodeAbi } from '../../utils/index.js' import { namehash } from '../../utils/normalise.js' import type { RegistrationParameters } from '../../utils/registerHelpers.js' -import { commitAndRegisterName, wait } from './helper.js' +import { commitAndRegisterName, syncSubgraphBlock } from './helper.js' let snapshot: Hex let accounts: Address[] @@ -43,6 +43,7 @@ beforeAll(async () => { beforeEach(async () => { snapshot = await testClient.snapshot() + await syncSubgraphBlock() }) afterEach(async () => { @@ -712,7 +713,8 @@ it.only('Register - Renew Name - Add Subname - Expire Subname - Create Subname', testClient.increaseTime({ seconds: 61 }) testClient.mine({ blocks: 1 }) - await wait(30_000) + await syncSubgraphBlock() + const result = await getSubnames(publicClient, { name: params.name, pageSize: 1000, diff --git a/packages/ensjs/src/test/usage/setRecords.e2e.test.ts b/packages/ensjs/src/test/usage/setRecords.e2e.test.ts index 63654ee2..fc0f021e 100644 --- a/packages/ensjs/src/test/usage/setRecords.e2e.test.ts +++ b/packages/ensjs/src/test/usage/setRecords.e2e.test.ts @@ -11,7 +11,7 @@ import { waitForTransaction, walletClient, } from '../addTestContracts.js' -import { commitAndRegisterName, wait } from './helper.js' +import { commitAndRegisterName, syncSubgraphBlock } from './helper.js' let snapshot: Hex let accounts: Address[] @@ -23,6 +23,7 @@ beforeAll(async () => { beforeEach(async () => { snapshot = await testClient.snapshot() + await syncSubgraphBlock() }) afterEach(async () => { @@ -81,6 +82,8 @@ it('should return a transaction to the resolver and update successfully', async expect(receipt.status).toBe('success') await testClient.mine({ blocks: 1 }) + const newAbi = [...dummyABI, { stateMutability: 'readonly' }] as const + const utx = await setRecords(walletClient, { name, resolverAddress: (await getResolver(publicClient, { @@ -95,7 +98,7 @@ it('should return a transaction to the resolver and update successfully', async texts: [{ key: 'foo', value: 'bars' }], abi: await encodeAbi({ encodeAs: 'json', - data: [...dummyABI, { stateMutability: 'readonly' }], + data: newAbi, }), contentHash: 'ipns://k51qzi5uqu5dgox2z23r6e99oqency055a6xt92xzmyvpz8mwz5ycjavm0u150', @@ -115,21 +118,18 @@ it('should return a transaction to the resolver and update successfully', async }, }) expect(records.contentHash).toMatchInlineSnapshot(` - { - "decoded": "k51qzi5uqu5dgox2z23r6e99oqency055a6xt92xzmyvpz8mwz5ycjavm0u150", - "protocolType": "ipns", - } -`) - expect(records.abi!.abi).toStrictEqual([ - ...dummyABI, - { stateMutability: 'readonly' }, - ]) + { + "decoded": "k51qzi5uqu5dgox2z23r6e99oqency055a6xt92xzmyvpz8mwz5ycjavm0u150", + "protocolType": "ipns", + } + `) + expect(records.abi!.abi).toStrictEqual(newAbi) expect(records.coins).toMatchInlineSnapshot(` [ { "id": 61, "name": "etcLegacy", - "value": "${accounts[1]}", + "value": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", }, ] `) @@ -197,7 +197,6 @@ it('should return a transaction to the resolver and remove successfully', async contentHash: true, }, }) - console.log(records) expect(records.contentHash).toBeNull() // expect(records.abi!.abi).toMatchInlineSnapshot(`abi: { contentType: 1, decoded: true, abi: [ [Object] ] }`) expect(records.coins).toMatchInlineSnapshot(`[]`) @@ -255,13 +254,12 @@ it('should return a transaction to the resolver and ignore undefined', async () contentHash: true, }, }) - console.log(records) expect(records.coins).toMatchInlineSnapshot(`[]`) expect(records.texts).toMatchInlineSnapshot(`[]`) expect(records.contentHash).not.toBeNull() expect(records.abi).not.toBeNull() }) -it.skip('should return a transaction to the resolver and retrieve multiple keys successfully', async () => { +it('should return a transaction to the resolver and retrieve multiple keys successfully', async () => { // generate random name const name = `test${Math.floor(Math.random() * 1000000)}.eth` const params: RegistrationParameters = { @@ -299,16 +297,13 @@ it.skip('should return a transaction to the resolver and retrieve multiple keys expect(tx).toBeTruthy() const receipt = await waitForTransaction(tx) expect(receipt.status).toBe('success') - await testClient.mine({ blocks: 1 }) - // set a wait time here - await wait(30000) + await syncSubgraphBlock() const result = await getSubgraphRecords(publicClient, { name, }) expect(result).toBeTruthy() const { createdAt, ...rest } = result! - console.log(rest) expect(rest).toMatchInlineSnapshot(` { "coins": [ @@ -344,15 +339,12 @@ it.skip('should return a transaction to the resolver and retrieve multiple keys const ureceipt = await waitForTransaction(utx) expect(ureceipt.status).toBe('success') - // set a wait time here - await wait(5000) + await syncSubgraphBlock() const newResult = await getSubgraphRecords(publicClient, { name, }) expect(result).toBeTruthy() - console.log(newResult) - const records = await getRecords(publicClient, { name, records: { @@ -362,37 +354,46 @@ it.skip('should return a transaction to the resolver and retrieve multiple keys abi: true, }, }) - console.log(records) expect(records.contentHash).toMatchInlineSnapshot(` - { - "decoded": "bafybeico3uuyj3vphxpvbowchdwjlrlrh62awxscrnii7w7flu5z6fk77y", - "protocolType": "ipfs", - } -`) - expect(records.abi!.abi).toStrictEqual([ - ...dummyABI, - { stateMutability: 'readonly' }, - ]) + { + "decoded": "bafybeico3uuyj3vphxpvbowchdwjlrlrh62awxscrnii7w7flu5z6fk77y", + "protocolType": "ipfs", + } + `) + expect(records.abi!.abi).toStrictEqual(dummyABI) expect(records.coins).toMatchInlineSnapshot(` [ { - id: 501, - name: 'sol', - value: 'HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH' + "id": 501, + "name": "sol", + "value": "HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH", }, { - id: 60, - name: 'eth', - value: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' + "id": 60, + "name": "eth", + "value": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + }, + { + "id": 0, + "name": "btc", + "value": "1PzAJcFtEiXo9UGtRU6iqXQKj8NXtcC7DE", }, - { id: 0, name: 'btc', value: '1PzAJcFtEiXo9UGtRU6iqXQKj8NXtcC7DE' } ] `) expect(records.texts).toMatchInlineSnapshot(` [ - { key: 'name', value: 'e2e' }, - { key: 'location', value: 'metaverse' }, - { key: 'description', value: 'e2e' } + { + "key": "name", + "value": "e2e", + }, + { + "key": "location", + "value": "metaverse", + }, + { + "key": "description", + "value": "e2e", + }, ] `) })