univo 0.2.7 → 0.2.9
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/dist/cli.mjs +1 -1
- package/dist/index.mjs +83 -50
- package/dist/realtime.mjs +10 -14
- package/dist/rpc.d.mts +1 -1
- package/dist/rpc.d.ts +1 -1
- package/dist/shared/{univo.Crj0ggpm.mjs → univo.RhVE6xw6.mjs} +2 -5
- package/dist/transport.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { config } from 'dotenv';
|
|
|
5
5
|
import { WebSocket } from 'partysocket';
|
|
6
6
|
import { defineCommand, runMain } from 'citty';
|
|
7
7
|
import { http } from './transport.mjs';
|
|
8
|
-
import { c as createLogger, v as version,
|
|
8
|
+
import { c as createLogger, v as version, f as name } from './shared/univo.RhVE6xw6.mjs';
|
|
9
9
|
import './shared/univo.C0flyVee.mjs';
|
|
10
10
|
|
|
11
11
|
const log = createLogger({ quiet: false });
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createLogger, d as decompress, a as decoder, h as hexToNumber, i as isHexEqual, r as retry, v as version, n as
|
|
1
|
+
import { c as createLogger, d as decompress, a as decoder, h as hexToNumber, i as isHexEqual, r as retry, v as version, n as normalizeHex } from './shared/univo.RhVE6xw6.mjs';
|
|
2
2
|
import { c as createException, g as getException, a as catchException } from './shared/univo.C0flyVee.mjs';
|
|
3
3
|
|
|
4
4
|
function matchFilter(block, filter) {
|
|
@@ -129,34 +129,62 @@ function indexer(opts) {
|
|
|
129
129
|
}
|
|
130
130
|
return block;
|
|
131
131
|
}
|
|
132
|
+
const GetBlockError = createException("Failed to load block from the provided `getBlock` function");
|
|
132
133
|
const public_getFinalizedHeight = async (chain) => {
|
|
133
|
-
const [stored] = await
|
|
134
|
+
const [[stored], finalizedBlock] = await Promise.all([
|
|
135
|
+
metadata.blocks.list({ chain }),
|
|
136
|
+
//
|
|
137
|
+
getBlock({ chain, number: "finalized" })
|
|
138
|
+
]);
|
|
139
|
+
if (finalizedBlock === null) {
|
|
140
|
+
log.debug("Failed to fetch finalized block and unable to determine finalized height, aborting...");
|
|
141
|
+
throw new Error(GetBlockError);
|
|
142
|
+
}
|
|
143
|
+
const finalizedHeight = hexToNumber(finalizedBlock.eth_getBlockByNumber.number);
|
|
134
144
|
if (stored === void 0) {
|
|
135
|
-
return
|
|
145
|
+
return finalizedHeight;
|
|
136
146
|
}
|
|
137
|
-
|
|
147
|
+
const indexerHeight = hexToNumber(stored.number) - 1;
|
|
148
|
+
return Math.min(indexerHeight, finalizedHeight);
|
|
138
149
|
};
|
|
139
150
|
const public_writeUnfinalizedHeads = async (heads) => {
|
|
151
|
+
if (heads.length === 0) {
|
|
152
|
+
return log.debug("No heads received, returning...");
|
|
153
|
+
}
|
|
140
154
|
let chain = void 0;
|
|
141
155
|
for (const head of heads) {
|
|
142
156
|
if (chain === void 0) {
|
|
143
157
|
chain = head.chain;
|
|
144
158
|
}
|
|
145
159
|
if (!isHexEqual(chain, head.chain)) {
|
|
146
|
-
throw new Error(
|
|
160
|
+
throw new Error("Received heads from separate chains");
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
163
|
if (chain === void 0) {
|
|
150
|
-
|
|
164
|
+
throw new Error("Internal error. Expected chain to be defined after checking heads length");
|
|
151
165
|
}
|
|
152
166
|
log.debug(`Received ${heads.length} unfinalized heads...`);
|
|
153
167
|
const blocks_start = Date.now();
|
|
154
|
-
const blocks_nullable = await Promise.all(
|
|
155
|
-
|
|
168
|
+
const [finalizedBlock, ...blocks_nullable] = await Promise.all([
|
|
169
|
+
getBlock({ chain, number: "finalized" }),
|
|
170
|
+
...heads.map(async (head) => {
|
|
156
171
|
return await getBlock({ chain, number: head.number, hash: head.hash });
|
|
157
172
|
})
|
|
158
|
-
);
|
|
159
|
-
|
|
173
|
+
]);
|
|
174
|
+
if (finalizedBlock === null) {
|
|
175
|
+
log.debug("Failed to determine finalized height when processing unfinalized heads");
|
|
176
|
+
throw new Error(GetBlockError);
|
|
177
|
+
}
|
|
178
|
+
const finalizedHeight = hexToNumber(finalizedBlock.eth_getBlockByNumber.number);
|
|
179
|
+
const blocks = blocks_nullable.flatMap((block) => {
|
|
180
|
+
if (block === null) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
if (hexToNumber(block.eth_getBlockByNumber.number) <= finalizedHeight) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
return block;
|
|
187
|
+
});
|
|
160
188
|
if (blocks.length === 0) {
|
|
161
189
|
return log.debug("All blocks failed to load, aborting early...");
|
|
162
190
|
}
|
|
@@ -239,61 +267,68 @@ function indexer(opts) {
|
|
|
239
267
|
await Promise.all(promises);
|
|
240
268
|
};
|
|
241
269
|
const public_writeFinalizedHeads = async (heads) => {
|
|
270
|
+
if (heads.length === 0) {
|
|
271
|
+
return log.debug("No heads received, returning...");
|
|
272
|
+
}
|
|
273
|
+
log.debug(`Received ${heads.length} finalized heads...`);
|
|
242
274
|
let chain = void 0;
|
|
243
275
|
for (const head of heads) {
|
|
244
276
|
if (chain === void 0) {
|
|
245
277
|
chain = head.chain;
|
|
246
278
|
}
|
|
247
279
|
if (!isHexEqual(chain, head.chain)) {
|
|
248
|
-
throw new Error(
|
|
280
|
+
throw new Error("Received heads from separate chains");
|
|
249
281
|
}
|
|
250
282
|
}
|
|
251
283
|
if (chain === void 0) {
|
|
252
|
-
throw new Error(
|
|
284
|
+
throw new Error("Internal error. Expected chain to be defined after checking heads length");
|
|
253
285
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
286
|
+
const [firstHead, ...remainingHeads] = heads;
|
|
287
|
+
if (firstHead === void 0) {
|
|
288
|
+
throw new Error("Internal error. Expected firstHead to be defined after checking heads length");
|
|
289
|
+
}
|
|
290
|
+
let previousHead = firstHead;
|
|
291
|
+
for (const head of remainingHeads) {
|
|
292
|
+
if (hexToNumber(head.number) !== hexToNumber(previousHead.number) + 1) {
|
|
293
|
+
throw new Error("Found invalid block number in received heads, aborting...");
|
|
294
|
+
}
|
|
295
|
+
if (!isHexEqual(head.parentHash, previousHead.hash)) {
|
|
296
|
+
throw new Error("Found invalid block hash in received heads, aborting...");
|
|
297
|
+
}
|
|
298
|
+
previousHead = head;
|
|
299
|
+
}
|
|
300
|
+
const [[unfinalizedMetadataBlock], finalizedBlock] = await Promise.all([
|
|
301
|
+
metadata.blocks.list({ chain }),
|
|
257
302
|
//
|
|
258
303
|
getBlock({ chain, number: "finalized" })
|
|
259
304
|
]);
|
|
260
|
-
if (indexerHeight === null) {
|
|
261
|
-
return log.debug(`No unfinalized blocks processed for chain ${hexToNumber(chain)}, aborting...`);
|
|
262
|
-
}
|
|
263
305
|
if (finalizedBlock === null) {
|
|
264
|
-
log.debug("Failed to load finalized block
|
|
306
|
+
log.debug("Failed to load chain finalized block. Request should be retried");
|
|
265
307
|
throw new Error(GetBlockError);
|
|
266
308
|
}
|
|
267
309
|
const finalizedHeight = hexToNumber(finalizedBlock.eth_getBlockByNumber.number);
|
|
268
|
-
|
|
269
|
-
const newHeads = heads.filter((head) => {
|
|
310
|
+
for (const head of heads) {
|
|
270
311
|
if (hexToNumber(head.number) > finalizedHeight) {
|
|
271
|
-
|
|
312
|
+
throw new Error("Received invalid finalized heads");
|
|
272
313
|
}
|
|
273
|
-
if (hexToNumber(head.number) > indexerHeight) {
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
return false;
|
|
277
|
-
});
|
|
278
|
-
const [firstHead, ...remainingHeads] = newHeads;
|
|
279
|
-
if (firstHead === void 0) {
|
|
280
|
-
return log.debug("Received no new finalized heads, aborting...");
|
|
281
314
|
}
|
|
282
|
-
if (
|
|
283
|
-
log.debug("
|
|
284
|
-
throw new Error(InvalidHeadsError);
|
|
315
|
+
if (unfinalizedMetadataBlock === void 0) {
|
|
316
|
+
return log.debug("No heads to finalize, returning...");
|
|
285
317
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
318
|
+
const indexerHeight = hexToNumber(unfinalizedMetadataBlock.number) - 1;
|
|
319
|
+
log.debug(`Indexer height ${indexerHeight}, finalized height ${finalizedHeight}`);
|
|
320
|
+
if (indexerHeight === finalizedHeight) {
|
|
321
|
+
return log.debug("No heads to finalize, returning...");
|
|
322
|
+
}
|
|
323
|
+
const newHeads = heads.filter((head) => {
|
|
324
|
+
return hexToNumber(head.number) > indexerHeight;
|
|
325
|
+
});
|
|
326
|
+
const [firstNewHead] = newHeads;
|
|
327
|
+
if (firstNewHead === void 0) {
|
|
328
|
+
return log.debug("No new heads received, returning...");
|
|
329
|
+
}
|
|
330
|
+
if (hexToNumber(firstNewHead.number) !== indexerHeight + 1) {
|
|
331
|
+
throw new Error("Client advanced too far. Heads received are greater is than the indexer height");
|
|
297
332
|
}
|
|
298
333
|
for (const head of newHeads) {
|
|
299
334
|
const processed = await metadata.blocks.get({ chain: head.chain, number: head.number });
|
|
@@ -320,7 +355,7 @@ function indexer(opts) {
|
|
|
320
355
|
block = await getBlock({ chain: head.chain, number: head.number, hash: head.hash });
|
|
321
356
|
}
|
|
322
357
|
if (block === null) {
|
|
323
|
-
throw new Error(
|
|
358
|
+
throw new Error("Received invalid finalized heads");
|
|
324
359
|
}
|
|
325
360
|
const promises = events_grouped_by_storage_map.entries().map(async ([storage, grouped_events]) => {
|
|
326
361
|
const batch = [];
|
|
@@ -445,6 +480,7 @@ function indexer(opts) {
|
|
|
445
480
|
};
|
|
446
481
|
return new Proxy(value, createProxyHandler());
|
|
447
482
|
};
|
|
483
|
+
const IncompleteBlockError = createException("Received block with missing required property");
|
|
448
484
|
const private_writeEvents = async (params) => {
|
|
449
485
|
if (all_events.length === 0) return { failures: [] };
|
|
450
486
|
const relevant_events = all_events.filter((event2) => params.events.includes(event2.id));
|
|
@@ -636,6 +672,7 @@ function indexer(opts) {
|
|
|
636
672
|
events_grouped_by_storage_map.set(event2.storage, group);
|
|
637
673
|
return event2;
|
|
638
674
|
};
|
|
675
|
+
const UnknownMethodError = createException("The requested method does not exist");
|
|
639
676
|
const handler = async (req) => {
|
|
640
677
|
let body_buffer;
|
|
641
678
|
try {
|
|
@@ -702,6 +739,7 @@ function indexer(opts) {
|
|
|
702
739
|
} catch (error) {
|
|
703
740
|
const message = getException(error);
|
|
704
741
|
if (message) {
|
|
742
|
+
log.error(message);
|
|
705
743
|
return Response.json(
|
|
706
744
|
{ jsonrpc: "2.0", id: json.id, error: { code: 0, message } },
|
|
707
745
|
//
|
|
@@ -720,10 +758,5 @@ function indexer(opts) {
|
|
|
720
758
|
};
|
|
721
759
|
return { fetch: handler, event };
|
|
722
760
|
}
|
|
723
|
-
const InvalidHeadsError = createException("Received invalid finalized heads");
|
|
724
|
-
const UnknownMethodError = createException("The requested method does not exist");
|
|
725
|
-
const MultipleChainsError = createException("Received heads from separate chains");
|
|
726
|
-
const IncompleteBlockError = createException("Received block with missing required property");
|
|
727
|
-
const GetBlockError = createException("Failed to load block from the provided `getBlock` function");
|
|
728
761
|
|
|
729
762
|
export { indexer, matchFilter };
|
package/dist/realtime.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createLogger,
|
|
1
|
+
import { c as createLogger, b as iife, h as hexToNumber, e as numberToHex, m as mutex, r as retry, i as isHexEqual } from './shared/univo.RhVE6xw6.mjs';
|
|
2
2
|
|
|
3
3
|
const MAX_LENGTH = 1e4;
|
|
4
4
|
function defineBlockchain(opts) {
|
|
@@ -139,18 +139,14 @@ function realtime(opts) {
|
|
|
139
139
|
getBlockByHash,
|
|
140
140
|
quiet: opts.quiet ?? false
|
|
141
141
|
});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
await indexer.reconcile(indexerBlock);
|
|
151
|
-
await indexer.reconcile(latestBlock);
|
|
152
|
-
log.debug("Reconciled local indexer chain");
|
|
153
|
-
}
|
|
142
|
+
log.debug(`Indexer last finalized at ${initialIndexerHeight}, reconciling local chain...`);
|
|
143
|
+
const indexerBlock = await opts.node.request({
|
|
144
|
+
method: "eth_getBlockByNumber",
|
|
145
|
+
params: [numberToHex(initialIndexerHeight), false]
|
|
146
|
+
});
|
|
147
|
+
await indexer.reconcile(indexerBlock);
|
|
148
|
+
await indexer.reconcile(latestBlock);
|
|
149
|
+
log.debug("Reconciled local indexer chain");
|
|
154
150
|
await opts.node.subscribe("newHeads", async (head) => {
|
|
155
151
|
try {
|
|
156
152
|
await indexer.reconcile(head);
|
|
@@ -161,7 +157,7 @@ function realtime(opts) {
|
|
|
161
157
|
}
|
|
162
158
|
});
|
|
163
159
|
log.debug("Subscribed indexer chain to new heads");
|
|
164
|
-
let indexerHeight = initialIndexerHeight
|
|
160
|
+
let indexerHeight = initialIndexerHeight;
|
|
165
161
|
const poll = async () => {
|
|
166
162
|
try {
|
|
167
163
|
const finalizedBlock = await opts.node.request({
|
package/dist/rpc.d.mts
CHANGED
|
@@ -57,7 +57,7 @@ type IndexerRpc = {
|
|
|
57
57
|
* Accepts a chain identifier
|
|
58
58
|
* @returns Height of the last finalized block indexed
|
|
59
59
|
*/
|
|
60
|
-
public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number
|
|
60
|
+
public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number>;
|
|
61
61
|
/**
|
|
62
62
|
* Accepts a reorganised block and deletes all related events from storage
|
|
63
63
|
*/
|
package/dist/rpc.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ type IndexerRpc = {
|
|
|
57
57
|
* Accepts a chain identifier
|
|
58
58
|
* @returns Height of the last finalized block indexed
|
|
59
59
|
*/
|
|
60
|
-
public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number
|
|
60
|
+
public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number>;
|
|
61
61
|
/**
|
|
62
62
|
* Accepts a reorganised block and deletes all related events from storage
|
|
63
63
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const name = "univo";
|
|
2
|
-
const version = "0.2.
|
|
2
|
+
const version = "0.2.9";
|
|
3
3
|
|
|
4
4
|
function createLogger(opts) {
|
|
5
5
|
let prefix = `[${name}@${version}]`;
|
|
@@ -73,9 +73,6 @@ function raise(...args) {
|
|
|
73
73
|
if (args[0] instanceof Error) throw args[0];
|
|
74
74
|
throw new Error(...args);
|
|
75
75
|
}
|
|
76
|
-
function nonNullable(value) {
|
|
77
|
-
return value !== null && value !== void 0;
|
|
78
|
-
}
|
|
79
76
|
async function compress(input) {
|
|
80
77
|
const compressed = new Blob([input]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
81
78
|
return new Response(compressed).arrayBuffer();
|
|
@@ -92,4 +89,4 @@ const normalizeHex = (hex, length) => {
|
|
|
92
89
|
return `0x${hex.slice(2).toLowerCase().padStart(length, "0")}`;
|
|
93
90
|
};
|
|
94
91
|
|
|
95
|
-
export { decoder as a,
|
|
92
|
+
export { decoder as a, iife as b, createLogger as c, decompress as d, numberToHex as e, name as f, compress as g, hexToNumber as h, isHexEqual as i, raise as j, mutex as m, normalizeHex as n, retry as r, version as v };
|
package/dist/transport.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ws from 'ws';
|
|
2
2
|
import { WebSocket } from 'partysocket';
|
|
3
3
|
import { c as createException } from './shared/univo.C0flyVee.mjs';
|
|
4
|
-
import {
|
|
4
|
+
import { g as compress, j as raise, c as createLogger } from './shared/univo.RhVE6xw6.mjs';
|
|
5
5
|
|
|
6
6
|
function createSocket(url, opts) {
|
|
7
7
|
const socket = new WebSocket(url, [], { WebSocket: ws });
|