Skip to content

Commit

Permalink
WIP correcting types and event parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
stwiname committed Jul 18, 2024
1 parent 9c0afe0 commit 6601e48
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 75 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"ts-loader": "^9.2.6",
"ts-node": "^10.4.0",
"tsconfig-paths": "^3.12.0",
"typescript": "^4.9.5"
"typescript": "^5.5.3"
},
"resolutions": {
"node-fetch": "2.6.7"
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/indexer/api.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe('ApiService', () => {

expect(rpcFetchSpy).toHaveBeenCalledTimes(1);
});

it.skip('query block info', async () => {
await prepareApiService(ENDPOINT, CHAINID, tmpPath);

Expand Down
11 changes: 4 additions & 7 deletions packages/node/src/indexer/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import { Uint53 } from '@cosmjs/math';
import { GeneratedType, Registry } from '@cosmjs/proto-signing';
import { Block, defaultRegistryTypes, SearchTxQuery } from '@cosmjs/stargate';
import { CometClient, toRfc3339WithNanoseconds } from '@cosmjs/tendermint-rpc';
import {
BlockResponse,
BlockResultsResponse,
Validator,
} from '@cosmjs/tendermint-rpc/build/tendermint37/responses';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { CosmosProjectNetConfig } from '@subql/common-cosmos';
Expand All @@ -36,7 +31,7 @@ import { SubqueryProject } from '../configure/SubqueryProject';
import * as CosmosUtil from '../utils/cosmos';
import { KyveApi } from '../utils/kyve/kyve';
import { CosmosClientConnection } from './cosmosClient.connection';
import { BlockContent } from './types';
import { BlockContent, BlockResponse, BlockResultsResponse } from './types';

const logger = getLogger('api');

Expand Down Expand Up @@ -257,7 +252,9 @@ export class CosmosSafeClient
};
}

async validators(): Promise<readonly Validator[]> {
async validators(): Promise<
Awaited<ReturnType<CometClient['validators']>>['validators']
> {
return (
await this.forceGetCometClient().validators({
height: this.height,
Expand Down
2 changes: 1 addition & 1 deletion packages/node/src/indexer/cosmosClient.connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const logger = getLogger('CosmosClientConnection');
/**
* Auto-detects the version of the backend and uses a suitable client.
*/
export async function connectComet(
async function connectComet(
client: WebsocketClient | HttpClient,
): Promise<CometClient> {
// Tendermint/CometBFT 0.34/0.37/0.38 auto-detection. Starting with 0.37 we seem to get reliable versions again 🎉
Expand Down
20 changes: 18 additions & 2 deletions packages/node/src/indexer/types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors
// SPDX-License-Identifier: GPL-3.0

import type {
tendermint34,
tendermint37,
comet38,
} from '@cosmjs/tendermint-rpc';
import {
CosmosBlock,
CosmosEvent,
CosmosTransaction,
CosmosMessage,
} from '@subql/types-cosmos';

export type BlockResponse =
| tendermint34.BlockResponse
| tendermint37.BlockResponse
| comet38.BlockResponse;
export type BlockResultsResponse =
| tendermint34.BlockResultsResponse
| tendermint37.BlockResultsResponse
| comet38.BlockResultsResponse;

export interface BlockContent {
block: CosmosBlock;
transactions: CosmosTransaction[];
messages: CosmosMessage[];
events: CosmosEvent[];
beginBlockEvents: CosmosEvent[];
endBlockEvents: CosmosEvent[];
beginBlockEvents?: CosmosEvent[];
endBlockEvents?: CosmosEvent[];
/* From Cosmos 0.50/Comet0.38 this replaces beginBlockEvents/endBlockEvents */
finalizedBlockEvents?: CosmosEvent[];
}

export type BestBlocks = Record<number, string>;
64 changes: 58 additions & 6 deletions packages/node/src/utils/cosmos.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import {
decodeTxRaw,
DecodedTxRaw,
} from '@cosmjs/proto-signing';
import { defaultRegistryTypes } from '@cosmjs/stargate';
import { Tendermint37Client } from '@cosmjs/tendermint-rpc';
import { Block, defaultRegistryTypes } from '@cosmjs/stargate';
import { connectComet, CometClient } from '@cosmjs/tendermint-rpc';
import { IBlock } from '@subql/node-core';
import {
CosmosMessageFilter,
CosmosBlock,
Expand All @@ -25,8 +26,13 @@ import {
} from 'cosmjs-types/cosmwasm/wasm/v1/tx';
import { isLong, fromInt } from 'long';
import { CosmosClient } from '../indexer/api.service';
import { HttpClient } from '../indexer/rpc-clients';
import { decodeMsg, filterMessageData, wrapEvent } from './cosmos';
import { BlockContent } from '../indexer/types';
import {
decodeMsg,
fetchBlocksBatches,
filterMessageData,
wrapEvent,
} from './cosmos';

const ENDPOINT = 'https://rpc.mainnet.archway.io';

Expand Down Expand Up @@ -88,8 +94,7 @@ describe('CosmosUtils', () => {
let msg: CosmosMessage;

beforeAll(async () => {
const client = new HttpClient(ENDPOINT);
const tendermint = await Tendermint37Client.create(client);
const tendermint = await connectComet(ENDPOINT);
const wasmTypes: ReadonlyArray<[string, GeneratedType]> = [
['/cosmwasm.wasm.v1.MsgClearAdmin', MsgClearAdmin],
['/cosmwasm.wasm.v1.MsgExecuteContract', MsgExecuteContract],
Expand Down Expand Up @@ -334,3 +339,50 @@ describe('CosmosUtils', () => {
api.disconnect();
});
});

describe('Cosmos 0.50 support', () => {
let api: CosmosClient;
let client: CometClient;
let block: IBlock<BlockContent>;

beforeAll(async () => {
client = await connectComet('https://rpc.neutron.quokkastake.io');
const wasmTypes: ReadonlyArray<[string, GeneratedType]> = [
['/cosmwasm.wasm.v1.MsgClearAdmin', MsgClearAdmin],
['/cosmwasm.wasm.v1.MsgExecuteContract', MsgExecuteContract],
['/cosmwasm.wasm.v1.MsgMigrateContract', MsgMigrateContract],
['/cosmwasm.wasm.v1.MsgStoreCode', MsgStoreCode],
['/cosmwasm.wasm.v1.MsgInstantiateContract', MsgInstantiateContract],
['/cosmwasm.wasm.v1.MsgUpdateAdmin', MsgUpdateAdmin],
];

const registry = new Registry([...defaultRegistryTypes, ...wasmTypes]);
api = new CosmosClient(client, registry);

const blocks = await fetchBlocksBatches(api, [12_495_419]);
block = blocks[0];
});

// This test is just to ensure
it('Is a cosmos 0.50 network', async () => {
const status = await client.status();

expect(status.nodeInfo.version).toMatch('0.38.');
});

// TODO requires these changes https://github.com/cosmos/cosmjs/compare/main...bryanchriswhite:cosmjs:main
it('correctly has finalized block events instead of being/end block events', () => {
expect(block.block.beginBlockEvents).toBeDefined();
expect(block.block.finalizedBlockEvents).toBeDefined();
});

it('correctly parses events', () => {
expect(block.block.events).toBeDefined();

const withLogs = block.block.events.filter((l) => !!l.log);

console.log('LOGS', withLogs);
expect(block.block.transactions[0].tx.events).toBeDefined();
expect(block.block.transactions[0].tx.log).toBeDefined();
});
});
84 changes: 53 additions & 31 deletions packages/node/src/utils/cosmos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@ import { toHex } from '@cosmjs/encoding';
import { DecodeObject, decodeTxRaw, Registry } from '@cosmjs/proto-signing';
import { fromTendermintEvent } from '@cosmjs/stargate';
import { Log, parseRawLog } from '@cosmjs/stargate/build/logs';
import { toRfc3339WithNanoseconds } from '@cosmjs/tendermint-rpc';
import {
BlockResponse,
BlockResultsResponse,
TxData,
Event,
Header as CosmosHeader,
} from '@cosmjs/tendermint-rpc/build/tendermint37';
toRfc3339WithNanoseconds,
tendermint34,
tendermint37,
comet38,
} from '@cosmjs/tendermint-rpc';
import {
IBlock,
getLogger,
Header,
filterBlockTimestamp,
} from '@subql/node-core';
import {
TxData,
TxEvent,
Header as CosmosHeader,
CosmosEventFilter,
CosmosMessageFilter,
CosmosBlock,
Expand All @@ -36,7 +37,11 @@ import { isObjectLike } from 'lodash';
import { isLong } from 'long';
import { SubqlProjectBlockFilter } from '../configure/SubqueryProject';
import { CosmosClient } from '../indexer/api.service';
import { BlockContent } from '../indexer/types';
import {
BlockContent,
BlockResponse,
BlockResultsResponse,
} from '../indexer/types';

const logger = getLogger('fetch');

Expand Down Expand Up @@ -311,7 +316,7 @@ function wrapMsg(

export function wrapBlockBeginAndEndEvents(
block: CosmosBlock,
events: Event[],
events: TxEvent[],
idxOffset: number,
): CosmosEvent[] {
return events.map(
Expand All @@ -327,47 +332,64 @@ export function wrapBlockBeginAndEndEvents(
);
}

// With tendermint34 the Attrbutes type key and value were Uint8Arrays
function attrToString(value: string | Uint8Array): string {
return typeof value === 'string'
? value
: Buffer.from(value).toString('utf8');
}

export function wrapEvent(
block: CosmosBlock,
txs: CosmosTransaction[],
registry: Registry,
idxOffset: number, //use this offset to avoid clash with idx of begin block events
): CosmosEvent[] {
const events: CosmosEvent[] = [];
const cosmosEvents: CosmosEvent[] = [];

for (const tx of txs) {
let logs: Log[];
let txEvents: readonly TxEvent[];
try {
logs = parseRawLog(tx.tx.log) as Log[];
txEvents = tx.tx.events;
} catch (e) {
//parsing fails if transaction had failed.
logger.debug('Failed to parse raw log, most likely a failed transaction');
continue;
return cosmosEvents;
}
for (const log of logs) {
for (const txEvent of txEvents) {
let msg: CosmosMessage;
try {
msg = wrapCosmosMsg(block, tx, log.msg_index, registry);
const eventMsgIndex = txEvent.attributes.find(
(attr) => attrToString(attr.key) === 'msg_index',
)?.value;

if (eventMsgIndex === undefined) {
continue;
}

const msgNumber = parseInt(attrToString(eventMsgIndex), 10);
msg = wrapCosmosMsg(block, tx, msgNumber, registry);
} catch (e) {
// Example where this can happen https://sei.explorers.guru/transaction/8D4CA68E917E15652E10CB960DE604AEEB1B183D6E94A85E9CD98403F15550B7
logger.warn(
`Unable to find message for event. tx=${tx.hash} messageIdx=${log.msg_index}`,
);
}
for (let i = 0; i < log.events.length; i++) {
const event: CosmosEvent = {
idx: idxOffset++,
msg,
tx,
block,
log,
event: log.events[i],
};
events.push(event);
logger.warn(`Unable to find message for event. tx=${tx.hash}`);
continue;
}
const cosmosEvent: CosmosEvent = {
idx: idxOffset++,
msg,
tx,
block,
log: {
msg_index: msg.idx,
log: txEvent.log,
events: txEvent.events,
},
event: txEvent,
};
cosmosEvents.push(cosmosEvent);
}
}

return events;
return cosmosEvents;
}

/*
Expand Down
13 changes: 4 additions & 9 deletions packages/node/src/utils/kyve/kyve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import { gzipSync } from 'zlib';
import { JsonRpcSuccessResponse } from '@cosmjs/json-rpc';
import { GeneratedType, Registry } from '@cosmjs/proto-signing';
import { defaultRegistryTypes } from '@cosmjs/stargate';
import { Tendermint37Client } from '@cosmjs/tendermint-rpc';
import {
BlockResponse,
BlockResultsResponse,
} from '@cosmjs/tendermint-rpc/build/tendermint37/responses';
import { connectComet, CometClient } from '@cosmjs/tendermint-rpc';
import KyveSDK from '@kyvejs/sdk';
import { makeTempDir } from '@subql/common';
import { delay } from '@subql/node-core';
Expand All @@ -28,7 +24,7 @@ import {
} from 'cosmjs-types/cosmwasm/wasm/v1/tx';
import { isEqual } from 'lodash';
import rimraf from 'rimraf';
import { HttpClient } from '../../indexer/rpc-clients';
import { BlockResponse, BlockResultsResponse } from '../../indexer/types';
import { LazyBlockContent } from '../cosmos';
import { KyveApi } from './kyve';
import { BundleDetails } from './kyveTypes';
Expand All @@ -55,7 +51,7 @@ const KYVE_CHAINID = 'kyve-1';
jest.setTimeout(100000);
describe('KyveApi', () => {
let kyveApi: KyveApi;
let tendermint: Tendermint37Client;
let tendermint: CometClient;
let registry: Registry;

let tmpPath: string;
Expand All @@ -81,8 +77,7 @@ describe('KyveApi', () => {
tmpPath,
300,
);
const client = new HttpClient('https://rpc.mainnet.archway.io:443');
tendermint = await Tendermint37Client.create(client);
tendermint = await connectComet('https://rpc.mainnet.archway.io:443');
});

beforeEach(async () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/node/src/utils/kyve/kyve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import * as zlib from 'zlib';
import { JsonRpcSuccessResponse } from '@cosmjs/json-rpc';
import { Registry } from '@cosmjs/proto-signing';
import { logs } from '@cosmjs/stargate';
import {
BlockResponse,
BlockResultsResponse,
TxData,
} from '@cosmjs/tendermint-rpc/build/tendermint37';
import { Responses } from '@cosmjs/tendermint-rpc/build/tendermint37/adaptor'; // adaptor is not exported
import KyveSDK, { KyveLCDClientType } from '@kyvejs/sdk';
import { SupportedChains } from '@kyvejs/sdk/src/constants'; // Currently these types are not exported
import { QueryPoolsResponse } from '@kyvejs/types/lcd/kyve/query/v1beta1/pools';
import { delay, getLogger, IBlock, timeout } from '@subql/node-core';
import { TxData } from '@subql/types-cosmos';
import axios, { AxiosResponse } from 'axios';
import { BlockContent } from '../../indexer/types';
import {
BlockContent,
BlockResponse,
BlockResultsResponse,
} from '../../indexer/types';
import { formatBlockUtil, LazyBlockContent } from '../cosmos';
import { isTmpDir } from '../project';
import { BundleDetails } from './kyveTypes';
Expand Down
Loading

0 comments on commit 6601e48

Please sign in to comment.