Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.

Commit 9123d3b

Browse files
will pankiewiczwill pankiewicz
authored andcommitted
bump version to v3.1.10
1 parent 807dbd3 commit 9123d3b

File tree

9 files changed

+145
-141
lines changed

9 files changed

+145
-141
lines changed

apps/1kv-backend/templates/kusama-otv-backend.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spec:
1717
source:
1818
repoURL: https://w3f.github.io/helm-charts/
1919
chart: otv-backend
20-
targetRevision: v3.1.9
20+
targetRevision: v3.1.10
2121
plugin:
2222
env:
2323
- name: HELM_VALUES

apps/1kv-backend/templates/polkadot-otv-backend.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spec:
1717
source:
1818
repoURL: https://w3f.github.io/helm-charts/
1919
chart: otv-backend
20-
targetRevision: v3.1.9
20+
targetRevision: v3.1.10
2121
plugin:
2222
env:
2323
- name: HELM_VALUES

charts/otv-backend/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
description: 1K Validators Backend
22
name: otv-backend
3-
version: v3.1.9
4-
appVersion: v3.1.9
3+
version: v3.1.10
4+
appVersion: v3.1.10
55
apiVersion: v2
Lines changed: 136 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,177 @@
11
import { ApiPromise, WsProvider } from "@polkadot/api";
22
import EventEmitter from "eventemitter3";
33

4-
import logger from "../logger";
5-
import { POLKADOT_API_TIMEOUT } from "../constants";
6-
import { sleep } from "../utils";
4+
import logger from "./logger";
5+
import { sleep } from "./util";
6+
import { POLKADOT_API_TIMEOUT } from "./constants";
77

88
export const apiLabel = { label: "ApiHandler" };
99

10+
/**
11+
* A higher level handler for the Polkadot-Js API that can handle reconnecting
12+
* to a different provider if one proves troublesome.
13+
*/
1014
class ApiHandler extends EventEmitter {
11-
private _wsProvider?: WsProvider;
12-
private _api: ApiPromise | null = null;
13-
private readonly _endpoints: string[];
14-
private _currentEndpointIndex = 0;
15-
private _maxRetries = 25;
16-
private _connectionAttemptInProgress = false;
17-
private healthCheckInProgress = false;
18-
public upSince: number = Date.now();
19-
20-
constructor(endpoints: string[]) {
15+
private _api: ApiPromise;
16+
private _endpoints: string[];
17+
private _reconnectLock: boolean;
18+
private _reconnectTries = 0;
19+
static isConnected: any;
20+
static _reconnect: any;
21+
22+
constructor(api: ApiPromise, endpoints?: string[]) {
2123
super();
22-
this._endpoints = endpoints;
23-
this.initiateConnection().catch(this.handleError);
24+
this._api = api;
25+
// this._endpoints = endpoints.sort(() => Math.random() - 0.5);
26+
this._registerEventHandlers(api);
2427
}
2528

26-
public async initiateConnection(retryCount = 0): Promise<void> {
27-
logger.info(`Initiating connection...`, apiLabel);
28-
if (this._connectionAttemptInProgress) {
29-
logger.info(
30-
"Connection attempt already in progress, skipping new attempt.",
31-
apiLabel,
32-
);
33-
return;
34-
}
35-
36-
logger.info(
37-
`Setting connection attempt in progress. Endpoints: ${this._endpoints}`,
38-
apiLabel,
39-
);
40-
this._connectionAttemptInProgress = true;
41-
const endpoint = this.currentEndpoint();
42-
logger.info(`Attempting to connect to endpoint: ${endpoint}`, apiLabel);
43-
44-
this._wsProvider = new WsProvider(endpoint, POLKADOT_API_TIMEOUT);
45-
46-
this._wsProvider.on("error", async (error) => {
47-
logger.error(
48-
`WS provider error at ${endpoint}: ${error.message}`,
49-
apiLabel,
50-
);
51-
await this.retryConnection();
52-
});
29+
static async createApi(endpoints, reconnectTries = 0) {
30+
const timeout = 12;
31+
let api, wsProvider;
32+
const healthCheck = async (api) => {
33+
logger.info(`Performing health check for WS Provider for rpc.`, apiLabel);
34+
35+
await sleep(timeout * 1000);
36+
if (api && api?.isConnected) {
37+
logger.info(`All good. Connected`, apiLabel);
38+
return true;
39+
} else {
40+
logger.info(
41+
`rpc endpoint still disconnected after ${timeout} seconds. Disconnecting `,
42+
apiLabel,
43+
);
44+
await api.disconnect();
5345

54-
this._wsProvider.on("disconnected", async () => {
55-
logger.info(`WS provider disconnected from ${endpoint}`, apiLabel);
56-
await this.retryConnection();
57-
});
46+
throw new Error(
47+
`rpc endpoint still disconnected after ${timeout} seconds.`,
48+
);
49+
}
50+
};
5851

5952
try {
60-
const api = await ApiPromise.create({ provider: this._wsProvider });
61-
await api.isReadyOrError;
62-
this._api = api;
63-
this._registerEventHandlers(api);
64-
logger.info(`Successfully connected to ${endpoint}`, apiLabel);
65-
this.emit("connected", { endpoint: endpoint });
66-
this.upSince = Date.now();
67-
} catch (error) {
68-
logger.error(
69-
`Connection failed to endpoint ${endpoint}: ${error}`,
70-
apiLabel,
53+
wsProvider = new WsProvider(
54+
endpoints,
55+
undefined,
56+
undefined,
57+
POLKADOT_API_TIMEOUT,
7158
);
72-
await this.retryConnection();
73-
} finally {
74-
this._connectionAttemptInProgress = false;
75-
}
76-
}
7759

78-
private async retryConnection(): Promise<void> {
79-
if (!this.isConnected() && this._maxRetries > 0) {
80-
this._maxRetries--;
81-
await this.cleanupConnection();
82-
this.moveToNextEndpoint();
83-
await this.initiateConnection();
84-
}
85-
}
86-
87-
private moveToNextEndpoint(): void {
88-
this._currentEndpointIndex =
89-
(this._currentEndpointIndex + 1) % this._endpoints.length;
90-
}
60+
api = new ApiPromise({
61+
provider: new WsProvider(
62+
endpoints,
63+
undefined,
64+
undefined,
65+
POLKADOT_API_TIMEOUT,
66+
),
67+
// throwOnConnect: true,
68+
});
9169

92-
private async cleanupConnection(): Promise<void> {
93-
try {
94-
if (this._wsProvider) {
95-
this._wsProvider?.disconnect();
96-
this._wsProvider = undefined;
70+
api
71+
.on("connected", () => {
72+
logger.info(`Connected to chain ${endpoints[0]}`, apiLabel);
73+
})
74+
.on("disconnected", async () => {
75+
logger.warn(`Disconnected from chain`, apiLabel);
76+
try {
77+
await healthCheck(wsProvider);
78+
await Promise.resolve(api);
79+
} catch (error: any) {
80+
await Promise.reject(error);
81+
}
82+
})
83+
.on("ready", () => {
84+
logger.info(`API connection ready ${endpoints[0]}`, apiLabel);
85+
})
86+
.on("error", async (error) => {
87+
logger.warn("The API has an error", apiLabel);
88+
logger.error(error, apiLabel);
89+
logger.warn(`attempting to reconnect to ${endpoints[0]}`, apiLabel);
90+
try {
91+
await healthCheck(wsProvider);
92+
await Promise.resolve(api);
93+
} catch (error: any) {
94+
await Promise.reject(error);
95+
}
96+
});
97+
98+
if (api) {
99+
await api.isReadyOrError.catch(logger.error);
100+
101+
return api;
102+
}
103+
} catch (e) {
104+
logger.error(`there was an error: `, apiLabel);
105+
logger.error(e, apiLabel);
106+
if (reconnectTries < 10) {
107+
return await this.createApi(
108+
endpoints.sort(() => Math.random() - 0.5),
109+
reconnectTries + 1,
110+
);
111+
} else {
112+
return api;
97113
}
98-
await this._api?.disconnect();
99-
this._api = null;
100-
this._connectionAttemptInProgress = false;
101-
logger.info(`Connection cleaned up`, apiLabel);
102-
await sleep(3000);
103-
} catch (error) {
104-
logger.error(`Error cleaning up connection: ${error}`, apiLabel);
105114
}
106115
}
107116

108-
async healthCheck(): Promise<boolean> {
109-
if (this.healthCheckInProgress) return false;
110-
this.healthCheckInProgress = true;
111-
117+
static async create(endpoints: string[]): Promise<ApiHandler> {
112118
try {
113-
logger.info(
114-
`Performing health check... endpoint: ${this.currentEndpoint()}`,
115-
apiLabel,
119+
const api = await this.createApi(
120+
endpoints.sort(() => Math.random() - 0.5),
116121
);
117-
const wsConnected = this._wsProvider?.isConnected || false;
118-
const apiConnected = this._api?.isConnected || false;
119-
const chain = await this._api?.rpc.system.chain();
120-
121-
this.healthCheckInProgress = false;
122-
const healthy = wsConnected && apiConnected && !!chain;
123-
logger.info(`Health: ${healthy}`, apiLabel);
124-
if (!healthy) {
125-
logger.info(
126-
"Cleaning up connection and trying a different endpoint",
127-
apiLabel,
128-
);
129-
this.cleanupConnection();
130-
this.moveToNextEndpoint();
131-
this.initiateConnection();
132-
}
133-
return healthy;
134-
} catch (error) {
135-
logger.error(`Health check failed: ${error}`, apiLabel);
136-
this.healthCheckInProgress = false;
137-
this.cleanupConnection();
138-
this.moveToNextEndpoint();
139-
this.initiateConnection();
140-
return false;
122+
123+
return new ApiHandler(api, endpoints);
124+
} catch (e) {
125+
logger.info(`there was an error: `, apiLabel);
126+
logger.error(e, apiLabel);
141127
}
142128
}
143129

144-
currentEndpoint(): string {
145-
return this._endpoints[this._currentEndpointIndex];
130+
isConnected(): boolean {
131+
return this._api.isConnected;
146132
}
147133

148-
getApi(): ApiPromise | null {
134+
getApi(): ApiPromise {
149135
return this._api;
150136
}
151137

152-
isConnected(): boolean {
153-
return !!this._wsProvider?.isConnected && !!this._api?.isConnected;
154-
}
155-
156138
_registerEventHandlers(api: ApiPromise): void {
157139
api.query.system.events((events) => {
140+
// Loop through the Vec<EventRecord>
158141
events.forEach((record) => {
142+
// Extract the phase, event and the event types
159143
const { event } = record;
160-
if (event.section === "session" && event.method === "NewSession") {
161-
const sessionIndex = Number(event?.data[0]?.toString()) || 0;
162-
this.emit("newSession", sessionIndex);
144+
145+
if (event.section == "session" && event.method == "NewSession") {
146+
const [session_index] = event.data;
147+
148+
this.emit("newSession", {
149+
sessionIndex: session_index.toString(),
150+
});
151+
}
152+
153+
if (
154+
event.section == "staking" &&
155+
(event.method == "Reward" || event.method == "Rewarded")
156+
) {
157+
const [stash, amount] = event.data;
158+
159+
this.emit("reward", {
160+
stash: stash.toString(),
161+
amount: amount.toString(),
162+
});
163+
}
164+
165+
if (event.section === "imOnline" && event.method === "SomeOffline") {
166+
const offlineVals = event.data.toJSON()[0].map((val) => val[0]);
167+
168+
this.emit("someOffline", {
169+
offlineVals: offlineVals,
170+
});
163171
}
164172
});
165173
});
166174
}
167-
168-
private handleError(error): void {
169-
logger.error(`Unhandled exception in ApiHandler: ${error}`, apiLabel);
170-
}
171175
}
172176

173177
export default ApiHandler;

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@1kv/core",
3-
"version": "3.1.9",
3+
"version": "3.1.10",
44
"description": "Services for running the Thousand Validator Program.",
55
"main": "index.js",
66
"scripts": {

packages/gateway/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@1kv/gateway",
3-
"version": "3.1.9",
3+
"version": "3.1.10",
44
"description": "Services for running the Thousand Validator Program.",
55
"main": "build/index.js",
66
"types": "build/index.d.ts",

packages/scorekeeper-status-ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@1kv/scorekeeper-status-ui",
33
"private": true,
4-
"version": "3.1.9",
4+
"version": "3.1.10",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

packages/telemetry/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@1kv/telemetry",
3-
"version": "3.1.9",
3+
"version": "3.1.10",
44
"description": "Services for running the Thousand Validator Program.",
55
"main": "build/index.js",
66
"types": "build/index.d.ts",

packages/worker/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@1kv/worker",
3-
"version": "3.1.9",
3+
"version": "3.1.10",
44
"description": "Services for running the Thousand Validator Program.",
55
"main": "build/index.js",
66
"types": "build/index.d.ts",

0 commit comments

Comments
 (0)