@subql/node-stellar 2.9.3-2
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 +7 -0
- package/LICENSE +674 -0
- package/README.md +77 -0
- package/bin/run +4 -0
- package/bin/run.cmd +3 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/app.module.d.ts +2 -0
- package/dist/app.module.js +35 -0
- package/dist/app.module.js.map +1 -0
- package/dist/configure/SubqueryProject.d.ts +25 -0
- package/dist/configure/SubqueryProject.js +148 -0
- package/dist/configure/SubqueryProject.js.map +1 -0
- package/dist/configure/configure.module.d.ts +10 -0
- package/dist/configure/configure.module.js +129 -0
- package/dist/configure/configure.module.js.map +1 -0
- package/dist/indexer/blockDispatcher/block-dispatcher.service.d.ts +16 -0
- package/dist/indexer/blockDispatcher/block-dispatcher.service.js +54 -0
- package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -0
- package/dist/indexer/blockDispatcher/index.d.ts +4 -0
- package/dist/indexer/blockDispatcher/index.js +10 -0
- package/dist/indexer/blockDispatcher/index.js.map +1 -0
- package/dist/indexer/blockDispatcher/stellar-block-dispatcher.d.ts +4 -0
- package/dist/indexer/blockDispatcher/stellar-block-dispatcher.js +5 -0
- package/dist/indexer/blockDispatcher/stellar-block-dispatcher.js.map +1 -0
- package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.d.ts +16 -0
- package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js +78 -0
- package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js.map +1 -0
- package/dist/indexer/dictionary.service.d.ts +7 -0
- package/dist/indexer/dictionary.service.js +34 -0
- package/dist/indexer/dictionary.service.js.map +1 -0
- package/dist/indexer/ds-processor.service.d.ts +9 -0
- package/dist/indexer/ds-processor.service.js +46 -0
- package/dist/indexer/ds-processor.service.js.map +1 -0
- package/dist/indexer/dynamic-ds.service.d.ts +9 -0
- package/dist/indexer/dynamic-ds.service.js +71 -0
- package/dist/indexer/dynamic-ds.service.js.map +1 -0
- package/dist/indexer/fetch.module.d.ts +2 -0
- package/dist/indexer/fetch.module.js +93 -0
- package/dist/indexer/fetch.module.js.map +1 -0
- package/dist/indexer/fetch.service.d.ts +33 -0
- package/dist/indexer/fetch.service.js +201 -0
- package/dist/indexer/fetch.service.js.map +1 -0
- package/dist/indexer/fetch.service.spec.d.ts +1 -0
- package/dist/indexer/fetch.service.spec.js +58 -0
- package/dist/indexer/fetch.service.spec.js.map +1 -0
- package/dist/indexer/indexer.manager.d.ts +36 -0
- package/dist/indexer/indexer.manager.js +92 -0
- package/dist/indexer/indexer.manager.js.map +1 -0
- package/dist/indexer/indexer.module.d.ts +2 -0
- package/dist/indexer/indexer.module.js +86 -0
- package/dist/indexer/indexer.module.js.map +1 -0
- package/dist/indexer/project.service.d.ts +13 -0
- package/dist/indexer/project.service.js +60 -0
- package/dist/indexer/project.service.js.map +1 -0
- package/dist/indexer/sandbox.service.d.ts +13 -0
- package/dist/indexer/sandbox.service.js +64 -0
- package/dist/indexer/sandbox.service.js.map +1 -0
- package/dist/indexer/types.d.ts +1 -0
- package/dist/indexer/types.js +5 -0
- package/dist/indexer/types.js.map +1 -0
- package/dist/indexer/unfinalizedBlocks.service.d.ts +11 -0
- package/dist/indexer/unfinalizedBlocks.service.js +52 -0
- package/dist/indexer/unfinalizedBlocks.service.js.map +1 -0
- package/dist/indexer/worker/worker.d.ts +31 -0
- package/dist/indexer/worker/worker.js +103 -0
- package/dist/indexer/worker/worker.js.map +1 -0
- package/dist/indexer/worker/worker.module.d.ts +2 -0
- package/dist/indexer/worker/worker.module.js +33 -0
- package/dist/indexer/worker/worker.module.js.map +1 -0
- package/dist/indexer/worker/worker.service.d.ts +26 -0
- package/dist/indexer/worker/worker.service.js +90 -0
- package/dist/indexer/worker/worker.service.js.map +1 -0
- package/dist/indexer/worker/worker.unfinalizedBlocks.service.d.ts +16 -0
- package/dist/indexer/worker/worker.unfinalizedBlocks.service.js +50 -0
- package/dist/indexer/worker/worker.unfinalizedBlocks.service.js.map +1 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +52 -0
- package/dist/init.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +22 -0
- package/dist/main.js.map +1 -0
- package/dist/meta/meta.controller.d.ts +21 -0
- package/dist/meta/meta.controller.js +36 -0
- package/dist/meta/meta.controller.js.map +1 -0
- package/dist/meta/meta.module.d.ts +2 -0
- package/dist/meta/meta.module.js +28 -0
- package/dist/meta/meta.module.js.map +1 -0
- package/dist/meta/meta.service.d.ts +24 -0
- package/dist/meta/meta.service.js +121 -0
- package/dist/meta/meta.service.js.map +1 -0
- package/dist/stellar/api.connection.d.ts +20 -0
- package/dist/stellar/api.connection.js +63 -0
- package/dist/stellar/api.connection.js.map +1 -0
- package/dist/stellar/api.connection.spec.d.ts +1 -0
- package/dist/stellar/api.connection.spec.js +81 -0
- package/dist/stellar/api.connection.spec.js.map +1 -0
- package/dist/stellar/api.service.stellar.d.ts +18 -0
- package/dist/stellar/api.service.stellar.js +144 -0
- package/dist/stellar/api.service.stellar.js.map +1 -0
- package/dist/stellar/api.service.stellar.spec.d.ts +5 -0
- package/dist/stellar/api.service.stellar.spec.js +87 -0
- package/dist/stellar/api.service.stellar.spec.js.map +1 -0
- package/dist/stellar/api.stellar.d.ts +29 -0
- package/dist/stellar/api.stellar.js +116 -0
- package/dist/stellar/api.stellar.js.map +1 -0
- package/dist/stellar/api.stellar.spec.d.ts +1 -0
- package/dist/stellar/api.stellar.spec.js +81 -0
- package/dist/stellar/api.stellar.spec.js.map +1 -0
- package/dist/stellar/block.stellar.d.ts +11 -0
- package/dist/stellar/block.stellar.js +81 -0
- package/dist/stellar/block.stellar.js.map +1 -0
- package/dist/stellar/block.stellar.spec.d.ts +1 -0
- package/dist/stellar/block.stellar.spec.js +58 -0
- package/dist/stellar/block.stellar.spec.js.map +1 -0
- package/dist/stellar/index.d.ts +2 -0
- package/dist/stellar/index.js +21 -0
- package/dist/stellar/index.js.map +1 -0
- package/dist/stellar/safe-api.d.ts +20 -0
- package/dist/stellar/safe-api.js +67 -0
- package/dist/stellar/safe-api.js.map +1 -0
- package/dist/stellar/stellar.server.d.ts +8 -0
- package/dist/stellar/stellar.server.js +72 -0
- package/dist/stellar/stellar.server.js.map +1 -0
- package/dist/stellar/stellar.server.spec.d.ts +1 -0
- package/dist/stellar/stellar.server.spec.js +132 -0
- package/dist/stellar/stellar.server.spec.js.map +1 -0
- package/dist/stellar/utils.stellar.d.ts +2 -0
- package/dist/stellar/utils.stellar.js +10 -0
- package/dist/stellar/utils.stellar.js.map +1 -0
- package/dist/subcommands/forceClean.init.d.ts +1 -0
- package/dist/subcommands/forceClean.init.js +24 -0
- package/dist/subcommands/forceClean.init.js.map +1 -0
- package/dist/subcommands/forceClean.module.d.ts +2 -0
- package/dist/subcommands/forceClean.module.js +28 -0
- package/dist/subcommands/forceClean.module.js.map +1 -0
- package/dist/subcommands/mmrMigrate.init.d.ts +2 -0
- package/dist/subcommands/mmrMigrate.init.js +28 -0
- package/dist/subcommands/mmrMigrate.init.js.map +1 -0
- package/dist/subcommands/mmrMigrate.module.d.ts +2 -0
- package/dist/subcommands/mmrMigrate.module.js +28 -0
- package/dist/subcommands/mmrMigrate.module.js.map +1 -0
- package/dist/subcommands/mmrRegenerate.init.d.ts +1 -0
- package/dist/subcommands/mmrRegenerate.init.js +28 -0
- package/dist/subcommands/mmrRegenerate.init.js.map +1 -0
- package/dist/subcommands/mmrRegenerate.module.d.ts +2 -0
- package/dist/subcommands/mmrRegenerate.module.js +30 -0
- package/dist/subcommands/mmrRegenerate.module.js.map +1 -0
- package/dist/subcommands/reindex.init.d.ts +1 -0
- package/dist/subcommands/reindex.init.js +30 -0
- package/dist/subcommands/reindex.init.js.map +1 -0
- package/dist/subcommands/reindex.module.d.ts +4 -0
- package/dist/subcommands/reindex.module.js +60 -0
- package/dist/subcommands/reindex.module.js.map +1 -0
- package/dist/subcommands/reindex.service.d.ts +11 -0
- package/dist/subcommands/reindex.service.js +46 -0
- package/dist/subcommands/reindex.service.js.map +1 -0
- package/dist/subcommands/testing.init.d.ts +1 -0
- package/dist/subcommands/testing.init.js +25 -0
- package/dist/subcommands/testing.init.js.map +1 -0
- package/dist/subcommands/testing.module.d.ts +4 -0
- package/dist/subcommands/testing.module.js +88 -0
- package/dist/subcommands/testing.module.js.map +1 -0
- package/dist/subcommands/testing.service.d.ts +9 -0
- package/dist/subcommands/testing.service.js +49 -0
- package/dist/subcommands/testing.service.js.map +1 -0
- package/dist/utils/project.d.ts +6 -0
- package/dist/utils/project.js +33 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/string.d.ts +1 -0
- package/dist/utils/string.js +10 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/yargs.d.ts +303 -0
- package/dist/yargs.js +381 -0
- package/dist/yargs.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
4
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
5
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
7
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
8
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
9
|
+
};
|
|
10
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.MetaService = void 0;
|
|
15
|
+
const common_1 = require("@nestjs/common");
|
|
16
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
17
|
+
const schedule_1 = require("@nestjs/schedule");
|
|
18
|
+
const node_core_1 = require("@subql/node-core");
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20
|
+
const { version: stellarSdkVersion } = require('soroban-client/package.json');
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
22
|
+
const { version: packageVersion } = require('../../package.json');
|
|
23
|
+
const logger = (0, node_core_1.getLogger)('profiler');
|
|
24
|
+
let MetaService = class MetaService extends node_core_1.BaseMetaService {
|
|
25
|
+
constructor(nodeConfig, storeCacheService) {
|
|
26
|
+
super(storeCacheService, nodeConfig);
|
|
27
|
+
this.nodeConfig = nodeConfig;
|
|
28
|
+
this.accEnqueueBlocks = 0;
|
|
29
|
+
this.accFetchBlocks = 0;
|
|
30
|
+
this.currentFilteringBlockNum = 0;
|
|
31
|
+
this.accRpcCalls = 0;
|
|
32
|
+
this.lastReportedFilteringBlockNum = 0;
|
|
33
|
+
this.lastReportedEnqueueBlocks = 0;
|
|
34
|
+
this.lastReportedFetchBlocks = 0;
|
|
35
|
+
this.lastReportedRpcCalls = 0;
|
|
36
|
+
this.packageVersion = packageVersion;
|
|
37
|
+
}
|
|
38
|
+
sdkVersion() {
|
|
39
|
+
return { name: 'stellarSdkVersion', version: stellarSdkVersion };
|
|
40
|
+
}
|
|
41
|
+
handleEnqueueBlocks(size) {
|
|
42
|
+
this.accEnqueueBlocks += size;
|
|
43
|
+
if (!this.lastStatsReportedTs) {
|
|
44
|
+
this.lastStatsReportedTs = new Date();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
handleFilteringBlocks(height) {
|
|
48
|
+
this.currentFilteringBlockNum = height;
|
|
49
|
+
if (!this.lastStatsReportedTs) {
|
|
50
|
+
this.lastReportedFilteringBlockNum = height;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
handleFetchBlock() {
|
|
54
|
+
this.accFetchBlocks++;
|
|
55
|
+
if (!this.lastStatsReportedTs) {
|
|
56
|
+
this.lastStatsReportedTs = new Date();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
handleRpcCall() {
|
|
60
|
+
this.accRpcCalls++;
|
|
61
|
+
if (!this.lastStatsReportedTs) {
|
|
62
|
+
this.lastStatsReportedTs = new Date();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
blockFilteringSpeed() {
|
|
66
|
+
if (!this.nodeConfig.profiler) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const count = this.accEnqueueBlocks - this.lastReportedEnqueueBlocks;
|
|
70
|
+
this.lastReportedEnqueueBlocks = this.accEnqueueBlocks;
|
|
71
|
+
const filteringCount = this.currentFilteringBlockNum - this.lastReportedFilteringBlockNum;
|
|
72
|
+
const now = new Date();
|
|
73
|
+
const timepass = now.getTime() - this.lastStatsReportedTs.getTime();
|
|
74
|
+
this.lastStatsReportedTs = now;
|
|
75
|
+
this.lastReportedFilteringBlockNum = this.currentFilteringBlockNum;
|
|
76
|
+
const rpcCalls = this.accRpcCalls - this.lastReportedRpcCalls;
|
|
77
|
+
this.lastReportedRpcCalls = this.accRpcCalls;
|
|
78
|
+
const fetchCount = this.accFetchBlocks - this.lastReportedFetchBlocks;
|
|
79
|
+
this.lastReportedFetchBlocks = this.accFetchBlocks;
|
|
80
|
+
logger.info(`actual block filtering: ${(count / (timepass / 1000)).toFixed(2)}/sec, \
|
|
81
|
+
seeming speed: ${(filteringCount / (timepass / 1000)).toFixed(2)}/sec, rpcCalls: ${(rpcCalls / (timepass / 1000)).toFixed(2)}/sec \
|
|
82
|
+
fetch speed: ${(fetchCount / (timepass / 1000)).toFixed(2)}/sec`);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
__decorate([
|
|
86
|
+
(0, event_emitter_1.OnEvent)('enqueueBlocks'),
|
|
87
|
+
__metadata("design:type", Function),
|
|
88
|
+
__metadata("design:paramtypes", [Number]),
|
|
89
|
+
__metadata("design:returntype", void 0)
|
|
90
|
+
], MetaService.prototype, "handleEnqueueBlocks", null);
|
|
91
|
+
__decorate([
|
|
92
|
+
(0, event_emitter_1.OnEvent)('filteringBlocks'),
|
|
93
|
+
__metadata("design:type", Function),
|
|
94
|
+
__metadata("design:paramtypes", [Number]),
|
|
95
|
+
__metadata("design:returntype", void 0)
|
|
96
|
+
], MetaService.prototype, "handleFilteringBlocks", null);
|
|
97
|
+
__decorate([
|
|
98
|
+
(0, event_emitter_1.OnEvent)('fetchBlock'),
|
|
99
|
+
__metadata("design:type", Function),
|
|
100
|
+
__metadata("design:paramtypes", []),
|
|
101
|
+
__metadata("design:returntype", void 0)
|
|
102
|
+
], MetaService.prototype, "handleFetchBlock", null);
|
|
103
|
+
__decorate([
|
|
104
|
+
(0, event_emitter_1.OnEvent)('rpcCall'),
|
|
105
|
+
__metadata("design:type", Function),
|
|
106
|
+
__metadata("design:paramtypes", []),
|
|
107
|
+
__metadata("design:returntype", void 0)
|
|
108
|
+
], MetaService.prototype, "handleRpcCall", null);
|
|
109
|
+
__decorate([
|
|
110
|
+
(0, schedule_1.Interval)(10000),
|
|
111
|
+
__metadata("design:type", Function),
|
|
112
|
+
__metadata("design:paramtypes", []),
|
|
113
|
+
__metadata("design:returntype", void 0)
|
|
114
|
+
], MetaService.prototype, "blockFilteringSpeed", null);
|
|
115
|
+
MetaService = __decorate([
|
|
116
|
+
(0, common_1.Injectable)(),
|
|
117
|
+
__metadata("design:paramtypes", [node_core_1.NodeConfig,
|
|
118
|
+
node_core_1.StoreCacheService])
|
|
119
|
+
], MetaService);
|
|
120
|
+
exports.MetaService = MetaService;
|
|
121
|
+
//# sourceMappingURL=meta.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.service.js","sourceRoot":"","sources":["../../src/meta/meta.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Injectable } from '@nestjs/common';\nimport { OnEvent } from '@nestjs/event-emitter';\nimport { Interval } from '@nestjs/schedule';\nimport {\n BaseMetaService,\n getLogger,\n NodeConfig,\n StoreCacheService,\n} from '@subql/node-core';\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { version: stellarSdkVersion } = require('soroban-client/package.json');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { version: packageVersion } = require('../../package.json');\nconst logger = getLogger('profiler');\n\n@Injectable()\nexport class MetaService extends BaseMetaService {\n private accEnqueueBlocks = 0;\n private accFetchBlocks = 0;\n private currentFilteringBlockNum = 0;\n private accRpcCalls = 0;\n private lastReportedFilteringBlockNum = 0;\n private lastReportedEnqueueBlocks = 0;\n private lastReportedFetchBlocks = 0;\n private lastReportedRpcCalls = 0;\n private lastStatsReportedTs: Date;\n\n constructor(\n private nodeConfig: NodeConfig,\n storeCacheService: StoreCacheService,\n ) {\n super(storeCacheService, nodeConfig);\n }\n\n protected packageVersion = packageVersion;\n protected sdkVersion(): { name: string; version: string } {\n return { name: 'stellarSdkVersion', version: stellarSdkVersion };\n }\n\n @OnEvent('enqueueBlocks')\n handleEnqueueBlocks(size: number): void {\n this.accEnqueueBlocks += size;\n if (!this.lastStatsReportedTs) {\n this.lastStatsReportedTs = new Date();\n }\n }\n\n @OnEvent('filteringBlocks')\n handleFilteringBlocks(height: number): void {\n this.currentFilteringBlockNum = height;\n if (!this.lastStatsReportedTs) {\n this.lastReportedFilteringBlockNum = height;\n }\n }\n\n @OnEvent('fetchBlock')\n handleFetchBlock(): void {\n this.accFetchBlocks++;\n if (!this.lastStatsReportedTs) {\n this.lastStatsReportedTs = new Date();\n }\n }\n\n @OnEvent('rpcCall')\n handleRpcCall(): void {\n this.accRpcCalls++;\n if (!this.lastStatsReportedTs) {\n this.lastStatsReportedTs = new Date();\n }\n }\n\n @Interval(10000)\n blockFilteringSpeed(): void {\n if (!this.nodeConfig.profiler) {\n return;\n }\n const count = this.accEnqueueBlocks - this.lastReportedEnqueueBlocks;\n this.lastReportedEnqueueBlocks = this.accEnqueueBlocks;\n const filteringCount =\n this.currentFilteringBlockNum - this.lastReportedFilteringBlockNum;\n const now = new Date();\n const timepass = now.getTime() - this.lastStatsReportedTs.getTime();\n this.lastStatsReportedTs = now;\n this.lastReportedFilteringBlockNum = this.currentFilteringBlockNum;\n const rpcCalls = this.accRpcCalls - this.lastReportedRpcCalls;\n this.lastReportedRpcCalls = this.accRpcCalls;\n const fetchCount = this.accFetchBlocks - this.lastReportedFetchBlocks;\n this.lastReportedFetchBlocks = this.accFetchBlocks;\n logger.info(`actual block filtering: ${(count / (timepass / 1000)).toFixed(\n 2,\n )}/sec, \\\nseeming speed: ${(filteringCount / (timepass / 1000)).toFixed(\n 2,\n )}/sec, rpcCalls: ${(rpcCalls / (timepass / 1000)).toFixed(2)}/sec \\\nfetch speed: ${(fetchCount / (timepass / 1000)).toFixed(2)}/sec`);\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
2
|
+
import { ApiConnectionError, IApiConnectionSpecific, NetworkMetadataPayload } from '@subql/node-core';
|
|
3
|
+
import { StellarBlockWrapper } from '@subql/types-stellar';
|
|
4
|
+
import { StellarApi } from './api.stellar';
|
|
5
|
+
import SafeStellarProvider from './safe-api';
|
|
6
|
+
type FetchFunc = (api: StellarApi, batch: number[]) => Promise<StellarBlockWrapper[]>;
|
|
7
|
+
export declare class StellarApiConnection implements IApiConnectionSpecific<StellarApi, SafeStellarProvider, StellarBlockWrapper> {
|
|
8
|
+
unsafeApi: StellarApi;
|
|
9
|
+
private fetchBlocksBatches;
|
|
10
|
+
readonly networkMeta: NetworkMetadataPayload;
|
|
11
|
+
constructor(unsafeApi: StellarApi, fetchBlocksBatches: FetchFunc);
|
|
12
|
+
static create(endpoint: string, fetchBlockBatches: FetchFunc, eventEmitter: EventEmitter2): Promise<StellarApiConnection>;
|
|
13
|
+
safeApi(height: number): SafeStellarProvider;
|
|
14
|
+
apiConnect(): Promise<void>;
|
|
15
|
+
apiDisconnect(): Promise<void>;
|
|
16
|
+
fetchBlocks(heights: number[]): Promise<StellarBlockWrapper[]>;
|
|
17
|
+
handleError: typeof StellarApiConnection.handleError;
|
|
18
|
+
static handleError(e: Error): ApiConnectionError;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.StellarApiConnection = void 0;
|
|
9
|
+
const node_core_1 = require("@subql/node-core");
|
|
10
|
+
const api_stellar_1 = require("./api.stellar");
|
|
11
|
+
const safe_api_1 = __importDefault(require("./safe-api"));
|
|
12
|
+
class StellarApiConnection {
|
|
13
|
+
constructor(unsafeApi, fetchBlocksBatches) {
|
|
14
|
+
this.unsafeApi = unsafeApi;
|
|
15
|
+
this.fetchBlocksBatches = fetchBlocksBatches;
|
|
16
|
+
this.handleError = StellarApiConnection.handleError;
|
|
17
|
+
this.networkMeta = {
|
|
18
|
+
chain: unsafeApi.getChainId(),
|
|
19
|
+
specName: unsafeApi.getSpecName(),
|
|
20
|
+
genesisHash: unsafeApi.getGenesisHash(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
static async create(endpoint, fetchBlockBatches, eventEmitter) {
|
|
24
|
+
const api = new api_stellar_1.StellarApi(endpoint, eventEmitter);
|
|
25
|
+
await api.init();
|
|
26
|
+
return new StellarApiConnection(api, fetchBlockBatches);
|
|
27
|
+
}
|
|
28
|
+
safeApi(height) {
|
|
29
|
+
return new safe_api_1.default(this.unsafeApi.api, height);
|
|
30
|
+
}
|
|
31
|
+
async apiConnect() {
|
|
32
|
+
await this.unsafeApi.connect();
|
|
33
|
+
}
|
|
34
|
+
async apiDisconnect() {
|
|
35
|
+
await this.unsafeApi.disconnect();
|
|
36
|
+
}
|
|
37
|
+
async fetchBlocks(heights) {
|
|
38
|
+
const blocks = await this.fetchBlocksBatches(this.unsafeApi, heights);
|
|
39
|
+
return blocks;
|
|
40
|
+
}
|
|
41
|
+
static handleError(e) {
|
|
42
|
+
let formatted_error;
|
|
43
|
+
if (e.message.includes(`Timeout`)) {
|
|
44
|
+
formatted_error = new node_core_1.TimeoutError(e);
|
|
45
|
+
}
|
|
46
|
+
else if (e.message.startsWith(`disconnected from `)) {
|
|
47
|
+
formatted_error = new node_core_1.DisconnectionError(e);
|
|
48
|
+
}
|
|
49
|
+
else if (e.message.includes(`Rate Limit Exceeded`) ||
|
|
50
|
+
e.message.includes('Too Many Requests')) {
|
|
51
|
+
formatted_error = new node_core_1.RateLimitError(e);
|
|
52
|
+
}
|
|
53
|
+
else if (e.message.includes(`limit must not exceed`)) {
|
|
54
|
+
formatted_error = new node_core_1.LargeResponseError(e);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
formatted_error = new node_core_1.ApiConnectionError(e.name, e.message, node_core_1.ApiErrorType.Default);
|
|
58
|
+
}
|
|
59
|
+
return formatted_error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.StellarApiConnection = StellarApiConnection;
|
|
63
|
+
//# sourceMappingURL=api.connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.connection.js","sourceRoot":"","sources":["../../src/stellar/api.connection.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;AAGnC,gDAS0B;AAE1B,+CAA2C;AAC3C,0DAA6C;AAO7C,MAAa,oBAAoB;IAU/B,YACS,SAAqB,EACpB,kBAA6B;QAD9B,cAAS,GAAT,SAAS,CAAY;QACpB,uBAAkB,GAAlB,kBAAkB,CAAW;QAsCvC,gBAAW,GAAG,oBAAoB,CAAC,WAAW,CAAC;QApC7C,IAAI,CAAC,WAAW,GAAG;YACjB,KAAK,EAAE,SAAS,CAAC,UAAU,EAAE;YAC7B,QAAQ,EAAE,SAAS,CAAC,WAAW,EAAE;YACjC,WAAW,EAAE,SAAS,CAAC,cAAc,EAAE;SACxC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,QAAgB,EAChB,iBAA4B,EAC5B,YAA2B;QAE3B,MAAM,GAAG,GAAG,IAAI,wBAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAEnD,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,OAAO,IAAI,oBAAoB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,CAAC,MAAc;QACpB,OAAO,IAAI,kBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAiB;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtE,OAAO,MAAM,CAAC;IAChB,CAAC;IAID,MAAM,CAAC,WAAW,CAAC,CAAQ;QACzB,IAAI,eAAmC,CAAC;QACxC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;YACjC,eAAe,GAAG,IAAI,wBAAY,CAAC,CAAC,CAAC,CAAC;SACvC;aAAM,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE;YACrD,eAAe,GAAG,IAAI,8BAAkB,CAAC,CAAC,CAAC,CAAC;SAC7C;aAAM,IACL,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YACzC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EACvC;YACA,eAAe,GAAG,IAAI,0BAAc,CAAC,CAAC,CAAC,CAAC;SACzC;aAAM,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE;YACtD,eAAe,GAAG,IAAI,8BAAkB,CAAC,CAAC,CAAC,CAAC;SAC7C;aAAM;YACL,eAAe,GAAG,IAAI,8BAAkB,CACtC,CAAC,CAAC,IAAI,EACN,CAAC,CAAC,OAAO,EACT,wBAAY,CAAC,OAAO,CACrB,CAAC;SACH;QACD,OAAO,eAAe,CAAC;IACzB,CAAC;CACF;AA1ED,oDA0EC","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n ApiConnectionError,\n ApiErrorType,\n IApiConnectionSpecific,\n NetworkMetadataPayload,\n TimeoutError,\n RateLimitError,\n DisconnectionError,\n LargeResponseError,\n} from '@subql/node-core';\nimport { StellarBlockWrapper } from '@subql/types-stellar';\nimport { StellarApi } from './api.stellar';\nimport SafeStellarProvider from './safe-api';\n\ntype FetchFunc = (\n api: StellarApi,\n batch: number[],\n) => Promise<StellarBlockWrapper[]>;\n\nexport class StellarApiConnection\n implements\n IApiConnectionSpecific<\n StellarApi,\n SafeStellarProvider,\n StellarBlockWrapper\n >\n{\n readonly networkMeta: NetworkMetadataPayload;\n\n constructor(\n public unsafeApi: StellarApi,\n private fetchBlocksBatches: FetchFunc,\n ) {\n this.networkMeta = {\n chain: unsafeApi.getChainId(),\n specName: unsafeApi.getSpecName(),\n genesisHash: unsafeApi.getGenesisHash(),\n };\n }\n\n static async create(\n endpoint: string,\n fetchBlockBatches: FetchFunc,\n eventEmitter: EventEmitter2,\n ): Promise<StellarApiConnection> {\n const api = new StellarApi(endpoint, eventEmitter);\n\n await api.init();\n\n return new StellarApiConnection(api, fetchBlockBatches);\n }\n\n safeApi(height: number): SafeStellarProvider {\n return new SafeStellarProvider(this.unsafeApi.api, height);\n }\n\n async apiConnect(): Promise<void> {\n await this.unsafeApi.connect();\n }\n\n async apiDisconnect(): Promise<void> {\n await this.unsafeApi.disconnect();\n }\n\n async fetchBlocks(heights: number[]): Promise<StellarBlockWrapper[]> {\n const blocks = await this.fetchBlocksBatches(this.unsafeApi, heights);\n return blocks;\n }\n\n handleError = StellarApiConnection.handleError;\n\n static handleError(e: Error): ApiConnectionError {\n let formatted_error: ApiConnectionError;\n if (e.message.includes(`Timeout`)) {\n formatted_error = new TimeoutError(e);\n } else if (e.message.startsWith(`disconnected from `)) {\n formatted_error = new DisconnectionError(e);\n } else if (\n e.message.includes(`Rate Limit Exceeded`) ||\n e.message.includes('Too Many Requests')\n ) {\n formatted_error = new RateLimitError(e);\n } else if (e.message.includes(`limit must not exceed`)) {\n formatted_error = new LargeResponseError(e);\n } else {\n formatted_error = new ApiConnectionError(\n e.name,\n e.message,\n ApiErrorType.Default,\n );\n }\n return formatted_error;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const node_core_1 = require("@subql/node-core");
|
|
9
|
+
const eventemitter2_1 = __importDefault(require("eventemitter2"));
|
|
10
|
+
const api_connection_1 = require("./api.connection");
|
|
11
|
+
const api_stellar_1 = require("./api.stellar");
|
|
12
|
+
const safe_api_1 = __importDefault(require("./safe-api"));
|
|
13
|
+
const HTTP_ENDPOINT = 'https://rpc-futurenet.stellar.org:443';
|
|
14
|
+
describe('StellarApiConnection', () => {
|
|
15
|
+
let apiConnection;
|
|
16
|
+
let unsafeApi;
|
|
17
|
+
const mockBlocks = [
|
|
18
|
+
{
|
|
19
|
+
ledger: 1,
|
|
20
|
+
hash: 'hash1',
|
|
21
|
+
events: [],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
ledger: 2,
|
|
25
|
+
hash: 'hash2',
|
|
26
|
+
events: [],
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
const mockBlockWrappers = mockBlocks.map((_block) => {
|
|
30
|
+
return { block: _block, events: [] };
|
|
31
|
+
});
|
|
32
|
+
const fetchBlockBatches = jest.fn().mockResolvedValue(mockBlockWrappers);
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
unsafeApi = new api_stellar_1.StellarApi(HTTP_ENDPOINT, new eventemitter2_1.default());
|
|
35
|
+
await unsafeApi.init();
|
|
36
|
+
apiConnection = new api_connection_1.StellarApiConnection(unsafeApi, fetchBlockBatches);
|
|
37
|
+
});
|
|
38
|
+
it('calling apiConnect throws error', async () => {
|
|
39
|
+
await expect(apiConnection.apiConnect()).rejects.toThrow();
|
|
40
|
+
});
|
|
41
|
+
it('calling apiDisconnect throws error', async () => {
|
|
42
|
+
await expect(apiConnection.apiDisconnect()).rejects.toThrow();
|
|
43
|
+
});
|
|
44
|
+
it('should fetch blocks', async () => {
|
|
45
|
+
const result = await apiConnection.fetchBlocks([1, 2]);
|
|
46
|
+
expect(result).toEqual(mockBlockWrappers);
|
|
47
|
+
expect(fetchBlockBatches).toHaveBeenCalledWith(apiConnection.unsafeApi, [1, 2]);
|
|
48
|
+
});
|
|
49
|
+
it('should safely provide API at a given height', () => {
|
|
50
|
+
const height = 10;
|
|
51
|
+
const safeApi = apiConnection.safeApi(height);
|
|
52
|
+
expect(safeApi).toBeInstanceOf(safe_api_1.default);
|
|
53
|
+
});
|
|
54
|
+
describe('Error handling', () => {
|
|
55
|
+
it('should handle timeout errors', () => {
|
|
56
|
+
const error = new Error('Timeout');
|
|
57
|
+
const handledError = api_connection_1.StellarApiConnection.handleError(error);
|
|
58
|
+
expect(handledError).toBeInstanceOf(node_core_1.ApiConnectionError);
|
|
59
|
+
expect(handledError.errorType).toEqual(node_core_1.ApiErrorType.Timeout);
|
|
60
|
+
});
|
|
61
|
+
it('should handle disconnection errors', () => {
|
|
62
|
+
const error = new Error('disconnected from ');
|
|
63
|
+
const handledError = api_connection_1.StellarApiConnection.handleError(error);
|
|
64
|
+
expect(handledError).toBeInstanceOf(node_core_1.ApiConnectionError);
|
|
65
|
+
expect(handledError.errorType).toEqual(node_core_1.ApiErrorType.Connection);
|
|
66
|
+
});
|
|
67
|
+
it('should handle rate limit errors', () => {
|
|
68
|
+
const error = new Error('Rate Limit Exceeded');
|
|
69
|
+
const handledError = api_connection_1.StellarApiConnection.handleError(error);
|
|
70
|
+
expect(handledError).toBeInstanceOf(node_core_1.ApiConnectionError);
|
|
71
|
+
expect(handledError.errorType).toEqual(node_core_1.ApiErrorType.RateLimit);
|
|
72
|
+
});
|
|
73
|
+
it('should handle large response errors', () => {
|
|
74
|
+
const error = new Error('limit must not exceed');
|
|
75
|
+
const handledError = api_connection_1.StellarApiConnection.handleError(error);
|
|
76
|
+
expect(handledError).toBeInstanceOf(node_core_1.ApiConnectionError);
|
|
77
|
+
expect(handledError.errorType).toEqual(node_core_1.ApiErrorType.Default);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=api.connection.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.connection.spec.js","sourceRoot":"","sources":["../../src/stellar/api.connection.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { ApiConnectionError, ApiErrorType } from '@subql/node-core';\nimport { StellarBlock, StellarBlockWrapper } from '@subql/types-stellar';\nimport EventEmitter2 from 'eventemitter2';\nimport { StellarApiConnection } from './api.connection';\nimport { StellarApi } from './api.stellar';\nimport SafeStellarProvider from './safe-api';\n\nconst HTTP_ENDPOINT = 'https://rpc-futurenet.stellar.org:443';\n\ndescribe('StellarApiConnection', () => {\n let apiConnection: StellarApiConnection;\n let unsafeApi: StellarApi;\n const mockBlocks: StellarBlock[] = [\n {\n ledger: 1,\n hash: 'hash1',\n events: [],\n },\n {\n ledger: 2,\n hash: 'hash2',\n events: [],\n },\n ];\n\n const mockBlockWrappers = mockBlocks.map((_block) => {\n return { block: _block, events: [] } as StellarBlockWrapper;\n });\n\n const fetchBlockBatches = jest.fn().mockResolvedValue(mockBlockWrappers);\n\n beforeEach(async () => {\n unsafeApi = new StellarApi(HTTP_ENDPOINT, new EventEmitter2());\n await unsafeApi.init();\n apiConnection = new StellarApiConnection(unsafeApi, fetchBlockBatches);\n });\n\n it('calling apiConnect throws error', async () => {\n await expect(apiConnection.apiConnect()).rejects.toThrow();\n });\n\n it('calling apiDisconnect throws error', async () => {\n await expect(apiConnection.apiDisconnect()).rejects.toThrow();\n });\n\n it('should fetch blocks', async () => {\n const result = await apiConnection.fetchBlocks([1, 2]);\n expect(result).toEqual(mockBlockWrappers);\n expect(fetchBlockBatches).toHaveBeenCalledWith(\n apiConnection.unsafeApi,\n [1, 2],\n );\n });\n\n it('should safely provide API at a given height', () => {\n const height = 10;\n const safeApi = apiConnection.safeApi(height);\n expect(safeApi).toBeInstanceOf(SafeStellarProvider);\n });\n\n describe('Error handling', () => {\n it('should handle timeout errors', () => {\n const error = new Error('Timeout');\n const handledError = StellarApiConnection.handleError(error);\n expect(handledError).toBeInstanceOf(ApiConnectionError);\n expect(handledError.errorType).toEqual(ApiErrorType.Timeout);\n });\n\n it('should handle disconnection errors', () => {\n const error = new Error('disconnected from ');\n const handledError = StellarApiConnection.handleError(error);\n expect(handledError).toBeInstanceOf(ApiConnectionError);\n expect(handledError.errorType).toEqual(ApiErrorType.Connection);\n });\n\n it('should handle rate limit errors', () => {\n const error = new Error('Rate Limit Exceeded');\n const handledError = StellarApiConnection.handleError(error);\n expect(handledError).toBeInstanceOf(ApiConnectionError);\n expect(handledError.errorType).toEqual(ApiErrorType.RateLimit);\n });\n\n it('should handle large response errors', () => {\n const error = new Error('limit must not exceed');\n const handledError = StellarApiConnection.handleError(error);\n expect(handledError).toBeInstanceOf(ApiConnectionError);\n expect(handledError.errorType).toEqual(ApiErrorType.Default);\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
2
|
+
import { ApiService, ConnectionPoolService, NetworkMetadataPayload } from '@subql/node-core';
|
|
3
|
+
import { StellarBlockWrapper } from '@subql/types-stellar';
|
|
4
|
+
import { SubqueryProject } from '../configure/SubqueryProject';
|
|
5
|
+
import { StellarApiConnection } from './api.connection';
|
|
6
|
+
import { StellarApi } from './api.stellar';
|
|
7
|
+
import SafeStellarProvider from './safe-api';
|
|
8
|
+
export declare class StellarApiService extends ApiService<StellarApi, SafeStellarProvider, StellarBlockWrapper> {
|
|
9
|
+
private project;
|
|
10
|
+
private eventEmitter;
|
|
11
|
+
constructor(project: SubqueryProject, connectionPoolService: ConnectionPoolService<StellarApiConnection>, eventEmitter: EventEmitter2);
|
|
12
|
+
networkMeta: NetworkMetadataPayload;
|
|
13
|
+
init(): Promise<StellarApiService>;
|
|
14
|
+
private metadataMismatchError;
|
|
15
|
+
get api(): StellarApi;
|
|
16
|
+
safeApi(height: number): SafeStellarProvider;
|
|
17
|
+
private fetchBlockBatches;
|
|
18
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
4
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
5
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
7
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
8
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
9
|
+
};
|
|
10
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
12
|
+
};
|
|
13
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
14
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
15
|
+
};
|
|
16
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
17
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
18
|
+
var m = o[Symbol.asyncIterator], i;
|
|
19
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
20
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
21
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.StellarApiService = void 0;
|
|
25
|
+
const common_1 = require("@nestjs/common");
|
|
26
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
27
|
+
const node_core_1 = require("@subql/node-core");
|
|
28
|
+
const SubqueryProject_1 = require("../configure/SubqueryProject");
|
|
29
|
+
const api_connection_1 = require("./api.connection");
|
|
30
|
+
const logger = (0, node_core_1.getLogger)('api');
|
|
31
|
+
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
32
|
+
let StellarApiService = class StellarApiService extends node_core_1.ApiService {
|
|
33
|
+
constructor(project, connectionPoolService, eventEmitter) {
|
|
34
|
+
super(connectionPoolService);
|
|
35
|
+
this.project = project;
|
|
36
|
+
this.eventEmitter = eventEmitter;
|
|
37
|
+
}
|
|
38
|
+
async init() {
|
|
39
|
+
var _a, e_1, _b, _c;
|
|
40
|
+
try {
|
|
41
|
+
let network;
|
|
42
|
+
try {
|
|
43
|
+
network = this.project.network;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
logger.error(Object.keys(e));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const endpoints = Array.isArray(network.endpoint)
|
|
50
|
+
? network.endpoint
|
|
51
|
+
: [network.endpoint];
|
|
52
|
+
const endpointToApiIndex = {};
|
|
53
|
+
try {
|
|
54
|
+
for (var _d = true, _e = __asyncValues(endpoints.entries()), _f; _f = await _e.next(), _a = _f.done, !_a;) {
|
|
55
|
+
_c = _f.value;
|
|
56
|
+
_d = false;
|
|
57
|
+
try {
|
|
58
|
+
const [i, endpoint] = _c;
|
|
59
|
+
const connection = await api_connection_1.StellarApiConnection.create(endpoint, this.fetchBlockBatches, this.eventEmitter);
|
|
60
|
+
const api = connection.unsafeApi;
|
|
61
|
+
this.eventEmitter.emit(node_core_1.IndexerEvent.ApiConnected, {
|
|
62
|
+
value: 1,
|
|
63
|
+
apiIndex: i,
|
|
64
|
+
endpoint: endpoint,
|
|
65
|
+
});
|
|
66
|
+
if (!this.networkMeta) {
|
|
67
|
+
this.networkMeta = connection.networkMeta;
|
|
68
|
+
}
|
|
69
|
+
if (network.chainId !== api.getChainId().toString()) {
|
|
70
|
+
throw this.metadataMismatchError('ChainId', network.chainId, api.getChainId().toString());
|
|
71
|
+
}
|
|
72
|
+
endpointToApiIndex[endpoint] = connection;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
_d = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
80
|
+
finally {
|
|
81
|
+
try {
|
|
82
|
+
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
|
|
83
|
+
}
|
|
84
|
+
finally { if (e_1) throw e_1.error; }
|
|
85
|
+
}
|
|
86
|
+
this.connectionPoolService.addBatchToConnections(endpointToApiIndex);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
logger.error(e, 'Failed to init api service');
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
metadataMismatchError(metadata, expected, actual) {
|
|
95
|
+
return Error(`Value of ${metadata} does not match across all endpoints. Please check that your endpoints are for the same network.\n
|
|
96
|
+
Expected: ${expected}
|
|
97
|
+
Actual: ${actual}`);
|
|
98
|
+
}
|
|
99
|
+
get api() {
|
|
100
|
+
return this.unsafeApi;
|
|
101
|
+
}
|
|
102
|
+
safeApi(height) {
|
|
103
|
+
const maxRetries = 5;
|
|
104
|
+
const handler = {
|
|
105
|
+
get: (target, prop, receiver) => {
|
|
106
|
+
const originalMethod = target[prop];
|
|
107
|
+
if (typeof originalMethod === 'function') {
|
|
108
|
+
return async (...args) => {
|
|
109
|
+
let retries = 0;
|
|
110
|
+
let currentApi = target;
|
|
111
|
+
let throwingError;
|
|
112
|
+
while (retries < maxRetries) {
|
|
113
|
+
try {
|
|
114
|
+
return await originalMethod.apply(currentApi, args);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logger.warn(`Request failed with api at height ${height} (retry ${retries}): ${error.message}`);
|
|
118
|
+
throwingError = error;
|
|
119
|
+
currentApi = this.unsafeApi.getSafeApi(height);
|
|
120
|
+
retries++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
logger.error(`Maximum retries (${maxRetries}) exceeded for api at height ${height}`);
|
|
124
|
+
throw throwingError;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return Reflect.get(target, prop, receiver);
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
return new Proxy(this.unsafeApi.getSafeApi(height), handler);
|
|
131
|
+
}
|
|
132
|
+
async fetchBlockBatches(api, batch) {
|
|
133
|
+
return api.fetchBlocks(batch);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
StellarApiService = __decorate([
|
|
137
|
+
(0, common_1.Injectable)(),
|
|
138
|
+
__param(0, (0, common_1.Inject)('ISubqueryProject')),
|
|
139
|
+
__metadata("design:paramtypes", [SubqueryProject_1.SubqueryProject,
|
|
140
|
+
node_core_1.ConnectionPoolService,
|
|
141
|
+
event_emitter_1.EventEmitter2])
|
|
142
|
+
], StellarApiService);
|
|
143
|
+
exports.StellarApiService = StellarApiService;
|
|
144
|
+
//# sourceMappingURL=api.service.stellar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.service.stellar.js","sourceRoot":"","sources":["../../src/stellar/api.service.stellar.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { ProjectNetworkV1_0_0 } from '@subql/common-stellar';\nimport {\n ApiService,\n ConnectionPoolService,\n NetworkMetadataPayload,\n getLogger,\n IndexerEvent,\n} from '@subql/node-core';\nimport { StellarBlockWrapper } from '@subql/types-stellar';\nimport { SubqueryProject } from '../configure/SubqueryProject';\nimport { StellarApiConnection } from './api.connection';\nimport { StellarApi } from './api.stellar';\nimport SafeStellarProvider from './safe-api';\n\nconst logger = getLogger('api');\n\nconst MAX_RECONNECT_ATTEMPTS = 5;\n\n@Injectable()\nexport class StellarApiService extends ApiService<\n StellarApi,\n SafeStellarProvider,\n StellarBlockWrapper\n> {\n constructor(\n @Inject('ISubqueryProject') private project: SubqueryProject,\n connectionPoolService: ConnectionPoolService<StellarApiConnection>,\n private eventEmitter: EventEmitter2,\n ) {\n super(connectionPoolService);\n }\n\n networkMeta: NetworkMetadataPayload;\n\n async init(): Promise<StellarApiService> {\n try {\n let network: ProjectNetworkV1_0_0;\n try {\n network = this.project.network;\n } catch (e) {\n logger.error(Object.keys(e));\n process.exit(1);\n }\n\n const endpoints = Array.isArray(network.endpoint)\n ? network.endpoint\n : [network.endpoint];\n\n const endpointToApiIndex: Record<string, StellarApiConnection> = {};\n\n for await (const [i, endpoint] of endpoints.entries()) {\n const connection = await StellarApiConnection.create(\n endpoint,\n this.fetchBlockBatches,\n this.eventEmitter,\n );\n\n const api = connection.unsafeApi;\n\n this.eventEmitter.emit(IndexerEvent.ApiConnected, {\n value: 1,\n apiIndex: i,\n endpoint: endpoint,\n });\n\n if (!this.networkMeta) {\n this.networkMeta = connection.networkMeta;\n }\n\n if (network.chainId !== api.getChainId().toString()) {\n throw this.metadataMismatchError(\n 'ChainId',\n network.chainId,\n api.getChainId().toString(),\n );\n }\n\n endpointToApiIndex[endpoint] = connection;\n }\n\n this.connectionPoolService.addBatchToConnections(endpointToApiIndex);\n\n return this;\n } catch (e) {\n logger.error(e, 'Failed to init api service');\n throw e;\n }\n }\n\n private metadataMismatchError(\n metadata: string,\n expected: string,\n actual: string,\n ): Error {\n return Error(\n `Value of ${metadata} does not match across all endpoints. Please check that your endpoints are for the same network.\\n\n Expected: ${expected}\n Actual: ${actual}`,\n );\n }\n\n get api(): StellarApi {\n return this.unsafeApi;\n }\n\n safeApi(height: number): SafeStellarProvider {\n const maxRetries = 5;\n\n const handler: ProxyHandler<SafeStellarProvider> = {\n get: (target, prop, receiver) => {\n const originalMethod = target[prop as keyof SafeStellarProvider];\n if (typeof originalMethod === 'function') {\n return async (...args: any[]) => {\n let retries = 0;\n let currentApi = target;\n let throwingError: Error;\n\n while (retries < maxRetries) {\n try {\n return await originalMethod.apply(currentApi, args);\n } catch (error) {\n logger.warn(\n `Request failed with api at height ${height} (retry ${retries}): ${error.message}`,\n );\n throwingError = error;\n currentApi = this.unsafeApi.getSafeApi(height);\n retries++;\n }\n }\n\n logger.error(\n `Maximum retries (${maxRetries}) exceeded for api at height ${height}`,\n );\n throw throwingError;\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n };\n\n return new Proxy(this.unsafeApi.getSafeApi(height), handler);\n }\n\n private async fetchBlockBatches(\n api: StellarApi,\n batch: number[],\n ): Promise<StellarBlockWrapper[]> {\n return api.fetchBlocks(batch);\n }\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { INestApplication } from '@nestjs/common';
|
|
2
|
+
import { SubqueryProject } from '../configure/SubqueryProject';
|
|
3
|
+
import { StellarApiService } from './api.service.stellar';
|
|
4
|
+
export declare function testSubqueryProject(endpoint: string): SubqueryProject;
|
|
5
|
+
export declare const prepareApiService: (endpoint?: string, project?: SubqueryProject) => Promise<[StellarApiService, INestApplication]>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.prepareApiService = exports.testSubqueryProject = void 0;
|
|
6
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
7
|
+
const testing_1 = require("@nestjs/testing");
|
|
8
|
+
const node_core_1 = require("@subql/node-core");
|
|
9
|
+
const dist_1 = require("@subql/node-core/dist");
|
|
10
|
+
const graphql_1 = require("graphql");
|
|
11
|
+
const lodash_1 = require("lodash");
|
|
12
|
+
const api_service_stellar_1 = require("./api.service.stellar");
|
|
13
|
+
const HTTP_ENDPOINT = 'https://rpc-futurenet.stellar.org:443';
|
|
14
|
+
function testSubqueryProject(endpoint) {
|
|
15
|
+
return {
|
|
16
|
+
network: {
|
|
17
|
+
endpoint,
|
|
18
|
+
chainId: 'Test SDF Future Network ; October 2022',
|
|
19
|
+
},
|
|
20
|
+
dataSources: [],
|
|
21
|
+
id: 'test',
|
|
22
|
+
root: './',
|
|
23
|
+
schema: new graphql_1.GraphQLSchema({}),
|
|
24
|
+
templates: [],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.testSubqueryProject = testSubqueryProject;
|
|
28
|
+
const prepareApiService = async (endpoint = HTTP_ENDPOINT, project) => {
|
|
29
|
+
const module = await testing_1.Test.createTestingModule({
|
|
30
|
+
providers: [
|
|
31
|
+
node_core_1.ConnectionPoolService,
|
|
32
|
+
dist_1.ConnectionPoolStateManager,
|
|
33
|
+
{
|
|
34
|
+
provide: node_core_1.NodeConfig,
|
|
35
|
+
useFactory: () => ({}),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
provide: 'ISubqueryProject',
|
|
39
|
+
useFactory: () => project !== null && project !== void 0 ? project : testSubqueryProject(endpoint),
|
|
40
|
+
},
|
|
41
|
+
api_service_stellar_1.StellarApiService,
|
|
42
|
+
],
|
|
43
|
+
imports: [event_emitter_1.EventEmitterModule.forRoot()],
|
|
44
|
+
}).compile();
|
|
45
|
+
const app = module.createNestApplication();
|
|
46
|
+
await app.init();
|
|
47
|
+
const apiService = app.get(api_service_stellar_1.StellarApiService);
|
|
48
|
+
await apiService.init();
|
|
49
|
+
return [apiService, app];
|
|
50
|
+
};
|
|
51
|
+
exports.prepareApiService = prepareApiService;
|
|
52
|
+
jest.setTimeout(90000);
|
|
53
|
+
describe('StellarApiService', () => {
|
|
54
|
+
let apiService;
|
|
55
|
+
let app;
|
|
56
|
+
beforeEach(async () => {
|
|
57
|
+
[apiService, app] = await (0, exports.prepareApiService)();
|
|
58
|
+
});
|
|
59
|
+
it('can instantiate api', async () => {
|
|
60
|
+
console.log(apiService.api.getChainId());
|
|
61
|
+
await (0, node_core_1.delay)(0.5);
|
|
62
|
+
});
|
|
63
|
+
it('can fetch blocks', async () => {
|
|
64
|
+
const finalizedHeight = await apiService.api.getFinalizedBlockHeight();
|
|
65
|
+
const blocks = await apiService.api.fetchBlocks((0, lodash_1.range)(finalizedHeight - 1000, finalizedHeight));
|
|
66
|
+
expect(blocks).toBeDefined();
|
|
67
|
+
await (0, node_core_1.delay)(0.5);
|
|
68
|
+
});
|
|
69
|
+
it('can get the finalized height', async () => {
|
|
70
|
+
const height = await apiService.api.getFinalizedBlockHeight();
|
|
71
|
+
console.log('Finalized height', height);
|
|
72
|
+
expect(height).not.toBeNaN();
|
|
73
|
+
});
|
|
74
|
+
it('throws error when chainId does not match', async () => {
|
|
75
|
+
const faultyProject = Object.assign(Object.assign({}, testSubqueryProject(HTTP_ENDPOINT)), { network: Object.assign(Object.assign({}, testSubqueryProject(HTTP_ENDPOINT).network), { chainId: 'Incorrect ChainId' }) });
|
|
76
|
+
await expect((0, exports.prepareApiService)(HTTP_ENDPOINT, faultyProject)).rejects.toThrow();
|
|
77
|
+
});
|
|
78
|
+
it('fails after maximum retries', async () => {
|
|
79
|
+
const safeApi = apiService.safeApi(50000);
|
|
80
|
+
// Mock the fetchBlocks method to always throw an error
|
|
81
|
+
safeApi.fetchBlocks = jest
|
|
82
|
+
.fn()
|
|
83
|
+
.mockRejectedValue(new Error('Network error'));
|
|
84
|
+
await expect(safeApi.fetchBlocks((0, lodash_1.range)(50000, 50100))).rejects.toThrow();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=api.service.stellar.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.service.stellar.spec.js","sourceRoot":"","sources":["../../src/stellar/api.service.stellar.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { INestApplication } from '@nestjs/common';\nimport { EventEmitterModule } from '@nestjs/event-emitter';\nimport { Test } from '@nestjs/testing';\nimport { ConnectionPoolService, delay, NodeConfig } from '@subql/node-core';\nimport { ConnectionPoolStateManager } from '@subql/node-core/dist';\nimport { GraphQLSchema } from 'graphql';\nimport { range } from 'lodash';\nimport { SubqueryProject } from '../configure/SubqueryProject';\nimport { StellarApiService } from './api.service.stellar';\n\nconst HTTP_ENDPOINT = 'https://rpc-futurenet.stellar.org:443';\n\nexport function testSubqueryProject(endpoint: string): SubqueryProject {\n return {\n network: {\n endpoint,\n chainId: 'Test SDF Future Network ; October 2022',\n },\n dataSources: [],\n id: 'test',\n root: './',\n schema: new GraphQLSchema({}),\n templates: [],\n };\n}\n\nexport const prepareApiService = async (\n endpoint: string = HTTP_ENDPOINT,\n project?: SubqueryProject,\n): Promise<[StellarApiService, INestApplication]> => {\n const module = await Test.createTestingModule({\n providers: [\n ConnectionPoolService,\n ConnectionPoolStateManager,\n {\n provide: NodeConfig,\n useFactory: () => ({}),\n },\n {\n provide: 'ISubqueryProject',\n useFactory: () => project ?? testSubqueryProject(endpoint),\n },\n StellarApiService,\n ],\n imports: [EventEmitterModule.forRoot()],\n }).compile();\n\n const app = module.createNestApplication();\n await app.init();\n const apiService = app.get(StellarApiService);\n await apiService.init();\n return [apiService, app];\n};\n\njest.setTimeout(90000);\ndescribe('StellarApiService', () => {\n let apiService: StellarApiService;\n let app: INestApplication;\n\n beforeEach(async () => {\n [apiService, app] = await prepareApiService();\n });\n\n it('can instantiate api', async () => {\n console.log(apiService.api.getChainId());\n await delay(0.5);\n });\n\n it('can fetch blocks', async () => {\n const finalizedHeight = await apiService.api.getFinalizedBlockHeight();\n const blocks = await apiService.api.fetchBlocks(\n range(finalizedHeight - 1000, finalizedHeight),\n );\n expect(blocks).toBeDefined();\n await delay(0.5);\n });\n\n it('can get the finalized height', async () => {\n const height = await apiService.api.getFinalizedBlockHeight();\n console.log('Finalized height', height);\n expect(height).not.toBeNaN();\n });\n\n it('throws error when chainId does not match', async () => {\n const faultyProject = {\n ...testSubqueryProject(HTTP_ENDPOINT),\n network: {\n ...testSubqueryProject(HTTP_ENDPOINT).network,\n chainId: 'Incorrect ChainId',\n },\n };\n\n await expect(\n prepareApiService(HTTP_ENDPOINT, faultyProject),\n ).rejects.toThrow();\n });\n\n it('fails after maximum retries', async () => {\n const safeApi = apiService.safeApi(50000);\n\n // Mock the fetchBlocks method to always throw an error\n (safeApi as any).fetchBlocks = jest\n .fn()\n .mockRejectedValue(new Error('Network error'));\n\n await expect(\n (safeApi as any).fetchBlocks(range(50000, 50100)),\n ).rejects.toThrow();\n });\n});\n"]}
|