Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dictionary V2 Ethereum #225

Merged
merged 59 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e348509
move node-core
jiqiang90 Nov 8, 2023
bda0b32
working but need tidy up
jiqiang90 Nov 19, 2023
846ba4f
use EnqueueBlock
jiqiang90 Nov 28, 2023
88d92c2
draft
jiqiang90 Nov 29, 2023
038e1c9
Update packages/node-core/src/indexer/blockDispatcher/block-dispatche…
jiqiang90 Nov 29, 2023
17c1630
draft
jiqiang90 Dec 6, 2023
728ed61
generalization draft
jiqiang90 Dec 21, 2023
0b4cc19
tidy up
jiqiang90 Dec 22, 2023
e4f1c8f
Fix runtime issue
stwiname Dec 22, 2023
47e64e5
working
jiqiang90 Dec 22, 2023
72168b9
rename
jiqiang90 Jan 11, 2024
55ee39a
update interface
jiqiang90 Jan 25, 2024
2a51107
fix v1 tests
jiqiang90 Jan 29, 2024
9e62536
update tests
jiqiang90 Jan 30, 2024
f45529b
update interface and tests
jiqiang90 Feb 2, 2024
37f04cf
fix test and change enqueue type
jiqiang90 Feb 5, 2024
2c8e564
fix modulo and bypass blocks
jiqiang90 Feb 6, 2024
8d1efcb
tidy up
jiqiang90 Feb 6, 2024
370c537
tidy up and more fixes
jiqiang90 Feb 7, 2024
b67e2a6
Update packages/node-core/src/indexer/blockDispatcher/worker-block-di…
jiqiang90 Feb 7, 2024
5d0e44c
Update packages/node-core/src/indexer/blockDispatcher/worker-block-di…
jiqiang90 Feb 7, 2024
1d5b631
Fix part 1
jiqiang90 Feb 8, 2024
a8b7a4b
Fix part 2
jiqiang90 Feb 8, 2024
f858c10
Update packages/node/src/indexer/dictionary/v2/ethDictionaryV2.ts
jiqiang90 Feb 8, 2024
a65f951
Update packages/node/src/indexer/dictionary/v2/types.ts
jiqiang90 Feb 8, 2024
eddc760
Update packages/node/src/indexer/dictionary/v2/ethDictionaryV2.ts
jiqiang90 Feb 8, 2024
8e90675
Fix part 3
jiqiang90 Feb 12, 2024
7757340
Fix part 4
jiqiang90 Feb 12, 2024
b04df53
Fix part 5
jiqiang90 Feb 13, 2024
df186af
Fix worker fetching
jiqiang90 Feb 13, 2024
c7ee51e
Add feature disable dictionary, timeout inspection query
jiqiang90 Feb 13, 2024
4151e83
private getDictionary
jiqiang90 Feb 15, 2024
5fa4c83
Fix part 6
jiqiang90 Feb 15, 2024
4703a9c
Fix update v2 metadata when getData
jiqiang90 Feb 15, 2024
2d5dd39
other fixes
jiqiang90 Feb 19, 2024
9400555
other fixes
jiqiang90 Feb 29, 2024
c6067ca
remove node-core, update dependencies
jiqiang90 Mar 12, 2024
3299f75
Merge remote-tracking branch 'origin/main' into dictionary-v2-poc-gen…
jiqiang90 Mar 12, 2024
09aefcb
update
jiqiang90 Mar 12, 2024
4254f60
remove FAT
jiqiang90 Mar 12, 2024
48184c1
fix formatter
jiqiang90 Mar 13, 2024
d4fe14e
Update packages/node/src/ethereum/utils.ethereum.ts
jiqiang90 Mar 14, 2024
f72e39f
tidy up
jiqiang90 Mar 14, 2024
b3cb703
Merge remote-tracking branch 'origin/dictionary-v2-poc-generalization…
jiqiang90 Mar 14, 2024
01cfd7d
fix isFullBlock
jiqiang90 Mar 17, 2024
e031b3f
Merge remote-tracking branch 'origin/main' into dictionary-v2-poc-gen…
jiqiang90 Mar 17, 2024
c0442b7
fix node-core version
jiqiang90 Mar 17, 2024
acf53f5
Update packages/node/src/indexer/dictionary/v2/ethDictionaryV2.ts
jiqiang90 Mar 18, 2024
0e73132
Update packages/node/src/indexer/dictionary/v1/ethDictionaryV1.ts
jiqiang90 Mar 18, 2024
5fba295
Fix1
jiqiang90 Mar 19, 2024
8d1e95f
Merge remote-tracking branch 'origin/dictionary-v2-poc-generalization…
jiqiang90 Mar 19, 2024
73b2bb9
tests
jiqiang90 Mar 19, 2024
b1c32ca
Fix2
jiqiang90 Mar 20, 2024
ae8ad1d
tidy up
jiqiang90 Mar 20, 2024
0939862
sync up
jiqiang90 Mar 20, 2024
2ff323d
fix dependencies
jiqiang90 Mar 20, 2024
d934910
fix dependencies
jiqiang90 Mar 21, 2024
1943764
fix tests
jiqiang90 Mar 21, 2024
09973bd
Fix converting dict block to eth block, add tests (#265)
stwiname Mar 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
*.tgz
*.cmd
*.sh
generate-project*.yaml
*.proto
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ module.exports = {
// moduleNameMapper: {},
moduleNameMapper: {
'@subql/common-ethereum': '<rootDir>/packages/common-ethereum/src',
'@subql/types-ethereum': '<rootDir>/packages/types/src',
'@subql/types-ethereum': '<rootDir>/packages/types/src'
},

// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
Expand Down
5 changes: 2 additions & 3 deletions packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@nestjs/schedule": "^3.0.1",
"@subql/common": "^3.4.1",
"@subql/common-ethereum": "workspace:*",
"@subql/node-core": "^7.4.1",
"@subql/node-core": "7.4.2-0",
"@subql/testing": "^2.1.0",
"@subql/types-ethereum": "workspace:*",
"cacheable-lookup": "6",
Expand Down Expand Up @@ -65,6 +65,5 @@
"files": [
"/dist",
"/bin"
],
"stableVersion": "3.9.1"
]
}
12 changes: 8 additions & 4 deletions packages/node/src/ethereum/api.connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import {
RateLimitError,
TimeoutError,
IApiConnectionSpecific,
IBlock,
} from '@subql/node-core';
import { EthereumBlock, LightEthereumBlock } from '@subql/types-ethereum';
import { EthereumApi } from './api.ethereum';
import SafeEthProvider from './safe-api';

export type FetchFunc =
| ((api: EthereumApi, batch: number[]) => Promise<EthereumBlock[]>)
| ((api: EthereumApi, batch: number[]) => Promise<LightEthereumBlock[]>);
| ((api: EthereumApi, batch: number[]) => Promise<IBlock<EthereumBlock>[]>)
| ((
api: EthereumApi,
batch: number[],
) => Promise<IBlock<LightEthereumBlock>[]>);

// We use a function to get the fetch function because it can change depending on the skipBlocks feature
export type GetFetchFunc = () => FetchFunc;
Expand All @@ -28,7 +32,7 @@ export class EthereumApiConnection
IApiConnectionSpecific<
EthereumApi,
SafeEthProvider,
EthereumBlock[] | LightEthereumBlock[]
IBlock<EthereumBlock>[] | IBlock<LightEthereumBlock>[]
>
{
readonly networkMeta: NetworkMetadataPayload;
Expand Down Expand Up @@ -77,7 +81,7 @@ export class EthereumApiConnection

async fetchBlocks(
heights: number[],
): Promise<EthereumBlock[] | LightEthereumBlock[]> {
): Promise<IBlock<EthereumBlock>[] | IBlock<LightEthereumBlock>[]> {
const blocks = await this.fetchBlocksBatches()(this.unsafeApi, heights);
return blocks;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/node/src/ethereum/api.ethereum.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('Api.ethereum', () => {
const fetchBlock = async (height: number) => {
const block = await ethApi.fetchBlock(height);

return block as EthereumBlock;
return block.block as EthereumBlock;
};

beforeEach(async () => {
Expand Down
47 changes: 26 additions & 21 deletions packages/node/src/ethereum/api.ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '@ethersproject/abstract-provider';
import { WebSocketProvider } from '@ethersproject/providers';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { getLogger, timeout } from '@subql/node-core';
import { getLogger, IBlock, timeout } from '@subql/node-core';
import {
ApiWrapper,
EthereumBlock,
Expand All @@ -40,6 +40,7 @@ import { ConnectionInfo } from './ethers/web';
import SafeEthProvider from './safe-api';
import {
formatBlock,
formatBlockUtil,
formatLog,
formatReceipt,
formatTransaction,
Expand Down Expand Up @@ -279,7 +280,10 @@ export class EthereumApi implements ApiWrapper {
return this.client.getBlock(heightOrHash);
}

private async getBlockPromise(num: number, includeTx = true): Promise<any> {
private async getBlockPromise(
num: number,
includeTx = true,
): Promise<IBlock<any>> {
const rawBlock = await this.client.send('eth_getBlockByNumber', [
hexValue(num),
includeTx,
Expand All @@ -288,11 +292,8 @@ export class EthereumApi implements ApiWrapper {
if (!rawBlock) {
throw new Error(`Failed to fetch block ${num}`);
}

const block = formatBlock(rawBlock);

block.stateRoot = this.client.formatter.hash(block.stateRoot);

const block = formatBlockUtil(formatBlock(rawBlock));
block.block.stateRoot = this.client.formatter.hash(block.block.stateRoot);
return block;
}

Expand All @@ -304,27 +305,29 @@ export class EthereumApi implements ApiWrapper {
);
}

async fetchBlock(blockNumber: number): Promise<EthereumBlock> {
async fetchBlock(blockNumber: number): Promise<IBlock<EthereumBlock>> {
try {
const block = await this.getBlockPromise(blockNumber, true);
const logsRaw = await this.client.getLogs({ blockHash: block.hash });
const logsRaw = await this.client.getLogs({
blockHash: block.block.hash,
});

// Certain RPC may not accommodate for blockHash, and would return wrong logs
if (logsRaw.length) {
assert(
logsRaw.every((l) => l.blockHash === block.hash),
logsRaw.every((l) => l.blockHash === block.block.hash),
`Log BlockHash does not match block: ${blockNumber}`,
);
}

block.logs = logsRaw.map((l) => formatLog(l, block));
block.transactions = block.transactions.map((tx) => ({
...formatTransaction(tx, block),
block.block.logs = logsRaw.map((l) => formatLog(l, block.block));
block.block.transactions = block.block.transactions.map((tx) => ({
...formatTransaction(tx, block.block),
receipt: () =>
this.getTransactionReceipt(tx.hash).then((r) =>
formatReceipt(r, block),
formatReceipt(r, block.block),
),
logs: block.logs.filter((l) => l.transactionHash === tx.hash),
logs: block.block.logs.filter((l) => l.transactionHash === tx.hash),
}));

this.eventEmitter.emit('fetchBlock');
Expand All @@ -336,23 +339,26 @@ export class EthereumApi implements ApiWrapper {

private async fetchLightBlock(
blockNumber: number,
): Promise<LightEthereumBlock> {
): Promise<IBlock<LightEthereumBlock>> {
const block = await this.getBlockPromise(blockNumber, false);
const logs = await this.client.getLogs({ blockHash: block.hash });
const logs = await this.client.getLogs({ blockHash: block.block.hash });

return {
block: {
logs: logs.map((l) => formatLog(l, block.block)),
...block.block,
},
...block,
logs: logs.map((l) => formatLog(l, block)),
};
}

async fetchBlocks(bufferBlocks: number[]): Promise<EthereumBlock[]> {
async fetchBlocks(bufferBlocks: number[]): Promise<IBlock<EthereumBlock>[]> {
return Promise.all(bufferBlocks.map(async (num) => this.fetchBlock(num)));
}

async fetchBlocksLight(
bufferBlocks: number[],
): Promise<LightEthereumBlock[]> {
): Promise<IBlock<LightEthereumBlock>[]> {
return Promise.all(
bufferBlocks.map(async (num) => this.fetchLightBlock(num)),
);
Expand Down Expand Up @@ -449,7 +455,6 @@ export class EthereumApi implements ApiWrapper {
)) as Array<EthereumLog | EthereumLog<T>>);

transaction.args = args;

return transaction;
} catch (e) {
logger.warn(`Failed to parse transaction data: ${e.message}`);
Expand Down
7 changes: 4 additions & 3 deletions packages/node/src/ethereum/api.service.ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
getLogger,
NodeConfig,
profilerWrap,
IBlock,
} from '@subql/node-core';
import {
EthereumBlock,
Expand All @@ -32,7 +33,7 @@ const logger = getLogger('api');
export class EthereumApiService extends ApiService<
EthereumApi,
SafeEthProvider,
EthereumBlock[] | LightEthereumBlock[]
IBlock<EthereumBlock>[] | IBlock<LightEthereumBlock>[]
> {
private fetchBlocksFunction: FetchFunc;
private fetchBlocksBatches: GetFetchFunc = () => this.fetchBlocksFunction;
Expand Down Expand Up @@ -159,14 +160,14 @@ export class EthereumApiService extends ApiService<
private async fetchFullBlocksBatch(
api: EthereumApi,
batch: number[],
): Promise<EthereumBlock[]> {
): Promise<IBlock<EthereumBlock>[]> {
return api.fetchBlocks(batch);
}

private async fetchLightBlocksBatch(
api: EthereumApi,
batch: number[],
): Promise<LightEthereumBlock[]> {
): Promise<IBlock<LightEthereumBlock>[]> {
return api.fetchBlocksLight(batch);
}

Expand Down
8 changes: 7 additions & 1 deletion packages/node/src/ethereum/block.ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,11 @@ export function filterLogsProcessor(

export function isFullBlock(block: BlockContent): block is EthereumBlock {
// Light etherum block just contains transaction hashes for transactions. If the block has no transactions then both types would be the same
return typeof (block as EthereumBlock).transactions[0] !== 'string';
return (
typeof (block as EthereumBlock).transactions[0] !== 'string' ||
!(
!(block as EthereumBlock).transactions.length &&
(block as EthereumBlock).logs.length
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have tests for this.

);
}
27 changes: 26 additions & 1 deletion packages/node/src/ethereum/utils.ethereum.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors
// SPDX-License-Identifier: GPL-3.0

import { Block } from '@ethersproject/abstract-provider';
import { getAddress } from '@ethersproject/address';
import { BigNumber } from '@ethersproject/bignumber';
import { Zero } from '@ethersproject/constants';
import { Header, IBlock } from '@subql/node-core';
import {
ApiWrapper,
EthereumBlock,
Expand All @@ -13,6 +15,7 @@ import {
EthereumTransaction,
} from '@subql/types-ethereum';
import { omit } from 'lodash';
import { BlockContent } from '../indexer/types';

export function calcInterval(api: ApiWrapper): number {
// TODO find a way to get this from the blockchain
Expand All @@ -26,7 +29,7 @@ function handleAddress(value: string): string | null {
return getAddress(value);
}

function handleNumber(value: string | number): BigNumber {
export function handleNumber(value: string | number): BigNumber {
if (value === undefined) {
return Zero;
}
Expand Down Expand Up @@ -58,6 +61,20 @@ export function formatBlock(block: Record<string, any>): EthereumBlock {
logs: [], // Filled in at AvalancheBlockWrapped constructor
} as EthereumBlock;
}

export function formatBlockUtil(block: EthereumBlock): IBlock<EthereumBlock> {
return {
block,
getHeader: () => {
return {
blockHash: block.hash,
blockHeight: block.number,
parentHash: block.parentHash,
};
},
};
}

export function formatLog(
log: Omit<
EthereumLog<EthereumResult> | EthereumLog,
Expand Down Expand Up @@ -139,3 +156,11 @@ export function formatReceipt<R extends EthereumReceipt = EthereumReceipt>(
},
} as unknown as R;
}

export function ethereumBlockToHeader(block: BlockContent | Block): Header {
return {
blockHeight: block.number,
blockHash: block.hash,
parentHash: block.parentHash,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
StoreCacheService,
StoreService,
IProjectService,
PoiService,
BlockDispatcher,
ProcessBlockResponse,
ApiService,
IProjectUpgradeService,
PoiSyncService,
IBlock,
} from '@subql/node-core';
import {
EthereumProjectDs,
Expand Down Expand Up @@ -63,16 +63,16 @@ export class BlockDispatcherService
);
}

protected getBlockHeight(block: BlockContent): number {
return block.number;
onApplicationShutdown(signal?: string) {
throw new Error('Method not implemented.');
}

protected async indexBlock(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be saved for another PR. But this service has nothing specific to ethereum, it would be good if this could now live purely in node-core. I think only substrate would need a specific version because of specVersions

block: BlockContent,
block: IBlock<BlockContent>,
): Promise<ProcessBlockResponse> {
return this.indexerManager.indexBlock(
block,
await this.projectService.getDataSources(this.getBlockHeight(block)),
await this.projectService.getDataSources(block.getHeader().blockHeight),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors
// SPDX-License-Identifier: GPL-3.0

import { IBlockDispatcher } from '@subql/node-core';
import { IBlockDispatcher, IBlock } from '@subql/node-core';
import { EthereumBlock } from '@subql/types-ethereum';

export interface IEthereumBlockDispatcher extends IBlockDispatcher {
export interface IEthereumBlockDispatcher
extends IBlockDispatcher<EthereumBlock> {
init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;
}
Loading
Loading