@corpus-core/colibri-stateless 0.2.4 → 0.2.6
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/README.md +24 -0
- package/c4w.js +1 -1
- package/connectionState.d.ts +1 -2
- package/connectionState.js +30 -9
- package/index.d.ts +3 -1
- package/index.js +49 -41
- package/package.json +1 -1
- package/strategy.d.ts +10 -0
- package/strategy.js +90 -0
- package/subscriptionManager.js +3 -2
- package/types.d.ts +24 -4
package/connectionState.d.ts
CHANGED
|
@@ -11,8 +11,7 @@ export declare class ConnectionState {
|
|
|
11
11
|
private config;
|
|
12
12
|
private fetchRpcChainIdCallback;
|
|
13
13
|
private eventEmitter;
|
|
14
|
-
|
|
15
|
-
constructor(config: ConnectionStateConfig, fetchRpcChainIdCallback: () => Promise<any>, eventEmitter: EventEmitter, formatChainIdFunc: (value: any, debug?: boolean) => string | null);
|
|
14
|
+
constructor(config: ConnectionStateConfig, fetchRpcChainIdCallback: () => Promise<any>, eventEmitter: EventEmitter);
|
|
16
15
|
get isConnected(): boolean;
|
|
17
16
|
get currentChainId(): string | null;
|
|
18
17
|
get initialConnectionAttempted(): boolean;
|
package/connectionState.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
import { ProviderRpcError } from './types.js';
|
|
2
|
+
// Helper function for chain ID formatting - intentionally kept separate for now
|
|
3
|
+
// If this function is *only* used by ConnectionState, it could be moved inside or made local.
|
|
4
|
+
// However, C4Client.rpc also uses it for its LOCAL eth_chainId case, so it might need broader access.
|
|
5
|
+
// For this refactoring, we assume it's passed in or globally accessible if needed elsewhere.
|
|
6
|
+
// Helper function for chain ID formatting (can be used by ConnectionManager and C4Client)
|
|
7
|
+
function formatChainId(value, debug) {
|
|
8
|
+
if (typeof value === 'string') {
|
|
9
|
+
if (value.startsWith('0x')) {
|
|
10
|
+
return value.toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
const parsed = parseInt(value, 10);
|
|
13
|
+
if (!isNaN(parsed)) {
|
|
14
|
+
return '0x' + parsed.toString(16);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
else if (typeof value === 'number') {
|
|
18
|
+
return '0x' + value.toString(16);
|
|
19
|
+
}
|
|
20
|
+
if (debug) {
|
|
21
|
+
console.warn('Could not format chainId:', value);
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
2
25
|
export class ConnectionState {
|
|
3
26
|
_isConnected = false;
|
|
4
27
|
_currentChainId = null;
|
|
@@ -6,13 +29,11 @@ export class ConnectionState {
|
|
|
6
29
|
config;
|
|
7
30
|
fetchRpcChainIdCallback;
|
|
8
31
|
eventEmitter;
|
|
9
|
-
|
|
10
|
-
constructor(config, fetchRpcChainIdCallback, eventEmitter, formatChainIdFunc) {
|
|
32
|
+
constructor(config, fetchRpcChainIdCallback, eventEmitter) {
|
|
11
33
|
this.config = config;
|
|
12
34
|
this.fetchRpcChainIdCallback = fetchRpcChainIdCallback;
|
|
13
35
|
this.eventEmitter = eventEmitter;
|
|
14
|
-
this.
|
|
15
|
-
this._currentChainId = this.formatChainIdFunc(this.config.chainId, this.config.debug);
|
|
36
|
+
this._currentChainId = formatChainId(this.config.chainId, this.config.debug);
|
|
16
37
|
}
|
|
17
38
|
get isConnected() {
|
|
18
39
|
return this._isConnected;
|
|
@@ -32,7 +53,7 @@ export class ConnectionState {
|
|
|
32
53
|
}
|
|
33
54
|
try {
|
|
34
55
|
const result = await this.fetchRpcChainIdCallback();
|
|
35
|
-
const formattedChainId =
|
|
56
|
+
const formattedChainId = formatChainId(result, this.config.debug);
|
|
36
57
|
if (formattedChainId) {
|
|
37
58
|
this._isConnected = true;
|
|
38
59
|
this._currentChainId = formattedChainId;
|
|
@@ -64,12 +85,12 @@ export class ConnectionState {
|
|
|
64
85
|
const updateAndEmitConnect = async () => {
|
|
65
86
|
let determinedChainId = null;
|
|
66
87
|
if (requestMethod === 'eth_chainId') {
|
|
67
|
-
determinedChainId =
|
|
88
|
+
determinedChainId = formatChainId(requestResult, this.config.debug);
|
|
68
89
|
}
|
|
69
90
|
else {
|
|
70
91
|
try {
|
|
71
92
|
const chainIdResult = await this.fetchRpcChainIdCallback();
|
|
72
|
-
determinedChainId =
|
|
93
|
+
determinedChainId = formatChainId(chainIdResult, this.config.debug);
|
|
73
94
|
}
|
|
74
95
|
catch (e) {
|
|
75
96
|
if (this.config.debug)
|
|
@@ -77,7 +98,7 @@ export class ConnectionState {
|
|
|
77
98
|
determinedChainId = this._currentChainId;
|
|
78
99
|
}
|
|
79
100
|
}
|
|
80
|
-
this._currentChainId = determinedChainId ||
|
|
101
|
+
this._currentChainId = determinedChainId || formatChainId(this.config.chainId, this.config.debug);
|
|
81
102
|
this.eventEmitter.emit('connect', { chainId: this._currentChainId });
|
|
82
103
|
};
|
|
83
104
|
updateAndEmitConnect().catch(err => {
|
|
@@ -86,7 +107,7 @@ export class ConnectionState {
|
|
|
86
107
|
});
|
|
87
108
|
}
|
|
88
109
|
else if (requestMethod === 'eth_chainId') {
|
|
89
|
-
const newChainId =
|
|
110
|
+
const newChainId = formatChainId(requestResult, this.config.debug);
|
|
90
111
|
if (newChainId && this._currentChainId !== newChainId) {
|
|
91
112
|
const oldChainId = this._currentChainId;
|
|
92
113
|
this._currentChainId = newChainId;
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Storage as C4Storage } from "./wasm.js";
|
|
2
2
|
import { ProviderRpcError, RequestArguments, Cache, Config as C4Config, DataRequest, MethodType as C4MethodType, ProviderMessage } from './types.js';
|
|
3
3
|
import { EthSubscribeSubscriptionType, EthNewFilterType } from './subscriptionManager.js';
|
|
4
|
+
import Strategy from './strategy.js';
|
|
5
|
+
export { Strategy };
|
|
4
6
|
export { ProviderRpcError, RequestArguments, Cache, C4Config, DataRequest, C4MethodType as MethodType, ProviderMessage, EthSubscribeSubscriptionType, EthNewFilterType };
|
|
5
7
|
export declare function handle_request(req: DataRequest, conf: C4Config): Promise<void>;
|
|
6
8
|
export default class C4Client {
|
|
@@ -41,7 +43,7 @@ export default class C4Client {
|
|
|
41
43
|
* @param args - The arguments to execute the method with
|
|
42
44
|
* @returns The result
|
|
43
45
|
*/
|
|
44
|
-
rpc(method: string, args: any[]): Promise<any>;
|
|
46
|
+
rpc(method: string, args: any[], method_type?: C4MethodType): Promise<any>;
|
|
45
47
|
static register_storage(storage: C4Storage): Promise<void>;
|
|
46
48
|
request(args: RequestArguments): Promise<unknown>;
|
|
47
49
|
on(event: string, callback: (data: any) => void): this;
|
package/index.js
CHANGED
|
@@ -4,31 +4,13 @@ import { EventEmitter } from './eventEmitter.js';
|
|
|
4
4
|
import { ConnectionState } from './connectionState.js';
|
|
5
5
|
import { ProviderRpcError, MethodType as C4MethodType } from './types.js';
|
|
6
6
|
import { SubscriptionManager } from './subscriptionManager.js';
|
|
7
|
+
import Strategy from './strategy.js';
|
|
8
|
+
export { Strategy };
|
|
7
9
|
// Re-export types needed by consumers of the C4Client module
|
|
8
10
|
export { ProviderRpcError, C4MethodType as MethodType };
|
|
9
|
-
// Helper function for chain ID formatting (can be used by ConnectionManager and C4Client)
|
|
10
|
-
function formatChainId(value, debug) {
|
|
11
|
-
if (typeof value === 'string') {
|
|
12
|
-
if (value.startsWith('0x')) {
|
|
13
|
-
return value.toLowerCase();
|
|
14
|
-
}
|
|
15
|
-
const parsed = parseInt(value, 10);
|
|
16
|
-
if (!isNaN(parsed)) {
|
|
17
|
-
return '0x' + parsed.toString(16);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
else if (typeof value === 'number') {
|
|
21
|
-
return '0x' + value.toString(16);
|
|
22
|
-
}
|
|
23
|
-
if (debug) {
|
|
24
|
-
console.warn('Could not format chainId:', value);
|
|
25
|
-
}
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
11
|
async function fetch_rpc(urls, payload, as_proof = false) {
|
|
29
12
|
let last_error = "All nodes failed";
|
|
30
13
|
for (const url of urls) {
|
|
31
|
-
console.log({ url, payload });
|
|
32
14
|
const response = await fetch(url, {
|
|
33
15
|
method: 'POST',
|
|
34
16
|
body: JSON.stringify({ id: 1, jsonrpc: "2.0", ...payload }),
|
|
@@ -124,34 +106,55 @@ function check_trusted_blockhashes(trusted_block_hashes, c4w, chainId) {
|
|
|
124
106
|
c4w._free(ptr);
|
|
125
107
|
trusted_block_hashes.length = 0;
|
|
126
108
|
}
|
|
109
|
+
const default_config = {
|
|
110
|
+
'1': {
|
|
111
|
+
alias: ["mainnet", "eth", "0x1"],
|
|
112
|
+
beacon_apis: ["https://lodestar-mainnet.chainsafe.io"],
|
|
113
|
+
rpcs: ["https://rpc.ankr.com/eth"],
|
|
114
|
+
proofer: ["https://mainnet.colibri-proof.tech"],
|
|
115
|
+
},
|
|
116
|
+
'100': {
|
|
117
|
+
alias: ["gnosis", "xdai", "0x64"],
|
|
118
|
+
beacon_apis: ["https://gnosis.colibri-proof.tech"],
|
|
119
|
+
rpcs: ["https://rpc.ankr.com/gnosis"],
|
|
120
|
+
proofer: ["https://gnosis.colibri-proof.tech"],
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
function get_chain_id(chain_id) {
|
|
124
|
+
const chain_id_num = parseInt(chain_id);
|
|
125
|
+
if (!isNaN(chain_id_num))
|
|
126
|
+
return chain_id_num;
|
|
127
|
+
for (const chain in default_config) {
|
|
128
|
+
if (default_config[chain].alias.includes(chain_id))
|
|
129
|
+
return parseInt(chain);
|
|
130
|
+
}
|
|
131
|
+
throw new Error("Invalid chain id: " + chain_id);
|
|
132
|
+
}
|
|
127
133
|
export default class C4Client {
|
|
128
134
|
config;
|
|
129
135
|
eventEmitter;
|
|
130
136
|
connectionState;
|
|
131
137
|
subscriptionManager;
|
|
132
138
|
constructor(config) {
|
|
139
|
+
const chainId = config?.chainId ? get_chain_id(config?.chainId + '') : 1;
|
|
140
|
+
const chain_config = { ...default_config[chainId + ''] };
|
|
133
141
|
this.config = {
|
|
134
|
-
// Defaults including pollingInterval if not provided
|
|
135
|
-
chainId: 1,
|
|
136
|
-
beacon_apis: ["https://lodestar-mainnet.chainsafe.io"],
|
|
137
|
-
rpcs: ["https://rpc.ankr.com/eth"],
|
|
138
142
|
trusted_block_hashes: [],
|
|
139
|
-
proofer: ["https://mainnet.colibri-proof.tech"],
|
|
140
143
|
pollingInterval: 12000, // Default here, can be overridden by user config
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
rpcs: chain_config.rpcs || [],
|
|
145
|
+
beacon_apis: chain_config.beacon_apis || [],
|
|
146
|
+
proofer: chain_config.proofer || [],
|
|
147
|
+
...config, // User config overrides defaults
|
|
148
|
+
chainId,
|
|
143
149
|
};
|
|
150
|
+
if (!this.config.warningHandler)
|
|
151
|
+
this.config.warningHandler = async (req, message) => console.warn(message);
|
|
152
|
+
if (!this.config.proofStrategy)
|
|
153
|
+
this.config.proofStrategy = Strategy.VerifyIfPossible;
|
|
144
154
|
this.eventEmitter = new EventEmitter();
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const generalRpcCaller = async (method, params) => {
|
|
149
|
-
return this.rpc(method, params);
|
|
150
|
-
};
|
|
151
|
-
this.connectionState = new ConnectionState({ chainId: this.config.chainId, debug: this.config.debug }, fetchChainIdForConnectionState, // Use the specific callback
|
|
152
|
-
this.eventEmitter, formatChainId);
|
|
153
|
-
this.subscriptionManager = new SubscriptionManager(generalRpcCaller, // Use the general rpc caller
|
|
154
|
-
this.eventEmitter, { debug: this.config.debug, pollingInterval: this.config.pollingInterval });
|
|
155
|
+
this.connectionState = new ConnectionState({ chainId: parseInt(this.config.chainId + ''), debug: this.config.debug }, async () => this.rpc('eth_chainId', [], C4MethodType.LOCAL), // Use the specific callback
|
|
156
|
+
this.eventEmitter);
|
|
157
|
+
this.subscriptionManager = new SubscriptionManager(async (method, params) => this.rpc(method, params), this.eventEmitter, { debug: this.config.debug, pollingInterval: this.config.pollingInterval });
|
|
155
158
|
}
|
|
156
159
|
async getProoferConfig() {
|
|
157
160
|
const c4w = await getC4w();
|
|
@@ -221,7 +224,7 @@ export default class C4Client {
|
|
|
221
224
|
let ctx = 0;
|
|
222
225
|
try {
|
|
223
226
|
if (this.config.trusted_block_hashes && this.config.trusted_block_hashes.length > 0)
|
|
224
|
-
check_trusted_blockhashes(this.config.trusted_block_hashes, c4w, this.config.chainId);
|
|
227
|
+
check_trusted_blockhashes(this.config.trusted_block_hashes, c4w, parseInt(this.config.chainId));
|
|
225
228
|
// Call the C function
|
|
226
229
|
ctx = c4w._c4w_create_verify_ctx(copy_to_c(proof, c4w, free_buffers), proof.length, as_char_ptr(method, c4w, free_buffers), as_char_ptr(JSON.stringify(args), c4w, free_buffers), BigInt(this.config.chainId));
|
|
227
230
|
while (true) {
|
|
@@ -253,10 +256,11 @@ export default class C4Client {
|
|
|
253
256
|
* @param args - The arguments to execute the method with
|
|
254
257
|
* @returns The result
|
|
255
258
|
*/
|
|
256
|
-
async rpc(method, args) {
|
|
259
|
+
async rpc(method, args, method_type) {
|
|
257
260
|
// eth_subscribe and eth_unsubscribe are handled by C4Client.request before this method is called.
|
|
258
261
|
// This rpc method is for the underlying data fetching/proving.
|
|
259
|
-
|
|
262
|
+
if (method_type === undefined)
|
|
263
|
+
method_type = await this.getMethodSupport(method);
|
|
260
264
|
switch (method_type) {
|
|
261
265
|
case C4MethodType.PROOFABLE: {
|
|
262
266
|
if (this.config.verify && !this.config.verify(method, args)) {
|
|
@@ -293,9 +297,13 @@ export default class C4Client {
|
|
|
293
297
|
// If handleRequest returns a Promise, it means it's handling the request
|
|
294
298
|
return subscriptionResult;
|
|
295
299
|
}
|
|
300
|
+
let conf = this.config.chains[this.config.chainId];
|
|
301
|
+
let strategy = conf?.proofStrategy || this.config.proofStrategy;
|
|
296
302
|
// If not handled by SubscriptionManager, proceed with standard RPC call logic
|
|
297
303
|
try {
|
|
298
|
-
const result =
|
|
304
|
+
const result = strategy
|
|
305
|
+
? await strategy(this, args, this.config, fetch_rpc)
|
|
306
|
+
: await this.rpc(method, paramsArray);
|
|
299
307
|
this.connectionState.processSuccessfulRequest(method, result);
|
|
300
308
|
return result;
|
|
301
309
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corpus-core/colibri-stateless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Colibri is a stateless and trustless ethereum client, which is optimized for the mobile apps or embedded devices, because it does not hols the state, but verifies on demand.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/strategy.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ColibriClient, RequestArguments, Config, FetchRpc } from './types.js';
|
|
2
|
+
declare function OnlyProofStrategy(client: ColibriClient, req: RequestArguments, config: Config, fetch_rpc: FetchRpc): Promise<any>;
|
|
3
|
+
declare function ProofIfPossibleStrategy(client: ColibriClient, req: RequestArguments, config: Config, fetch_rpc: FetchRpc): Promise<any>;
|
|
4
|
+
declare function WarningStrategy(client: ColibriClient, req: RequestArguments, config: Config, fetch_rpc: FetchRpc): Promise<any>;
|
|
5
|
+
declare const _default: {
|
|
6
|
+
VerifiedOnly: typeof OnlyProofStrategy;
|
|
7
|
+
VerifyIfPossible: typeof ProofIfPossibleStrategy;
|
|
8
|
+
WarningWithFallback: typeof WarningStrategy;
|
|
9
|
+
};
|
|
10
|
+
export default _default;
|
package/strategy.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { MethodType } from './types.js';
|
|
2
|
+
function argsToArray(args) {
|
|
3
|
+
return Array.isArray(args) ? args : (args ? [args] : []);
|
|
4
|
+
}
|
|
5
|
+
function deepEqual(a, b) {
|
|
6
|
+
if (a === b)
|
|
7
|
+
return true;
|
|
8
|
+
if (a === null || b === null)
|
|
9
|
+
return false;
|
|
10
|
+
if (a.constructor !== b.constructor)
|
|
11
|
+
return false;
|
|
12
|
+
if (a instanceof Date)
|
|
13
|
+
return a.getTime() === b.getTime();
|
|
14
|
+
if (a instanceof RegExp)
|
|
15
|
+
return a.source === b.source && a.flags === b.flags;
|
|
16
|
+
if (a instanceof Uint8Array)
|
|
17
|
+
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
18
|
+
if (a instanceof Array)
|
|
19
|
+
return a.length === b.length && a.every((value, index) => deepEqual(value, b[index]));
|
|
20
|
+
if (a instanceof Object)
|
|
21
|
+
return Object.keys(a).every(key => b[key] === undefined || deepEqual(a[key], b[key]));
|
|
22
|
+
if (a instanceof String)
|
|
23
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
24
|
+
if (a instanceof Number)
|
|
25
|
+
return a.toFixed(10) === b.toFixed(10);
|
|
26
|
+
if (a instanceof Boolean)
|
|
27
|
+
return a === b;
|
|
28
|
+
if (a instanceof BigInt)
|
|
29
|
+
return a.toString() === b.toString();
|
|
30
|
+
if (a instanceof Buffer)
|
|
31
|
+
return a.equals(b);
|
|
32
|
+
if (a instanceof Map)
|
|
33
|
+
return a.size === b.size && Array.from(a.entries()).every(([key, value]) => deepEqual(value, b.get(key)));
|
|
34
|
+
if (a instanceof Set)
|
|
35
|
+
return a.size === b.size && Array.from(a).every(value => b.has(value));
|
|
36
|
+
if (a instanceof Date)
|
|
37
|
+
return a.getTime() === b.getTime();
|
|
38
|
+
return a == b;
|
|
39
|
+
}
|
|
40
|
+
function fetch_unverified_rpc(config, req, fetch_rpc) {
|
|
41
|
+
const fallback_provider = config.fallback_provider;
|
|
42
|
+
if (fallback_provider)
|
|
43
|
+
return fallback_provider.request(req);
|
|
44
|
+
let conf = config.chains[config.chainId];
|
|
45
|
+
let rpcs = conf?.rpcs || config.rpcs;
|
|
46
|
+
if (!rpcs || !Array.isArray(rpcs) || rpcs.length === 0)
|
|
47
|
+
throw new Error("No RPC- Endpoint configured");
|
|
48
|
+
return fetch_rpc(rpcs, req, false);
|
|
49
|
+
}
|
|
50
|
+
function OnlyProofStrategy(client, req, config, fetch_rpc) {
|
|
51
|
+
return client.rpc(req.method, argsToArray(req.params));
|
|
52
|
+
}
|
|
53
|
+
async function ProofIfPossibleStrategy(client, req, config, fetch_rpc) {
|
|
54
|
+
const method_type = await client.getMethodSupport(req.method);
|
|
55
|
+
switch (method_type) {
|
|
56
|
+
case MethodType.PROOFABLE:
|
|
57
|
+
case MethodType.LOCAL:
|
|
58
|
+
return client.rpc(req.method, argsToArray(req.params), method_type);
|
|
59
|
+
default:
|
|
60
|
+
return fetch_unverified_rpc(config, req, fetch_rpc);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function WarningStrategy(client, req, config, fetch_rpc) {
|
|
64
|
+
const method_type = await client.getMethodSupport(req.method);
|
|
65
|
+
switch (method_type) {
|
|
66
|
+
case MethodType.LOCAL:
|
|
67
|
+
return client.rpc(req.method, argsToArray(req.params), method_type);
|
|
68
|
+
case MethodType.UNPROOFABLE:
|
|
69
|
+
case MethodType.NOT_SUPPORTED:
|
|
70
|
+
return fetch_unverified_rpc(config, req, fetch_rpc);
|
|
71
|
+
case MethodType.PROOFABLE: {
|
|
72
|
+
const [verified_result, unverified_result] = await Promise.all([
|
|
73
|
+
client.rpc(req.method, argsToArray(req.params), MethodType.PROOFABLE)
|
|
74
|
+
.catch(async (err) => {
|
|
75
|
+
await config.warningHandler(req, `[Warning] ${req.method} failed to be verfiy: ${err.message}, falling back to Default`);
|
|
76
|
+
return undefined;
|
|
77
|
+
}),
|
|
78
|
+
fetch_unverified_rpc(config, req, fetch_rpc)
|
|
79
|
+
]);
|
|
80
|
+
if (verified_result !== undefined && !deepEqual(verified_result, unverified_result))
|
|
81
|
+
await config.warningHandler(req, `[Warning] ${req.method} does not match the rpc-result`);
|
|
82
|
+
return unverified_result;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export default {
|
|
87
|
+
VerifiedOnly: OnlyProofStrategy,
|
|
88
|
+
VerifyIfPossible: ProofIfPossibleStrategy,
|
|
89
|
+
WarningWithFallback: WarningStrategy
|
|
90
|
+
};
|
package/subscriptionManager.js
CHANGED
|
@@ -155,9 +155,10 @@ export class SubscriptionManager {
|
|
|
155
155
|
if (currentVerifiableBlockNumber) {
|
|
156
156
|
let fromBlock = sub.lastPolledBlockNumber ? sub.lastPolledBlockNumber + 1n : currentVerifiableBlockNumber;
|
|
157
157
|
if (sub.kind === 'newHeads') { // For newHeads, we only care if the latest is newer
|
|
158
|
-
if (!sub.lastPolledBlockNumber
|
|
158
|
+
if (!sub.lastPolledBlockNumber)
|
|
159
|
+
sub.lastPolledBlockNumber = currentVerifiableBlockNumber;
|
|
160
|
+
if (currentVerifiableBlockNumber <= sub.lastPolledBlockNumber)
|
|
159
161
|
return []; // No new head yet for eth_subscribe('newHeads')
|
|
160
|
-
}
|
|
161
162
|
// If new, target currentVerifiableBlockNumber for eth_getBlockByNumber
|
|
162
163
|
fromBlock = currentVerifiableBlockNumber;
|
|
163
164
|
}
|
package/types.d.ts
CHANGED
|
@@ -4,6 +4,13 @@ export declare class ProviderRpcError extends Error {
|
|
|
4
4
|
constructor(code: number, message: string, data?: unknown);
|
|
5
5
|
static createError(error: any): ProviderRpcError;
|
|
6
6
|
}
|
|
7
|
+
export interface ColibriClient {
|
|
8
|
+
rpc(method: string, params: any[], method_type?: MethodType): Promise<any>;
|
|
9
|
+
getMethodSupport(method: string): Promise<MethodType>;
|
|
10
|
+
}
|
|
11
|
+
export type FetchRpc = (urls: string[], payload: any, as_proof: boolean) => Promise<any>;
|
|
12
|
+
export type ProofStrategy = (client: ColibriClient, req: RequestArguments, config: Config, fetch_rpc: FetchRpc) => Promise<any>;
|
|
13
|
+
export type WarningHandler = (req: RequestArguments, message: string) => Promise<any>;
|
|
7
14
|
export interface RequestArguments {
|
|
8
15
|
readonly method: string;
|
|
9
16
|
readonly params?: readonly unknown[] | object;
|
|
@@ -20,17 +27,30 @@ export interface Cache {
|
|
|
20
27
|
get(req: DataRequest): Uint8Array | undefined;
|
|
21
28
|
set(req: DataRequest, data: Uint8Array): void;
|
|
22
29
|
}
|
|
23
|
-
export interface
|
|
24
|
-
chainId: number;
|
|
30
|
+
export interface ChainConfig {
|
|
25
31
|
beacon_apis: string[];
|
|
26
32
|
rpcs: string[];
|
|
27
33
|
proofer?: string[];
|
|
28
34
|
trusted_block_hashes: string[];
|
|
35
|
+
verify?: (method: string, args: any[]) => boolean;
|
|
36
|
+
pollingInterval?: number;
|
|
37
|
+
proofStrategy?: ProofStrategy;
|
|
38
|
+
}
|
|
39
|
+
export interface EIP1193Client {
|
|
40
|
+
request(args: RequestArguments): Promise<unknown>;
|
|
41
|
+
on(event: string, callback: (data: any) => void): this;
|
|
42
|
+
removeListener(event: string, callback: (data: any) => void): this;
|
|
43
|
+
}
|
|
44
|
+
export interface Config extends ChainConfig {
|
|
45
|
+
chainId: number | string;
|
|
29
46
|
cache?: Cache;
|
|
30
47
|
debug?: boolean;
|
|
31
48
|
include_code?: boolean;
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
chains: {
|
|
50
|
+
[chainId: number]: ChainConfig;
|
|
51
|
+
};
|
|
52
|
+
fallback_provider?: EIP1193Client;
|
|
53
|
+
warningHandler: WarningHandler;
|
|
34
54
|
}
|
|
35
55
|
export interface DataRequest {
|
|
36
56
|
method: string;
|