@subql/node-solana 6.0.2-0 → 6.0.3-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/indexer/indexer.manager.js +0 -1
- package/dist/indexer/indexer.manager.js.map +1 -1
- package/dist/solana/api.solana.spec.js +6 -1
- package/dist/solana/api.solana.spec.js.map +1 -1
- package/dist/solana/block.solana.js +13 -6
- package/dist/solana/block.solana.js.map +1 -1
- package/dist/solana/decoder.spec.js +7 -8
- package/dist/solana/decoder.spec.js.map +1 -1
- package/package.json +2 -2
|
@@ -36,7 +36,6 @@ let IndexerManager = class IndexerManager extends node_core_1.BaseIndexerManager
|
|
|
36
36
|
return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);
|
|
37
37
|
}
|
|
38
38
|
async indexBlockData(block, dataSources, getVM) {
|
|
39
|
-
// console.time(`Indexed block ${block.blockHeight}`);
|
|
40
39
|
await this.indexBlockContent(block, dataSources, getVM);
|
|
41
40
|
for (const tx of block.transactions) {
|
|
42
41
|
await this.indexTransaction(tx, dataSources, getVM);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexer.manager.js","sourceRoot":"","sources":["../../src/indexer/indexer.manager.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;;;;;;;;;;AAEnC,2CAAoD;AACpD,wDAS8B;AAC9B,gDAW0B;AAC1B,sDAY6B;AAC7B,mCAAiC;AACjC,8DAA0D;AAE1D,sCAKmB;AACnB,yDAKgC;AAIzB,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,8BAUnC;IACW,WAAW,GAAG,2BAAW,CAAC;IAC1B,UAAU,GAAG,0BAAU,CAAC;IAElC,YACwB,UAA4B,EAClD,UAAsB,EACtB,cAAwD,EACxD,kBAGC,EACD,gBAAyD,EAEzD,wBAAkD,EACpB,iBAAoC;QAElE,KAAK,CACH,UAAU,EACV,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,CAAC,UAAU,CAAC,OAAO,CAAC,EACpC,gBAAgB,EAChB,iBAAiB,CAClB,CAAC;IACJ,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU,CACd,KAA2B,EAC3B,WAAoC;QAEpC,OAAO,KAAK,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CACvD,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAC/C,CAAC;IACJ,CAAC;IAES,cAAc,CACtB,EAAyB,EACzB,OAAsB;QAEtB,OAAO,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9E,CAAC;IAES,KAAK,CAAC,cAAc,CAC5B,KAAmB,EACnB,WAA8B,EAC9B,KAAsD;QAEtD,sDAAsD;QACtD,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAExD,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACpC,MAAM,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YAEpD,8FAA8F;YAC9F,MAAM,iBAAiB,GAAG,IAAA,gBAAO,EAC/B,EAAE,CAAC,IAAI,EAAE,iBAAiB,EAC1B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CACvB,CAAC;YAEF,KAAK,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAC7C,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAC1C,EAAE,CAAC;gBACF,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;gBAE7D,KAAK,MAAM,iBAAiB,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC7D,KAAK,MAAM,eAAe,IAAI,iBAAiB,CAAC,YAAY,EAAE,CAAC;wBAC7D,MAAM,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;YACH,CAAC;YAED,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,yDAAyD;IAC3D,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC7B,KAAkB,EAClB,WAA8B,EAC9B,KAAsD;QAEtD,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,SAAS,CAAC,gCAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,EAAqB,EACrB,WAA8B,EAC9B,KAAsD;QAEtD,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,SAAS,CAAC,gCAAiB,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,WAA8B,EAC9B,WAA8B,EAC9B,KAAsD;QAEtD,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,SAAS,CAClB,gCAAiB,CAAC,WAAW,EAC7B,WAAW,EACX,EAAE,EACF,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,QAAQ,CACpB,GAAqB,EACrB,WAA8B,EAC9B,KAAsD;QAEtD,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,SAAS,CAAC,gCAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,4DAA4D;IAClD,KAAK,CAAC,mBAAmB,CACjC,IAAuB,EACvB,IAAS,EACT,EAA0B;QAE1B,yCAAyC;QACzC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE/C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;CACF,CAAA;AArJY,wCAAc;AAyCnB;IADL,IAAA,oBAAQ,GAAE;;;;gDAQV;yBAhDU,cAAc;IAD1B,IAAA,mBAAU,GAAE;IAgBR,WAAA,IAAA,eAAM,EAAC,YAAY,CAAC,CAAA;IAQpB,WAAA,IAAA,eAAM,EAAC,2BAA2B,CAAC,CAAA;IAEnC,WAAA,IAAA,eAAM,EAAC,oBAAoB,CAAC,CAAA;qCAVK,yBAAgB;QACtC,sBAAU;QACN,0BAAc;QACV,8BAAkB;QAIpB,4BAAgB;QAER,oCAAwB;QACD,sCAAiB;GAzBzD,cAAc,CAqJ1B;AAED,MAAM,gBAAgB,GAAG;IACvB,CAAC,gCAAiB,CAAC,KAAK,CAAC,EAAE,uCAAuB;IAClD,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,6CAA6B;IAC9D,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,6CAA6B;IAC9D,CAAC,gCAAiB,CAAC,GAAG,CAAC,EAAE,qCAAqB;CAC/C,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,OAAsB,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,gCAAiB,CAAC,KAAK,CAAC,EAAE,CACzB,IAAiB,EACjB,MAAyB,EACzB,EAAyB,EACzB,EAAE,CAAC,IAAA,oCAAqB,EAAC,IAAI,EAAE,MAAM,CAAC;IACxC,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,CAC/B,IAAuB,EACvB,MAA+B,EAC/B,EAAyB,EACzB,EAAE,CAAC,IAAA,0CAA2B,EAAC,IAAI,EAAE,MAAM,CAAC;IAC9C,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,CAC/B,IAAuB,EACvB,MAA+B,EAC/B,EAAyB,EACzB,EAAE,CAAC,IAAA,0CAA2B,EAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;IACvD,CAAC,gCAAiB,CAAC,GAAG,CAAC,EAAE,CACvB,IAAsB,EACtB,MAAuB,EACvB,EAAyB,EACzB,EAAE,CAAC,IAAA,kCAAmB,EAAC,IAAI,EAAE,MAAM,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG;IACpB,CAAC,gCAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,IAAiB,EAAE,EAAE,CAAC,IAAI;IACtD,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,CAAC,IAAuB,EAAE,EAAE,CAAC,IAAI;IAClE,CAAC,gCAAiB,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,IAAuB,EAAE,EAAE;QACjE,2BAA2B;QAC3B,MAAM,IAAI,CAAC,WAAW,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,CAAC,gCAAiB,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAsB,EAAE,EAAE;QACxD,2BAA2B;QAC3B,MAAM,IAAI,CAAC,cAAc,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n isBlockHandlerProcessor,\n isCustomDs,\n isRuntimeDs,\n SubqlSolanaCustomDataSource,\n SubqlSolanaDataSource,\n isInstructionHandlerProcessor,\n isTransactionHandlerProcessor,\n isLogHandlerProcessor,\n} from '@subql/common-solana';\nimport {\n NodeConfig,\n profiler,\n IndexerSandbox,\n ProcessBlockResponse,\n BaseIndexerManager,\n IBlock,\n SandboxService,\n DsProcessorService,\n DynamicDsService,\n UnfinalizedBlocksService,\n} from '@subql/node-core';\nimport {\n SolanaHandlerKind,\n SolanaTransaction,\n SolanaBlock,\n SubqlRuntimeDatasource,\n SolanaBlockFilter,\n SolanaTransactionFilter,\n SolanaInstruction,\n SolanaInstructionFilter,\n SolanaRuntimeHandlerInputMap,\n SolanaLogMessage,\n SolanaLogFilter,\n} from '@subql/types-solana';\nimport { groupBy } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { SolanaProjectDs } from '../configure/SubqueryProject';\nimport {\n SolanaApi,\n SolanaApiService,\n SolanaDecoder,\n SolanaSafeApi,\n} from '../solana';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from '../solana/utils.solana';\nimport { BlockContent } from './types';\n\n@Injectable()\nexport class IndexerManager extends BaseIndexerManager<\n SolanaApi,\n SolanaSafeApi,\n BlockContent,\n SolanaApiService,\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource,\n ReturnType<typeof getFilterTypeMap>,\n typeof ProcessorTypeMap,\n SolanaRuntimeHandlerInputMap\n> {\n protected isRuntimeDs = isRuntimeDs;\n protected isCustomDs = isCustomDs;\n\n constructor(\n @Inject('APIService') apiService: SolanaApiService,\n nodeConfig: NodeConfig,\n sandboxService: SandboxService<SolanaSafeApi, SolanaApi>,\n dsProcessorService: DsProcessorService<\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource\n >,\n dynamicDsService: DynamicDsService<SubqlSolanaDataSource>,\n @Inject('IUnfinalizedBlocksService')\n unfinalizedBlocksService: UnfinalizedBlocksService,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n super(\n apiService,\n nodeConfig,\n sandboxService,\n dsProcessorService,\n dynamicDsService,\n unfinalizedBlocksService,\n getFilterTypeMap(apiService.decoder),\n ProcessorTypeMap,\n blockchainService,\n );\n }\n\n @profiler()\n async indexBlock(\n block: IBlock<BlockContent>,\n dataSources: SubqlSolanaDataSource[],\n ): Promise<ProcessBlockResponse> {\n return super.internalIndexBlock(block, dataSources, () =>\n this.blockchainService.getSafeApi(block.block),\n );\n }\n\n protected getDsProcessor(\n ds: SubqlSolanaDataSource,\n safeApi: SolanaSafeApi,\n ): IndexerSandbox {\n return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);\n }\n\n protected async indexBlockData(\n block: BlockContent,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n // console.time(`Indexed block ${block.blockHeight}`);\n await this.indexBlockContent(block, dataSources, getVM);\n\n for (const tx of block.transactions) {\n await this.indexTransaction(tx, dataSources, getVM);\n\n // There is probably only one item per group but that could change based on the data structure\n const innerInstructions = groupBy(\n tx.meta?.innerInstructions,\n (inner) => inner.index,\n );\n\n for (const [idx, instruction] of Object.entries(\n tx.transaction.message.instructions ?? [],\n )) {\n await this.indexInstruction(instruction, dataSources, getVM);\n\n for (const innerInstrutions1 of innerInstructions[idx] ?? []) {\n for (const innerInstrution of innerInstrutions1.instructions) {\n await this.indexInstruction(innerInstrution, dataSources, getVM);\n }\n }\n }\n\n for (const log of tx.meta?.logs ?? []) {\n await this.indexLog(log, dataSources, getVM);\n }\n }\n // console.timeEnd(`Indexed block ${block.blockHeight}`);\n }\n\n private async indexBlockContent(\n block: SolanaBlock,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Block, block, ds, getVM);\n }\n }\n\n private async indexTransaction(\n tx: SolanaTransaction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Transaction, tx, ds, getVM);\n }\n }\n\n private async indexInstruction(\n instruction: SolanaInstruction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(\n SolanaHandlerKind.Instruction,\n instruction,\n ds,\n getVM,\n );\n }\n }\n\n private async indexLog(\n log: SolanaLogMessage,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Log, log, ds, getVM);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n protected async prepareFilteredData(\n kind: SolanaHandlerKind,\n data: any,\n ds: SubqlRuntimeDatasource,\n ): Promise<any> {\n // Ensure any provided IDLs are available\n await this.apiService.api.decoder.loadIdls(ds);\n\n return DataIDLParser[kind](data);\n }\n}\n\nconst ProcessorTypeMap = {\n [SolanaHandlerKind.Block]: isBlockHandlerProcessor,\n [SolanaHandlerKind.Transaction]: isTransactionHandlerProcessor,\n [SolanaHandlerKind.Instruction]: isInstructionHandlerProcessor,\n [SolanaHandlerKind.Log]: isLogHandlerProcessor,\n};\n\nconst getFilterTypeMap = (decoder: SolanaDecoder) => ({\n [SolanaHandlerKind.Block]: (\n data: SolanaBlock,\n filter: SolanaBlockFilter,\n ds: SubqlSolanaDataSource,\n ) => filterBlocksProcessor(data, filter),\n [SolanaHandlerKind.Transaction]: (\n data: SolanaTransaction,\n filter: SolanaTransactionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterTransactionsProcessor(data, filter),\n [SolanaHandlerKind.Instruction]: (\n data: SolanaInstruction,\n filter: SolanaInstructionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterInstructionsProcessor(data, decoder, filter),\n [SolanaHandlerKind.Log]: (\n data: SolanaLogMessage,\n filter: SolanaLogFilter,\n ds: SubqlSolanaDataSource,\n ) => filterLogsProcessor(data, filter),\n});\n\nconst DataIDLParser = {\n [SolanaHandlerKind.Block]: (data: SolanaBlock) => data,\n [SolanaHandlerKind.Transaction]: (data: SolanaTransaction) => data,\n [SolanaHandlerKind.Instruction]: async (data: SolanaInstruction) => {\n // Preload the decoded data\n await data.decodedData;\n return data;\n },\n [SolanaHandlerKind.Log]: async (data: SolanaLogMessage) => {\n // Preload the decoded data\n await data.decodedMessage;\n return data;\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"indexer.manager.js","sourceRoot":"","sources":["../../src/indexer/indexer.manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n isBlockHandlerProcessor,\n isCustomDs,\n isRuntimeDs,\n SubqlSolanaCustomDataSource,\n SubqlSolanaDataSource,\n isInstructionHandlerProcessor,\n isTransactionHandlerProcessor,\n isLogHandlerProcessor,\n} from '@subql/common-solana';\nimport {\n NodeConfig,\n profiler,\n IndexerSandbox,\n ProcessBlockResponse,\n BaseIndexerManager,\n IBlock,\n SandboxService,\n DsProcessorService,\n DynamicDsService,\n UnfinalizedBlocksService,\n} from '@subql/node-core';\nimport {\n SolanaHandlerKind,\n SolanaTransaction,\n SolanaBlock,\n SubqlRuntimeDatasource,\n SolanaBlockFilter,\n SolanaTransactionFilter,\n SolanaInstruction,\n SolanaInstructionFilter,\n SolanaRuntimeHandlerInputMap,\n SolanaLogMessage,\n SolanaLogFilter,\n} from '@subql/types-solana';\nimport { groupBy } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { SolanaProjectDs } from '../configure/SubqueryProject';\nimport {\n SolanaApi,\n SolanaApiService,\n SolanaDecoder,\n SolanaSafeApi,\n} from '../solana';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from '../solana/utils.solana';\nimport { BlockContent } from './types';\n\n@Injectable()\nexport class IndexerManager extends BaseIndexerManager<\n SolanaApi,\n SolanaSafeApi,\n BlockContent,\n SolanaApiService,\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource,\n ReturnType<typeof getFilterTypeMap>,\n typeof ProcessorTypeMap,\n SolanaRuntimeHandlerInputMap\n> {\n protected isRuntimeDs = isRuntimeDs;\n protected isCustomDs = isCustomDs;\n\n constructor(\n @Inject('APIService') apiService: SolanaApiService,\n nodeConfig: NodeConfig,\n sandboxService: SandboxService<SolanaSafeApi, SolanaApi>,\n dsProcessorService: DsProcessorService<\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource\n >,\n dynamicDsService: DynamicDsService<SubqlSolanaDataSource>,\n @Inject('IUnfinalizedBlocksService')\n unfinalizedBlocksService: UnfinalizedBlocksService,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n super(\n apiService,\n nodeConfig,\n sandboxService,\n dsProcessorService,\n dynamicDsService,\n unfinalizedBlocksService,\n getFilterTypeMap(apiService.decoder),\n ProcessorTypeMap,\n blockchainService,\n );\n }\n\n @profiler()\n async indexBlock(\n block: IBlock<BlockContent>,\n dataSources: SubqlSolanaDataSource[],\n ): Promise<ProcessBlockResponse> {\n return super.internalIndexBlock(block, dataSources, () =>\n this.blockchainService.getSafeApi(block.block),\n );\n }\n\n protected getDsProcessor(\n ds: SubqlSolanaDataSource,\n safeApi: SolanaSafeApi,\n ): IndexerSandbox {\n return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);\n }\n\n protected async indexBlockData(\n block: BlockContent,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n await this.indexBlockContent(block, dataSources, getVM);\n\n for (const tx of block.transactions) {\n await this.indexTransaction(tx, dataSources, getVM);\n\n // There is probably only one item per group but that could change based on the data structure\n const innerInstructions = groupBy(\n tx.meta?.innerInstructions,\n (inner) => inner.index,\n );\n\n for (const [idx, instruction] of Object.entries(\n tx.transaction.message.instructions ?? [],\n )) {\n await this.indexInstruction(instruction, dataSources, getVM);\n\n for (const innerInstrutions1 of innerInstructions[idx] ?? []) {\n for (const innerInstrution of innerInstrutions1.instructions) {\n await this.indexInstruction(innerInstrution, dataSources, getVM);\n }\n }\n }\n\n for (const log of tx.meta?.logs ?? []) {\n await this.indexLog(log, dataSources, getVM);\n }\n }\n // console.timeEnd(`Indexed block ${block.blockHeight}`);\n }\n\n private async indexBlockContent(\n block: SolanaBlock,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Block, block, ds, getVM);\n }\n }\n\n private async indexTransaction(\n tx: SolanaTransaction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Transaction, tx, ds, getVM);\n }\n }\n\n private async indexInstruction(\n instruction: SolanaInstruction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(\n SolanaHandlerKind.Instruction,\n instruction,\n ds,\n getVM,\n );\n }\n }\n\n private async indexLog(\n log: SolanaLogMessage,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Log, log, ds, getVM);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n protected async prepareFilteredData(\n kind: SolanaHandlerKind,\n data: any,\n ds: SubqlRuntimeDatasource,\n ): Promise<any> {\n // Ensure any provided IDLs are available\n await this.apiService.api.decoder.loadIdls(ds);\n\n return DataIDLParser[kind](data);\n }\n}\n\nconst ProcessorTypeMap = {\n [SolanaHandlerKind.Block]: isBlockHandlerProcessor,\n [SolanaHandlerKind.Transaction]: isTransactionHandlerProcessor,\n [SolanaHandlerKind.Instruction]: isInstructionHandlerProcessor,\n [SolanaHandlerKind.Log]: isLogHandlerProcessor,\n};\n\nconst getFilterTypeMap = (decoder: SolanaDecoder) => ({\n [SolanaHandlerKind.Block]: (\n data: SolanaBlock,\n filter: SolanaBlockFilter,\n ds: SubqlSolanaDataSource,\n ) => filterBlocksProcessor(data, filter),\n [SolanaHandlerKind.Transaction]: (\n data: SolanaTransaction,\n filter: SolanaTransactionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterTransactionsProcessor(data, filter),\n [SolanaHandlerKind.Instruction]: (\n data: SolanaInstruction,\n filter: SolanaInstructionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterInstructionsProcessor(data, decoder, filter),\n [SolanaHandlerKind.Log]: (\n data: SolanaLogMessage,\n filter: SolanaLogFilter,\n ds: SubqlSolanaDataSource,\n ) => filterLogsProcessor(data, filter),\n});\n\nconst DataIDLParser = {\n [SolanaHandlerKind.Block]: (data: SolanaBlock) => data,\n [SolanaHandlerKind.Transaction]: (data: SolanaTransaction) => data,\n [SolanaHandlerKind.Instruction]: async (data: SolanaInstruction) => {\n // Preload the decoded data\n await data.decodedData;\n return data;\n },\n [SolanaHandlerKind.Log]: async (data: SolanaLogMessage) => {\n // Preload the decoded data\n await data.decodedMessage;\n return data;\n },\n};\n"]}
|
|
@@ -13,8 +13,9 @@ describe('Api.solana', () => {
|
|
|
13
13
|
let solanaApi;
|
|
14
14
|
const eventEmitter = new event_emitter_1.EventEmitter2();
|
|
15
15
|
let block;
|
|
16
|
+
const decoder = new decoder_1.SolanaDecoder();
|
|
16
17
|
beforeAll(async () => {
|
|
17
|
-
solanaApi = await api_solana_1.SolanaApi.create(HTTP_ENDPOINT, eventEmitter,
|
|
18
|
+
solanaApi = await api_solana_1.SolanaApi.create(HTTP_ENDPOINT, eventEmitter, decoder);
|
|
18
19
|
// https://solscan.io/block/325922873
|
|
19
20
|
block = await solanaApi.fetchBlock(325_922_873);
|
|
20
21
|
}, 20_000);
|
|
@@ -176,12 +177,16 @@ describe('Api.solana', () => {
|
|
|
176
177
|
const tx = getTxBySig('4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d');
|
|
177
178
|
const inst = tx?.transaction.message.instructions[4];
|
|
178
179
|
expect(inst).toBeDefined();
|
|
180
|
+
const decodeInst = jest.spyOn(solanaApi.decoder, 'decodeInstruction');
|
|
179
181
|
expect(() => JSON.stringify(inst)).not.toThrow();
|
|
182
|
+
expect(decodeInst).not.toHaveBeenCalled();
|
|
180
183
|
});
|
|
181
184
|
it('can stringify a LogMessage', () => {
|
|
182
185
|
const tx = getTxBySig('4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d');
|
|
183
186
|
for (const log of tx.meta.logs) {
|
|
187
|
+
const decodeLog = jest.spyOn(solanaApi.decoder, 'decodeLog');
|
|
184
188
|
expect(() => JSON.stringify(log)).not.toThrow();
|
|
189
|
+
expect(decodeLog).not.toHaveBeenCalled();
|
|
185
190
|
}
|
|
186
191
|
});
|
|
187
192
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.solana.spec.js","sourceRoot":"","sources":["../../src/solana/api.solana.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { TransactionFilter } from '@subql/common-solana';\nimport { IBlock } from '@subql/node-core';\nimport {\n SolanaBlock,\n SolanaBlockFilter,\n SolanaTransaction,\n} from '@subql/types-solana';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from './utils.solana';\n\n// Add api key to work\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\n\ndescribe('Api.solana', () => {\n let solanaApi: SolanaApi;\n const eventEmitter = new EventEmitter2();\n let block: IBlock<SolanaBlock>;\n\n beforeAll(async () => {\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n eventEmitter,\n new SolanaDecoder(),\n );\n // https://solscan.io/block/325922873\n block = await solanaApi.fetchBlock(325_922_873);\n }, 20_000);\n\n function getTxBySig(sig: string): SolanaTransaction {\n const tx = block.block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n if (!tx) {\n throw new Error(`Unable to find tx with signature ${sig}`);\n }\n return tx;\n }\n\n it('parses block timestamps correctly', () => {\n expect(block.getHeader().timestamp).toEqual(\n new Date('2025-03-10T22:40:28.000Z'),\n );\n });\n\n describe('Filters', () => {\n it('Should run block filters correctly', () => {\n const moduloBlockFilter: SolanaBlockFilter = {\n modulo: 1,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter),\n ).toBeTruthy();\n\n const moduloBlockFilter2: SolanaBlockFilter = {\n modulo: 325_922_870,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter2),\n ).toBeFalsy();\n\n // TODO timestamp block filter\n });\n\n it('Should run transaction filters correctly', () => {\n // https://solscan.io/tx/FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n const signerMatch: TransactionFilter = {\n signerAccountKey: '3j1iDNRseKJVEWAb62Xxn74mVjJ7sUTVJaaBNb3gKtUe',\n };\n expect(filterTransactionsProcessor(tx!, signerMatch)).toBeTruthy();\n\n const signerMismatch: TransactionFilter = {\n signerAccountKey: '7yYGUXSY9hSa3MqmU7t4acCMBzSQyjxZyoRC1bDKMKJh',\n };\n expect(filterTransactionsProcessor(tx!, signerMismatch)).toBeFalsy();\n });\n\n describe('instructions', () => {\n it('can filter failed instructions', () => {\n const failedTx = block.block.transactions.find((tx) => tx.meta?.err);\n const failedInst = failedTx!.transaction.message.instructions[0];\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: true,\n }),\n ).toBeTruthy();\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: false,\n }),\n ).toBeFalsy();\n });\n\n it('can filter programIds', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n\n // A program called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // A program not called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n }),\n ).toBe(false);\n });\n\n it.each([\n // ['human', 'swap', true], // TODO wrong IDL currently\n ['hex', '0x09', true],\n ['base58', 'A', true],\n ['human', 'shutdown', false],\n ['hex', '0x74ce1bbfa6130049', false],\n ['base58', 'kPf6M86k1NDLT', false],\n ])(\n 'should correctly match discrminators in %s format',\n (_, discriminator, result) => {\n // TODO wrong IDL currently\n solanaApi.decoder.idls[\n '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'\n ] = IDL_swap;\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n discriminator,\n }),\n ).toBe(result);\n },\n );\n\n it('can filter accounts', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W']],\n }),\n ).toBe(true);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n null,\n ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W'], // Out of position\n ],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, null, []],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n [\n '6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W',\n '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n ], // Out of position\n ],\n }),\n ).toBe(true);\n });\n });\n\n describe('logs', () => {\n it('should filter logs by program Id', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n const log = tx!.meta!.logs![1];\n expect(log).toBeDefined();\n // Matching program id\n expect(\n filterLogsProcessor(log, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // non-matching programId\n expect(\n filterLogsProcessor(log, {\n programId: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n }),\n ).toBe(false);\n });\n });\n });\n\n describe('Block parsing', () => {\n it('makes instructions that have a transaction property', () => {\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n for (const instruction of tx!.transaction.message.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n\n for (const innerInstruction of tx!.meta!.innerInstructions) {\n for (const instruction of innerInstruction.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n }\n });\n\n it('corretly parses logs', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n expect(tx!.meta!.logs).toBeDefined();\n expect(tx!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with data logs\n const txWData = getTxBySig(\n 'qtUujQqx16ChZRMG4TE9eNMp4th3GxLvuuCQBEXK4KYyjqfAAPbP6xejA2ZTUe7X1cZYiHCnJHpC5v6GRctYc8c',\n );\n expect(txWData!.meta!.logs).toBeDefined();\n expect(txWData!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with a failure\n const txWError = getTxBySig(\n '8q3z3WoYUcA8UQLYgdgriGCZrGJUAYoeUwTJaVuuq43AmKLQxKLAMxuEAWXMquozVXEX4eL91r3jxKFVifmeXrv',\n );\n expect(txWError!.meta!.logs).toBeDefined();\n expect(txWError!.meta!.logs!.length).toBeGreaterThan(0);\n });\n });\n\n // Tests that data types can be stringified, this is important to test because of circular references\n describe('JSON serialization', () => {\n it('can stringify a SolanaBlock', () => {\n expect(() => JSON.stringify(block)).not.toThrow();\n });\n\n it('can stringify a SolanaTransaction', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n\n expect(tx).toBeDefined();\n expect(() => JSON.stringify(tx)).not.toThrow();\n });\n\n it('can stringify a SolanaInstruction', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n expect(() => JSON.stringify(inst)).not.toThrow();\n });\n\n it('can stringify a LogMessage', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n for (const log of tx!.meta!.logs!) {\n expect(() => JSON.stringify(log)).not.toThrow();\n }\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"api.solana.spec.js","sourceRoot":"","sources":["../../src/solana/api.solana.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { TransactionFilter } from '@subql/common-solana';\nimport { IBlock } from '@subql/node-core';\nimport {\n SolanaBlock,\n SolanaBlockFilter,\n SolanaTransaction,\n} from '@subql/types-solana';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from './utils.solana';\n\n// Add api key to work\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\n\ndescribe('Api.solana', () => {\n let solanaApi: SolanaApi;\n const eventEmitter = new EventEmitter2();\n let block: IBlock<SolanaBlock>;\n const decoder = new SolanaDecoder();\n\n beforeAll(async () => {\n solanaApi = await SolanaApi.create(HTTP_ENDPOINT, eventEmitter, decoder);\n // https://solscan.io/block/325922873\n block = await solanaApi.fetchBlock(325_922_873);\n }, 20_000);\n\n function getTxBySig(sig: string): SolanaTransaction {\n const tx = block.block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n if (!tx) {\n throw new Error(`Unable to find tx with signature ${sig}`);\n }\n return tx;\n }\n\n it('parses block timestamps correctly', () => {\n expect(block.getHeader().timestamp).toEqual(\n new Date('2025-03-10T22:40:28.000Z'),\n );\n });\n\n describe('Filters', () => {\n it('Should run block filters correctly', () => {\n const moduloBlockFilter: SolanaBlockFilter = {\n modulo: 1,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter),\n ).toBeTruthy();\n\n const moduloBlockFilter2: SolanaBlockFilter = {\n modulo: 325_922_870,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter2),\n ).toBeFalsy();\n\n // TODO timestamp block filter\n });\n\n it('Should run transaction filters correctly', () => {\n // https://solscan.io/tx/FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n const signerMatch: TransactionFilter = {\n signerAccountKey: '3j1iDNRseKJVEWAb62Xxn74mVjJ7sUTVJaaBNb3gKtUe',\n };\n expect(filterTransactionsProcessor(tx!, signerMatch)).toBeTruthy();\n\n const signerMismatch: TransactionFilter = {\n signerAccountKey: '7yYGUXSY9hSa3MqmU7t4acCMBzSQyjxZyoRC1bDKMKJh',\n };\n expect(filterTransactionsProcessor(tx!, signerMismatch)).toBeFalsy();\n });\n\n describe('instructions', () => {\n it('can filter failed instructions', () => {\n const failedTx = block.block.transactions.find((tx) => tx.meta?.err);\n const failedInst = failedTx!.transaction.message.instructions[0];\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: true,\n }),\n ).toBeTruthy();\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: false,\n }),\n ).toBeFalsy();\n });\n\n it('can filter programIds', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n\n // A program called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // A program not called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n }),\n ).toBe(false);\n });\n\n it.each([\n // ['human', 'swap', true], // TODO wrong IDL currently\n ['hex', '0x09', true],\n ['base58', 'A', true],\n ['human', 'shutdown', false],\n ['hex', '0x74ce1bbfa6130049', false],\n ['base58', 'kPf6M86k1NDLT', false],\n ])(\n 'should correctly match discrminators in %s format',\n (_, discriminator, result) => {\n // TODO wrong IDL currently\n solanaApi.decoder.idls[\n '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'\n ] = IDL_swap;\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n discriminator,\n }),\n ).toBe(result);\n },\n );\n\n it('can filter accounts', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W']],\n }),\n ).toBe(true);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n null,\n ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W'], // Out of position\n ],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, null, []],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n [\n '6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W',\n '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n ], // Out of position\n ],\n }),\n ).toBe(true);\n });\n });\n\n describe('logs', () => {\n it('should filter logs by program Id', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n const log = tx!.meta!.logs![1];\n expect(log).toBeDefined();\n // Matching program id\n expect(\n filterLogsProcessor(log, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // non-matching programId\n expect(\n filterLogsProcessor(log, {\n programId: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n }),\n ).toBe(false);\n });\n });\n });\n\n describe('Block parsing', () => {\n it('makes instructions that have a transaction property', () => {\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n for (const instruction of tx!.transaction.message.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n\n for (const innerInstruction of tx!.meta!.innerInstructions) {\n for (const instruction of innerInstruction.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n }\n });\n\n it('corretly parses logs', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n expect(tx!.meta!.logs).toBeDefined();\n expect(tx!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with data logs\n const txWData = getTxBySig(\n 'qtUujQqx16ChZRMG4TE9eNMp4th3GxLvuuCQBEXK4KYyjqfAAPbP6xejA2ZTUe7X1cZYiHCnJHpC5v6GRctYc8c',\n );\n expect(txWData!.meta!.logs).toBeDefined();\n expect(txWData!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with a failure\n const txWError = getTxBySig(\n '8q3z3WoYUcA8UQLYgdgriGCZrGJUAYoeUwTJaVuuq43AmKLQxKLAMxuEAWXMquozVXEX4eL91r3jxKFVifmeXrv',\n );\n expect(txWError!.meta!.logs).toBeDefined();\n expect(txWError!.meta!.logs!.length).toBeGreaterThan(0);\n });\n });\n\n // Tests that data types can be stringified, this is important to test because of circular references\n describe('JSON serialization', () => {\n it('can stringify a SolanaBlock', () => {\n expect(() => JSON.stringify(block)).not.toThrow();\n });\n\n it('can stringify a SolanaTransaction', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n\n expect(tx).toBeDefined();\n expect(() => JSON.stringify(tx)).not.toThrow();\n });\n\n it('can stringify a SolanaInstruction', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n expect(inst).toBeDefined();\n\n const decodeInst = jest.spyOn(solanaApi.decoder, 'decodeInstruction');\n expect(() => JSON.stringify(inst)).not.toThrow();\n expect(decodeInst).not.toHaveBeenCalled();\n });\n\n it('can stringify a LogMessage', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n for (const log of tx!.meta!.logs!) {\n const decodeLog = jest.spyOn(solanaApi.decoder, 'decodeLog');\n expect(() => JSON.stringify(log)).not.toThrow();\n expect(decodeLog).not.toHaveBeenCalled();\n }\n });\n });\n});\n"]}
|
|
@@ -7,6 +7,16 @@ exports.formatBlockUtil = formatBlockUtil;
|
|
|
7
7
|
exports.solanaBlockToHeader = solanaBlockToHeader;
|
|
8
8
|
const node_core_1 = require("@subql/node-core");
|
|
9
9
|
const logger = (0, node_core_1.getLogger)('SolanaBlock');
|
|
10
|
+
// We use this function to omit properties without accessing getters
|
|
11
|
+
function omit(input, omit) {
|
|
12
|
+
const json = {};
|
|
13
|
+
for (const key of Object.getOwnPropertyNames(input)) {
|
|
14
|
+
if (!omit.includes(key)) {
|
|
15
|
+
json[key] = input[key];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return json;
|
|
19
|
+
}
|
|
10
20
|
function wrapInstruction(index, instruction, transaction, block, decoder) {
|
|
11
21
|
let pendingDecode;
|
|
12
22
|
// XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction
|
|
@@ -22,8 +32,7 @@ function wrapInstruction(index, instruction, transaction, block, decoder) {
|
|
|
22
32
|
};
|
|
23
33
|
// Implement this in order to calculate block size
|
|
24
34
|
res.toJSON = () => {
|
|
25
|
-
|
|
26
|
-
return rest;
|
|
35
|
+
return omit(res, ['block', 'decodedData', 'transaction']);
|
|
27
36
|
};
|
|
28
37
|
return res;
|
|
29
38
|
}
|
|
@@ -107,8 +116,7 @@ function wrapLogs(logs, decoder) {
|
|
|
107
116
|
// Implement this in order to calculate block size
|
|
108
117
|
res.forEach((r) => {
|
|
109
118
|
r.toJSON = () => {
|
|
110
|
-
|
|
111
|
-
return rest;
|
|
119
|
+
return omit(r, ['decodedMessage']);
|
|
112
120
|
};
|
|
113
121
|
});
|
|
114
122
|
return res;
|
|
@@ -131,8 +139,7 @@ function wrapDictionaryLogs(logs, decoder) {
|
|
|
131
139
|
};
|
|
132
140
|
// Implement this in order to calculate block size
|
|
133
141
|
res.toJSON = () => {
|
|
134
|
-
|
|
135
|
-
return rest;
|
|
142
|
+
return omit(res, ['decodedMessage']);
|
|
136
143
|
};
|
|
137
144
|
return res;
|
|
138
145
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.solana.js","sourceRoot":"","sources":["../../src/solana/block.solana.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport type {\n UnixTimestamp,\n Blockhash,\n Slot,\n TransactionForFullJson,\n} from '@solana/rpc-types';\nimport { getLogger, type Header, type IBlock } from '@subql/node-core';\nimport type {\n SolanaBlock,\n BaseSolanaBlock,\n SolanaInstruction,\n DecodedData,\n SolanaLogMessage,\n} from '@subql/types-solana';\nimport { SolanaDecoder } from './decoder';\n\nconst logger = getLogger('SolanaBlock');\n\ntype RawSolanaBlock = Readonly<{\n /** The number of blocks beneath this block */\n blockHeight: bigint;\n /** Estimated production time, as Unix timestamp */\n blockTime: UnixTimestamp;\n /** the blockhash of this block */\n blockhash: Blockhash;\n /** The slot index of this block's parent */\n parentSlot: Slot;\n /** The blockhash of this block's parent */\n previousBlockhash: Blockhash;\n\n transactions: readonly TransactionForFullJson<0>[];\n}>;\n\nfunction wrapInstruction(\n index: number[],\n instruction: Omit<\n SolanaInstruction,\n 'index' | 'block' | 'transaction' | 'decodedData'\n >,\n transaction: TransactionForFullJson<0>,\n block: BaseSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaInstruction {\n let pendingDecode: Promise<DecodedData | null>;\n // XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction\n const res = {\n ...instruction,\n index,\n transaction,\n block,\n get decodedData(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeInstruction(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n const { block, decodedData, transaction, ...rest } = res;\n return rest;\n };\n\n return res;\n}\n\nfunction wrapLogs(\n logs: readonly string[] | null,\n decoder: SolanaDecoder,\n): SolanaLogMessage[] | null {\n if (logs === null) {\n return null;\n }\n const res: SolanaLogMessage[] = [];\n\n // Keep a stack of the instruction programs\n const instructionPath: string[] = [];\n\n for (const [idx, log] of Object.entries(logs)) {\n let pendingDecode: Promise<DecodedData | null>;\n if (log.startsWith('Program log:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'log',\n decodedMessage: Promise.resolve(null),\n });\n } else if (log.startsWith('Program data:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'data',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse\n });\n } else if (log.startsWith('Program return:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'other',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse, can return data be dcoded?\n });\n } else if (log.startsWith('Program consumption:')) {\n // DO nothing\n } else if (log.startsWith('Program')) {\n const [, /* \"Program\"*/ programAddress, mode, ...rest] = log.split(' '); // TODO doesn't work with compute units\n switch (mode) {\n case 'invoke':\n instructionPath.push(programAddress);\n break;\n case 'success':\n // TODO need to check this is always the last item\n instructionPath.pop();\n break;\n case 'consumed':\n // Do nothing\n break;\n case 'failed:':\n // TODO\n instructionPath.pop();\n break;\n default:\n throw new Error(`Unknown log mode: ${mode}, log: ${log}`);\n }\n } else {\n /**\n * Known examples (prefixes):\n * * Transfer\n * * Create Account\n * * Allocate\n * * Instruction references an unknown account\n * */\n\n logger.warn(`Unable to parse log message: ${log}`);\n }\n }\n\n // Implement this in order to calculate block size\n res.forEach((r) => {\n (r as any).toJSON = () => {\n const { decodedMessage, ...rest } = r;\n return rest;\n };\n });\n\n return res;\n}\n\ntype DictionaryLog = {\n message: string;\n logIndex: number;\n programId: string;\n kind: 'data' | 'log' | 'other';\n};\n\nfunction wrapDictionaryLogs(\n logs: DictionaryLog[],\n decoder: SolanaDecoder,\n): SolanaLogMessage[] {\n return logs.map((l) => {\n let pendingDecode: Promise<DecodedData | null>;\n const res = {\n message: l.message,\n programId: l.programId,\n logIndex: l.logIndex,\n type: l.kind,\n get decodedMessage() {\n if (!['other', 'data'].includes(l.kind)) {\n return Promise.resolve(null);\n }\n\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n const { decodedMessage, ...rest } = res;\n return rest;\n };\n\n return res;\n });\n}\n\n/**\n * Transforms a block from a raw response to the types injected into handlers*/\nexport function transformBlock(\n block: RawSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaBlock {\n const { transactions, ...baseBlock } = block;\n return {\n ...baseBlock,\n transactions: transactions.map((tx) => {\n try {\n return {\n ...tx,\n block: baseBlock,\n transaction: {\n ...tx.transaction,\n message: {\n ...tx.transaction.message,\n instructions: tx.transaction.message.instructions.map(\n (instruction, index) =>\n wrapInstruction([index], instruction, tx, baseBlock, decoder),\n ),\n },\n },\n meta: tx.meta\n ? {\n ...tx.meta,\n innerInstructions: tx.meta.innerInstructions.map(\n (innerInstruction) => ({\n ...innerInstruction,\n instructions: innerInstruction.instructions.map(\n (instruction, innerIndex) =>\n wrapInstruction(\n [innerInstruction.index, innerIndex],\n instruction,\n tx,\n baseBlock,\n decoder,\n ),\n ),\n }),\n ),\n // Dictionary blocks have logs instead of logMessages that are already somewhat wrapped\n logs: (tx.meta as any).logs\n ? wrapDictionaryLogs((tx.meta as any).logs, decoder)\n : wrapLogs(tx.meta.logMessages, decoder),\n }\n : null,\n };\n } catch (e) {\n throw new Error(\n `Failed to transform transaction: ${tx.transaction.signatures[0]}`,\n { cause: e },\n );\n }\n }),\n };\n}\n\nexport function formatBlockUtil<B extends SolanaBlock = SolanaBlock>(\n block: B,\n): IBlock<B> {\n return {\n block,\n getHeader: () => solanaBlockToHeader(block),\n };\n}\n\nexport function solanaBlockToHeader(block: BaseSolanaBlock): Header {\n return {\n blockHeight: Number(block.parentSlot) + 1, // The blocks don't include the slot because they assume you know that when making the request\n blockHash: block.blockhash,\n parentHash: block.previousBlockhash,\n timestamp: new Date(Number(block.blockTime) * 1000),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"block.solana.js","sourceRoot":"","sources":["../../src/solana/block.solana.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;AA+MnC,wCAuDC;AAED,0CAOC;AAED,kDAOC;AAhRD,gDAAuE;AAUvE,MAAM,MAAM,GAAG,IAAA,qBAAS,EAAC,aAAa,CAAC,CAAC;AAiBxC,oEAAoE;AACpE,SAAS,IAAI,CAAI,KAAQ,EAAE,IAAiB;IAC1C,MAAM,IAAI,GAAwB,EAAE,CAAC;IAErC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAc,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,GAAI,KAAa,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CACtB,KAAe,EACf,WAGC,EACD,WAAsC,EACtC,KAAsB,EACtB,OAAsB;IAEtB,IAAI,aAA0C,CAAC;IAC/C,6GAA6G;IAC7G,MAAM,GAAG,GAAG;QACV,GAAG,WAAW;QACd,KAAK;QACL,WAAW;QACX,KAAK;QACL,IAAI,WAAW;YACb,aAAa,KAAK,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,aAAa,CAAC;QACvB,CAAC;KACF,CAAC;IAEF,kDAAkD;IACjD,GAAW,CAAC,MAAM,GAAG,GAAG,EAAE;QACzB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC;IAEF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CACf,IAA8B,EAC9B,OAAsB;IAEtB,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAuB,EAAE,CAAC;IAEnC,2CAA2C;IAC3C,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,aAA0C,CAAC;QAC/C,IAAI,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,GAAG;gBACZ,SAAS,EAAE,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;gBACtD,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;gBAC3B,IAAI,EAAE,KAAK;gBACX,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,GAAG;gBACZ,SAAS,EAAE,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;gBACtD,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;gBAC3B,IAAI,EAAE,MAAM;gBACZ,IAAI,cAAc;oBAChB,aAAa,KAAK,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAC1C,OAAO,aAAa,CAAC;gBACvB,CAAC,EAAE,gCAAgC;aACpC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC7C,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,GAAG;gBACZ,SAAS,EAAE,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;gBACtD,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;gBAC3B,IAAI,EAAE,OAAO;gBACb,IAAI,cAAc;oBAChB,aAAa,KAAK,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAC1C,OAAO,aAAa,CAAC;gBACvB,CAAC,EAAE,4DAA4D;aAChE,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAClD,aAAa;QACf,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,MAAM,CAAC,EAAE,cAAc,CAAC,cAAc,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,uCAAuC;YAChH,QAAQ,IAAI,EAAE,CAAC;gBACb,KAAK,QAAQ;oBACX,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;oBACrC,MAAM;gBACR,KAAK,SAAS;oBACZ,kDAAkD;oBAClD,eAAe,CAAC,GAAG,EAAE,CAAC;oBACtB,MAAM;gBACR,KAAK,UAAU;oBACb,aAAa;oBACb,MAAM;gBACR,KAAK,SAAS;oBACZ,OAAO;oBACP,eAAe,CAAC,GAAG,EAAE,CAAC;oBACtB,MAAM;gBACR;oBACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,UAAU,GAAG,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;aAAM,CAAC;YACN;;;;;;iBAMK;YAEL,MAAM,CAAC,IAAI,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACf,CAAS,CAAC,MAAM,GAAG,GAAG,EAAE;YACvB,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC;AASD,SAAS,kBAAkB,CACzB,IAAqB,EACrB,OAAsB;IAEtB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpB,IAAI,aAA0C,CAAC;QAC/C,MAAM,GAAG,GAAG;YACV,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,cAAc;gBAChB,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxC,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC/B,CAAC;gBAED,aAAa,KAAK,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC1C,OAAO,aAAa,CAAC;YACvB,CAAC;SACF,CAAC;QAEF,kDAAkD;QACjD,GAAW,CAAC,MAAM,GAAG,GAAG,EAAE;YACzB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED;+EAC+E;AAC/E,SAAgB,cAAc,CAC5B,KAAqB,EACrB,OAAsB;IAEtB,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;IAC7C,OAAO;QACL,GAAG,SAAS;QACZ,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,OAAO;oBACL,GAAG,EAAE;oBACL,KAAK,EAAE,SAAS;oBAChB,WAAW,EAAE;wBACX,GAAG,EAAE,CAAC,WAAW;wBACjB,OAAO,EAAE;4BACP,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO;4BACzB,YAAY,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,CACnD,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,CACrB,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAChE;yBACF;qBACF;oBACD,IAAI,EAAE,EAAE,CAAC,IAAI;wBACX,CAAC,CAAC;4BACE,GAAG,EAAE,CAAC,IAAI;4BACV,iBAAiB,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAC9C,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;gCACrB,GAAG,gBAAgB;gCACnB,YAAY,EAAE,gBAAgB,CAAC,YAAY,CAAC,GAAG,CAC7C,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,CAC1B,eAAe,CACb,CAAC,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,EACpC,WAAW,EACX,EAAE,EACF,SAAS,EACT,OAAO,CACR,CACJ;6BACF,CAAC,CACH;4BACD,uFAAuF;4BACvF,IAAI,EAAG,EAAE,CAAC,IAAY,CAAC,IAAI;gCACzB,CAAC,CAAC,kBAAkB,CAAE,EAAE,CAAC,IAAY,CAAC,IAAI,EAAE,OAAO,CAAC;gCACpD,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;yBAC3C;wBACH,CAAC,CAAC,IAAI;iBACT,CAAC;YACJ,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CACb,oCAAoC,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAClE,EAAE,KAAK,EAAE,CAAC,EAAE,CACb,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAgB,eAAe,CAC7B,KAAQ;IAER,OAAO;QACL,KAAK;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,SAAgB,mBAAmB,CAAC,KAAsB;IACxD,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,8FAA8F;QACzI,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,iBAAiB;QACnC,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;KACpD,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport type {\n UnixTimestamp,\n Blockhash,\n Slot,\n TransactionForFullJson,\n} from '@solana/rpc-types';\nimport { getLogger, type Header, type IBlock } from '@subql/node-core';\nimport type {\n SolanaBlock,\n BaseSolanaBlock,\n SolanaInstruction,\n DecodedData,\n SolanaLogMessage,\n} from '@subql/types-solana';\nimport { SolanaDecoder } from './decoder';\n\nconst logger = getLogger('SolanaBlock');\n\ntype RawSolanaBlock = Readonly<{\n /** The number of blocks beneath this block */\n blockHeight: bigint;\n /** Estimated production time, as Unix timestamp */\n blockTime: UnixTimestamp;\n /** the blockhash of this block */\n blockhash: Blockhash;\n /** The slot index of this block's parent */\n parentSlot: Slot;\n /** The blockhash of this block's parent */\n previousBlockhash: Blockhash;\n\n transactions: readonly TransactionForFullJson<0>[];\n}>;\n\n// We use this function to omit properties without accessing getters\nfunction omit<T>(input: T, omit: (keyof T)[]) {\n const json: Record<string, any> = {};\n\n for (const key of Object.getOwnPropertyNames(input)) {\n if (!omit.includes(key as keyof T)) {\n json[key] = (input as any)[key];\n }\n }\n\n return json;\n}\n\nfunction wrapInstruction(\n index: number[],\n instruction: Omit<\n SolanaInstruction,\n 'index' | 'block' | 'transaction' | 'decodedData'\n >,\n transaction: TransactionForFullJson<0>,\n block: BaseSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaInstruction {\n let pendingDecode: Promise<DecodedData | null>;\n // XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction\n const res = {\n ...instruction,\n index,\n transaction,\n block,\n get decodedData(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeInstruction(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n return omit(res, ['block', 'decodedData', 'transaction']);\n };\n\n return res;\n}\n\nfunction wrapLogs(\n logs: readonly string[] | null,\n decoder: SolanaDecoder,\n): SolanaLogMessage[] | null {\n if (logs === null) {\n return null;\n }\n const res: SolanaLogMessage[] = [];\n\n // Keep a stack of the instruction programs\n const instructionPath: string[] = [];\n\n for (const [idx, log] of Object.entries(logs)) {\n let pendingDecode: Promise<DecodedData | null>;\n if (log.startsWith('Program log:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'log',\n decodedMessage: Promise.resolve(null),\n });\n } else if (log.startsWith('Program data:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'data',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse\n });\n } else if (log.startsWith('Program return:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'other',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse, can return data be dcoded?\n });\n } else if (log.startsWith('Program consumption:')) {\n // DO nothing\n } else if (log.startsWith('Program')) {\n const [, /* \"Program\"*/ programAddress, mode, ...rest] = log.split(' '); // TODO doesn't work with compute units\n switch (mode) {\n case 'invoke':\n instructionPath.push(programAddress);\n break;\n case 'success':\n // TODO need to check this is always the last item\n instructionPath.pop();\n break;\n case 'consumed':\n // Do nothing\n break;\n case 'failed:':\n // TODO\n instructionPath.pop();\n break;\n default:\n throw new Error(`Unknown log mode: ${mode}, log: ${log}`);\n }\n } else {\n /**\n * Known examples (prefixes):\n * * Transfer\n * * Create Account\n * * Allocate\n * * Instruction references an unknown account\n * */\n\n logger.warn(`Unable to parse log message: ${log}`);\n }\n }\n\n // Implement this in order to calculate block size\n res.forEach((r) => {\n (r as any).toJSON = () => {\n return omit(r, ['decodedMessage']);\n };\n });\n\n return res;\n}\n\ntype DictionaryLog = {\n message: string;\n logIndex: number;\n programId: string;\n kind: 'data' | 'log' | 'other';\n};\n\nfunction wrapDictionaryLogs(\n logs: DictionaryLog[],\n decoder: SolanaDecoder,\n): SolanaLogMessage[] {\n return logs.map((l) => {\n let pendingDecode: Promise<DecodedData | null>;\n const res = {\n message: l.message,\n programId: l.programId,\n logIndex: l.logIndex,\n type: l.kind,\n get decodedMessage() {\n if (!['other', 'data'].includes(l.kind)) {\n return Promise.resolve(null);\n }\n\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n return omit(res, ['decodedMessage']);\n };\n\n return res;\n });\n}\n\n/**\n * Transforms a block from a raw response to the types injected into handlers*/\nexport function transformBlock(\n block: RawSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaBlock {\n const { transactions, ...baseBlock } = block;\n return {\n ...baseBlock,\n transactions: transactions.map((tx) => {\n try {\n return {\n ...tx,\n block: baseBlock,\n transaction: {\n ...tx.transaction,\n message: {\n ...tx.transaction.message,\n instructions: tx.transaction.message.instructions.map(\n (instruction, index) =>\n wrapInstruction([index], instruction, tx, baseBlock, decoder),\n ),\n },\n },\n meta: tx.meta\n ? {\n ...tx.meta,\n innerInstructions: tx.meta.innerInstructions.map(\n (innerInstruction) => ({\n ...innerInstruction,\n instructions: innerInstruction.instructions.map(\n (instruction, innerIndex) =>\n wrapInstruction(\n [innerInstruction.index, innerIndex],\n instruction,\n tx,\n baseBlock,\n decoder,\n ),\n ),\n }),\n ),\n // Dictionary blocks have logs instead of logMessages that are already somewhat wrapped\n logs: (tx.meta as any).logs\n ? wrapDictionaryLogs((tx.meta as any).logs, decoder)\n : wrapLogs(tx.meta.logMessages, decoder),\n }\n : null,\n };\n } catch (e) {\n throw new Error(\n `Failed to transform transaction: ${tx.transaction.signatures[0]}`,\n { cause: e },\n );\n }\n }),\n };\n}\n\nexport function formatBlockUtil<B extends SolanaBlock = SolanaBlock>(\n block: B,\n): IBlock<B> {\n return {\n block,\n getHeader: () => solanaBlockToHeader(block),\n };\n}\n\nexport function solanaBlockToHeader(block: BaseSolanaBlock): Header {\n return {\n blockHeight: Number(block.parentSlot) + 1, // The blocks don't include the slot because they assume you know that when making the request\n blockHash: block.blockhash,\n parentHash: block.previousBlockhash,\n timestamp: new Date(Number(block.blockTime) * 1000),\n };\n}\n"]}
|
|
@@ -14,6 +14,9 @@ const HTTP_ENDPOINT = process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinalit
|
|
|
14
14
|
const IDL_Jupiter = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');
|
|
15
15
|
const IDL_swap = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');
|
|
16
16
|
const IDL_token = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');
|
|
17
|
+
function findTx(block, sig) {
|
|
18
|
+
return block.transactions.find((tx) => tx.transaction.signatures.find((s) => s === sig));
|
|
19
|
+
}
|
|
17
20
|
describe('SolanaDecoder', () => {
|
|
18
21
|
let solanaApi;
|
|
19
22
|
let decoder;
|
|
@@ -112,8 +115,7 @@ describe('SolanaDecoder', () => {
|
|
|
112
115
|
};
|
|
113
116
|
it('can decode an instruction with an IDL file', async () => {
|
|
114
117
|
//https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi
|
|
115
|
-
const tx = blockData
|
|
116
|
-
'3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi'));
|
|
118
|
+
const tx = findTx(blockData, '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi');
|
|
117
119
|
const instruction = tx.transaction.message.instructions[3];
|
|
118
120
|
const decoded = await decoder.decodeInstruction(instruction);
|
|
119
121
|
expect(decoded).toBeDefined();
|
|
@@ -123,8 +125,7 @@ describe('SolanaDecoder', () => {
|
|
|
123
125
|
// Since removing anchor we don't have a way of fetching IDLS
|
|
124
126
|
it.skip('can decode an instruction with an IDL found on chain', async () => {
|
|
125
127
|
// https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi
|
|
126
|
-
const tx = blockData
|
|
127
|
-
'3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi'));
|
|
128
|
+
const tx = findTx(blockData, '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi');
|
|
128
129
|
const instruction = tx.transaction.message.instructions[3];
|
|
129
130
|
const decoded = await decoder.decodeInstruction(instruction);
|
|
130
131
|
expect(decoded).toBeDefined();
|
|
@@ -132,8 +133,7 @@ describe('SolanaDecoder', () => {
|
|
|
132
133
|
expect(decoded.data).toEqual(instructionData);
|
|
133
134
|
});
|
|
134
135
|
it('can decode SPL token program instructions', async () => {
|
|
135
|
-
const tx = blockData
|
|
136
|
-
'61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL'));
|
|
136
|
+
const tx = findTx(blockData, '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL');
|
|
137
137
|
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
|
|
138
138
|
const instruction = tx.meta?.innerInstructions.find((inner) => inner.index === 0)?.instructions[1];
|
|
139
139
|
const program = (0, utils_solana_1.getProgramId)(instruction);
|
|
@@ -163,8 +163,7 @@ describe('SolanaDecoder', () => {
|
|
|
163
163
|
};
|
|
164
164
|
it('can decode a log with an Anchor IDL file', async () => {
|
|
165
165
|
// https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig
|
|
166
|
-
const tx = blockData
|
|
167
|
-
'5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig'));
|
|
166
|
+
const tx = findTx(blockData, '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig');
|
|
168
167
|
const programLogs = tx.meta.logs?.filter((l) => l.message.startsWith('Program data:'));
|
|
169
168
|
expect(programLogs?.length).toBe(1);
|
|
170
169
|
const decoded = await decoder.decodeLog(programLogs[0]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoder.spec.js","sourceRoot":"","sources":["../../src/solana/decoder.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { SolanaBlock } from '@subql/types-solana';\nimport bs58 from 'bs58';\nimport { RootNode } from 'codama';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport { getProgramId } from './utils.solana';\n\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_Jupiter: IdlV01 = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\nconst IDL_token: RootNode = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');\n\ndescribe('SolanaDecoder', () => {\n let solanaApi: SolanaApi;\n let decoder: SolanaDecoder;\n let blockData: SolanaBlock;\n\n beforeAll(async () => {\n decoder = new SolanaDecoder();\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n new EventEmitter2(),\n decoder,\n );\n });\n\n const loadDecoderIdls = () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'] = IDL_Jupiter;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW'] = IDL_swap;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'] = IDL_token;\n };\n\n describe('caching IDLs', () => {\n // Fetching IDLs from the network is not currently supported\n it.skip('caches IDLs from the network', async () => {\n const spy = jest.spyOn(solanaApi, 'getAccountInfo');\n\n const mockInst = {\n transaction: {\n transaction: {\n message: {\n accountKeys: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],\n },\n },\n },\n data: '',\n programIdIndex: 0,\n };\n\n await decoder.decodeInstruction(mockInst as any);\n await decoder.decodeInstruction(mockInst as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n\n await decoder.decodeLog({\n programId: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n message: '',\n } as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n });\n });\n\n describe('parsing instruction discriminators', () => {\n beforeAll(() => {\n loadDecoderIdls();\n });\n\n it('correctly parses Anchor program discriminators', () => {\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses SPL program discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n const inst = IDL_token.program.instructions[i];\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n });\n\n it('correctly parses hex discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from([i]).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from(inst.discriminator).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses base58 discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from([i])),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from(inst.discriminator)),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n });\n\n describe('decode instrutions', () => {\n beforeAll(async () => {\n // https://solscan.io/block/330469167\n const { block } = await solanaApi.fetchBlock(330_469_167);\n blockData = block;\n\n loadDecoderIdls();\n }, 30_000);\n\n const instructionData = {\n routePlan: [\n {\n swap: {\n __kind: 'MeteoraDlmm',\n },\n percent: 100,\n inputIndex: 0,\n outputIndex: 1,\n },\n ],\n inAmount: BigInt(16000),\n quotedOutAmount: BigInt(126754),\n slippageBps: 200,\n platformFeeBps: 98,\n };\n\n it('can decode an instruction with an IDL file', async () => {\n //https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n ),\n );\n const instruction = tx!.transaction.message.instructions[3];\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n // Since removing anchor we don't have a way of fetching IDLS\n it.skip('can decode an instruction with an IDL found on chain', async () => {\n // https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n ),\n );\n const instruction = tx!.transaction.message.instructions[3];\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n it('can decode SPL token program instructions', async () => {\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL',\n ),\n );\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const instruction = tx!.meta?.innerInstructions.find(\n (inner) => inner.index === 0,\n )?.instructions[1]!;\n\n const program = getProgramId(instruction);\n expect(program).toBe('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toEqual({\n name: 'transferChecked',\n data: {\n amount: BigInt('5904646875'),\n decimals: 6,\n },\n });\n });\n });\n\n describe('decode log', () => {\n beforeAll(async () => {\n //https://solscan.io/block/327347682\n const { block } = await solanaApi.fetchBlock(327_347_682);\n loadDecoderIdls();\n blockData = block;\n }, 30_000);\n\n const logData = {\n pubkey: 'BQR6JJFyMWxnUERqbCRCCy1ietW2yq8RTKDx9odzruha',\n data: {\n balances: [BigInt('16648442361'), BigInt('4003645427000')],\n },\n };\n\n it('can decode a log with an Anchor IDL file', async () => {\n // https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig',\n ),\n );\n\n const programLogs = tx!.meta!.logs?.filter((l) =>\n l.message.startsWith('Program data:'),\n );\n expect(programLogs?.length).toBe(1);\n\n const decoded = await decoder.decodeLog(programLogs![0]);\n\n expect(decoded).not.toBeNull();\n expect(decoded!.name).toBe('poolBalanceUpdatedEvent');\n expect(decoded!.data).toEqual(logData);\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"decoder.spec.js","sourceRoot":"","sources":["../../src/solana/decoder.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { SolanaBlock, SolanaTransaction } from '@subql/types-solana';\nimport bs58 from 'bs58';\nimport { RootNode } from 'codama';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport { getProgramId, filterInstructionsProcessor } from './utils.solana';\n\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_Jupiter: IdlV01 = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\nconst IDL_token: RootNode = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');\n\nfunction findTx(\n block: SolanaBlock,\n sig: string,\n): SolanaTransaction | undefined {\n return block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n}\n\ndescribe('SolanaDecoder', () => {\n let solanaApi: SolanaApi;\n let decoder: SolanaDecoder;\n let blockData: SolanaBlock;\n\n beforeAll(async () => {\n decoder = new SolanaDecoder();\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n new EventEmitter2(),\n decoder,\n );\n });\n\n const loadDecoderIdls = () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'] = IDL_Jupiter;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW'] = IDL_swap;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'] = IDL_token;\n };\n\n describe('caching IDLs', () => {\n // Fetching IDLs from the network is not currently supported\n it.skip('caches IDLs from the network', async () => {\n const spy = jest.spyOn(solanaApi, 'getAccountInfo');\n\n const mockInst = {\n transaction: {\n transaction: {\n message: {\n accountKeys: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],\n },\n },\n },\n data: '',\n programIdIndex: 0,\n };\n\n await decoder.decodeInstruction(mockInst as any);\n await decoder.decodeInstruction(mockInst as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n\n await decoder.decodeLog({\n programId: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n message: '',\n } as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n });\n });\n\n describe('parsing instruction discriminators', () => {\n beforeAll(() => {\n loadDecoderIdls();\n });\n\n it('correctly parses Anchor program discriminators', () => {\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses SPL program discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n const inst = IDL_token.program.instructions[i];\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n });\n\n it('correctly parses hex discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from([i]).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from(inst.discriminator).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses base58 discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from([i])),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from(inst.discriminator)),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n });\n\n describe('decode instrutions', () => {\n beforeAll(async () => {\n // https://solscan.io/block/330469167\n const { block } = await solanaApi.fetchBlock(330_469_167);\n blockData = block;\n\n loadDecoderIdls();\n }, 30_000);\n\n const instructionData = {\n routePlan: [\n {\n swap: {\n __kind: 'MeteoraDlmm',\n },\n percent: 100,\n inputIndex: 0,\n outputIndex: 1,\n },\n ],\n inAmount: BigInt(16000),\n quotedOutAmount: BigInt(126754),\n slippageBps: 200,\n platformFeeBps: 98,\n };\n\n it('can decode an instruction with an IDL file', async () => {\n //https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = findTx(\n blockData,\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n );\n const instruction = tx!.transaction.message.instructions[3];\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n // Since removing anchor we don't have a way of fetching IDLS\n it.skip('can decode an instruction with an IDL found on chain', async () => {\n // https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = findTx(\n blockData,\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n );\n\n const instruction = tx!.transaction.message.instructions[3];\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n it('can decode SPL token program instructions', async () => {\n const tx = findTx(\n blockData,\n '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL',\n );\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const instruction = tx!.meta?.innerInstructions.find(\n (inner) => inner.index === 0,\n )?.instructions[1]!;\n\n const program = getProgramId(instruction);\n expect(program).toBe('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toEqual({\n name: 'transferChecked',\n data: {\n amount: BigInt('5904646875'),\n decimals: 6,\n },\n });\n });\n });\n\n describe('decode log', () => {\n beforeAll(async () => {\n //https://solscan.io/block/327347682\n const { block } = await solanaApi.fetchBlock(327_347_682);\n loadDecoderIdls();\n blockData = block;\n }, 30_000);\n\n const logData = {\n pubkey: 'BQR6JJFyMWxnUERqbCRCCy1ietW2yq8RTKDx9odzruha',\n data: {\n balances: [BigInt('16648442361'), BigInt('4003645427000')],\n },\n };\n\n it('can decode a log with an Anchor IDL file', async () => {\n // https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig\n const tx = findTx(\n blockData,\n '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig',\n );\n\n const programLogs = tx!.meta!.logs?.filter((l) =>\n l.message.startsWith('Program data:'),\n );\n expect(programLogs?.length).toBe(1);\n\n const decoded = await decoder.decodeLog(programLogs![0]);\n\n expect(decoded).not.toBeNull();\n expect(decoded!.name).toBe('poolBalanceUpdatedEvent');\n expect(decoded!.data).toEqual(logData);\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subql/node-solana",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.3-0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "Ian He",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"/dist",
|
|
66
66
|
"/bin"
|
|
67
67
|
],
|
|
68
|
-
"stableVersion": "6.0.
|
|
68
|
+
"stableVersion": "6.0.2"
|
|
69
69
|
}
|