envio 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/index.d.ts +399 -156
- package/package.json +6 -6
- package/src/AddressRows.res +121 -0
- package/src/AddressRows.res.mjs +143 -0
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +2 -1
- package/src/ChainState.res +82 -68
- package/src/ChainState.res.mjs +81 -65
- package/src/ChainState.resi +14 -9
- package/src/Config.res +41 -91
- package/src/Config.res.mjs +34 -68
- package/src/ContractMapping.res +66 -0
- package/src/ContractMapping.res.mjs +73 -0
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +4 -0
- package/src/Envio.res +54 -76
- package/src/EventConfigBuilder.res +157 -30
- package/src/EventConfigBuilder.res.mjs +118 -24
- package/src/FetchState.res +59 -67
- package/src/FetchState.res.mjs +34 -44
- package/src/HandlerRegister.res +20 -11
- package/src/HandlerRegister.res.mjs +22 -5
- package/src/Hasura.res +30 -22
- package/src/Hasura.res.mjs +11 -5
- package/src/InMemoryStore.res +18 -36
- package/src/InMemoryStore.res.mjs +12 -26
- package/src/IndexerState.res +21 -1
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +1 -0
- package/src/Internal.res +33 -13
- package/src/Internal.res.mjs +12 -16
- package/src/Main.res +27 -20
- package/src/Main.res.mjs +19 -14
- package/src/MemoryStorage.res +78 -73
- package/src/MemoryStorage.res.mjs +66 -81
- package/src/Metrics.res +15 -1
- package/src/Metrics.res.mjs +5 -1
- package/src/Persistence.res +34 -18
- package/src/Persistence.res.mjs +8 -5
- package/src/PgStorage.res +189 -66
- package/src/PgStorage.res.mjs +93 -59
- package/src/Rollback.res +14 -10
- package/src/Rollback.res.mjs +4 -2
- package/src/SimulateItems.res +254 -9
- package/src/SimulateItems.res.mjs +214 -47
- package/src/TestIndexer.res +119 -121
- package/src/TestIndexer.res.mjs +95 -100
- package/src/Utils.res +7 -0
- package/src/Utils.res.mjs +9 -2
- package/src/Writing.res +2 -0
- package/src/Writing.res.mjs +2 -1
- package/src/bindings/ClickHouse.res +39 -6
- package/src/bindings/ClickHouse.res.mjs +29 -4
- package/src/bindings/NodeJs.res +9 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/bindings/Postgres.res +9 -0
- package/src/bindings/Postgres.res.mjs +3 -0
- package/src/db/EntityHistory.res +12 -18
- package/src/db/EntityHistory.res.mjs +3 -14
- package/src/db/InternalTable.res +182 -65
- package/src/db/InternalTable.res.mjs +183 -73
- package/src/db/Table.res +24 -0
- package/src/db/Table.res.mjs +20 -1
- package/src/sources/AddressSet.res +0 -22
- package/src/sources/AddressStore.res +48 -88
- package/src/sources/AddressStore.res.mjs +11 -22
- package/src/sources/EvmHyperSyncSource.res +3 -2
- package/src/sources/SimulateSource.res +8 -4
- package/src/sources/SimulateSource.res.mjs +7 -3
- package/src/sources/Svm.res +34 -7
- package/src/sources/Svm.res.mjs +32 -4
- package/src/sources/SvmHyperSyncClient.res +24 -30
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +88 -36
- package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
- package/src/sources/TransactionStore.res +38 -0
- package/src/sources/TransactionStore.res.mjs +5 -0
- package/svm.schema.json +37 -82
|
@@ -2,17 +2,153 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Table from "./Table.res.mjs";
|
|
4
4
|
import * as Utils from "../Utils.res.mjs";
|
|
5
|
-
import * as Config from "../Config.res.mjs";
|
|
6
5
|
import * as Address from "../Address.res.mjs";
|
|
7
6
|
import * as ChainId from "../ChainId.res.mjs";
|
|
7
|
+
import * as Postgres from "../bindings/Postgres.res.mjs";
|
|
8
|
+
import * as AddressRows from "../AddressRows.res.mjs";
|
|
8
9
|
import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
|
|
9
10
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
11
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
11
12
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
12
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
13
14
|
|
|
15
|
+
let undefinedTableSqlState = "42P01";
|
|
16
|
+
|
|
17
|
+
function isUndefinedTable(exn) {
|
|
18
|
+
let e = Primitive_exceptions.internalToException(exn);
|
|
19
|
+
if (e.RE_EXN_ID === "JsExn") {
|
|
20
|
+
return e._1.code === undefinedTableSqlState;
|
|
21
|
+
} else {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function chainIdArrayType(pgSchema, chainIdMode) {
|
|
27
|
+
return Table.getPgFieldType("ChainId", pgSchema, true, false, false, chainIdMode);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let table = Table.mkTable("envio_contracts", undefined, [
|
|
31
|
+
Table.mkField("id", "SmallInt", S$RescriptSchema.int, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
32
|
+
Table.mkField("name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
33
|
+
], undefined);
|
|
34
|
+
|
|
35
|
+
function makeInsertQuery(pgSchema) {
|
|
36
|
+
return `INSERT INTO "` + pgSchema + `"."` + table.tableName + `" ("id", "name")
|
|
37
|
+
SELECT * FROM unnest($1::` + "SMALLINT" + `[],$2::` + "TEXT" + `[]);`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function insert(sql, pgSchema, contractNames) {
|
|
41
|
+
return sql.unsafe(makeInsertQuery(pgSchema), [
|
|
42
|
+
contractNames.map((param, idx) => idx),
|
|
43
|
+
contractNames
|
|
44
|
+
], {prepare: true});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function read(sql, pgSchema) {
|
|
48
|
+
try {
|
|
49
|
+
let rows = await sql.unsafe(`SELECT "name" FROM "` + pgSchema + `"."` + table.tableName + `" ORDER BY "id";`);
|
|
50
|
+
return rows.map(row => row.name);
|
|
51
|
+
} catch (raw_exn) {
|
|
52
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
53
|
+
if (isUndefinedTable(exn)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw exn;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let EnvioContracts = {
|
|
61
|
+
table: table,
|
|
62
|
+
makeInsertQuery: makeInsertQuery,
|
|
63
|
+
insert: insert,
|
|
64
|
+
read: read
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
let name = "envio_addresses";
|
|
68
|
+
|
|
69
|
+
let table$1 = Table.mkTable(name, undefined, [
|
|
70
|
+
Table.mkField("chain_id", "ChainId", ChainId.schema, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
71
|
+
Table.mkField("address", "Bytea", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
72
|
+
Table.mkField("contract_id", "SmallInt", S$RescriptSchema.int, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
73
|
+
Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
74
|
+
], undefined);
|
|
75
|
+
|
|
76
|
+
function makeInsertQuery$1(pgSchema, chainIdModeOpt) {
|
|
77
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
78
|
+
let chainIdArrayType$1 = chainIdArrayType(pgSchema, chainIdMode);
|
|
79
|
+
return `INSERT INTO "` + pgSchema + `"."` + table$1.tableName + `" ("chain_id", "address", "contract_id", "registration_block")
|
|
80
|
+
SELECT * FROM unnest($1::` + chainIdArrayType$1 + `,$2::` + "BYTEA" + `[],$3::` + "SMALLINT" + `[],$4::` + "INTEGER" + `[])
|
|
81
|
+
ON CONFLICT ("chain_id", "address", "contract_id") DO NOTHING;`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function insert$1(sql, pgSchema, rows, chainIdModeOpt) {
|
|
85
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
86
|
+
let chainIds = [];
|
|
87
|
+
let addresses = [];
|
|
88
|
+
let contractIds = [];
|
|
89
|
+
let registrationBlocks = [];
|
|
90
|
+
rows.forEach(row => {
|
|
91
|
+
chainIds.push(row.chainId);
|
|
92
|
+
addresses.push(row.address);
|
|
93
|
+
contractIds.push(row.contractId);
|
|
94
|
+
registrationBlocks.push(row.registrationBlock);
|
|
95
|
+
});
|
|
96
|
+
return sql.unsafe(makeInsertQuery$1(pgSchema, chainIdMode), [
|
|
97
|
+
chainIds,
|
|
98
|
+
sql.typed(addresses, Postgres.byteaArrayOid),
|
|
99
|
+
contractIds,
|
|
100
|
+
registrationBlocks
|
|
101
|
+
], {prepare: true});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function makeDeleteQuery(pgSchema, chainIdModeOpt) {
|
|
105
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
106
|
+
let chainIdArrayType$1 = chainIdArrayType(pgSchema, chainIdMode);
|
|
107
|
+
return `DELETE FROM "` + pgSchema + `"."` + table$1.tableName + `"
|
|
108
|
+
USING unnest($1::` + chainIdArrayType$1 + `,$2::` + "BYTEA" + `[],$3::` + "SMALLINT" + `[]) AS dead(chain_id, address, contract_id)
|
|
109
|
+
WHERE "` + table$1.tableName + `"."chain_id" = dead.chain_id
|
|
110
|
+
AND "` + table$1.tableName + `"."address" = dead.address
|
|
111
|
+
AND "` + table$1.tableName + `"."contract_id" = dead.contract_id;`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function $$delete(sql, pgSchema, keys, chainIdModeOpt) {
|
|
115
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
116
|
+
let chainIds = [];
|
|
117
|
+
let addresses = [];
|
|
118
|
+
let contractIds = [];
|
|
119
|
+
keys.forEach(key => {
|
|
120
|
+
chainIds.push(key.chainId);
|
|
121
|
+
addresses.push(key.address);
|
|
122
|
+
contractIds.push(key.contractId);
|
|
123
|
+
});
|
|
124
|
+
return sql.unsafe(makeDeleteQuery(pgSchema, chainIdMode), [
|
|
125
|
+
chainIds,
|
|
126
|
+
sql.typed(addresses, Postgres.byteaArrayOid),
|
|
127
|
+
contractIds
|
|
128
|
+
], {prepare: true});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function makeGetRowsQuery(pgSchema) {
|
|
132
|
+
return `SELECT "chain_id" as "chainId",
|
|
133
|
+
"address" as "address",
|
|
134
|
+
"contract_id" as "contractId",
|
|
135
|
+
"registration_block" as "registrationBlock"
|
|
136
|
+
FROM "` + pgSchema + `"."` + table$1.tableName + `";`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let EnvioAddresses = {
|
|
140
|
+
name: name,
|
|
141
|
+
table: table$1,
|
|
142
|
+
makeInsertQuery: makeInsertQuery$1,
|
|
143
|
+
insert: insert$1,
|
|
144
|
+
makeDeleteQuery: makeDeleteQuery,
|
|
145
|
+
$$delete: $$delete,
|
|
146
|
+
makeGetRowsQuery: makeGetRowsQuery
|
|
147
|
+
};
|
|
148
|
+
|
|
14
149
|
let fields = [
|
|
15
150
|
"id",
|
|
151
|
+
"ecosystem",
|
|
16
152
|
"start_block",
|
|
17
153
|
"end_block",
|
|
18
154
|
"max_reorg_depth",
|
|
@@ -25,8 +161,9 @@ let fields = [
|
|
|
25
161
|
"_is_hyper_sync"
|
|
26
162
|
];
|
|
27
163
|
|
|
28
|
-
let table = Table.mkTable("envio_chains", undefined, [
|
|
164
|
+
let table$2 = Table.mkTable("envio_chains", undefined, [
|
|
29
165
|
Table.mkField("id", "ChainId", ChainId.schema, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
166
|
+
Table.mkField("ecosystem", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
30
167
|
Table.mkField("start_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
31
168
|
Table.mkField("end_block", "Int32", S$RescriptSchema.$$null(S$RescriptSchema.int), undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
32
169
|
Table.mkField("max_reorg_depth", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
@@ -42,6 +179,7 @@ let table = Table.mkTable("envio_chains", undefined, [
|
|
|
42
179
|
function initialFromConfig(chainConfig) {
|
|
43
180
|
return {
|
|
44
181
|
id: chainConfig.id,
|
|
182
|
+
ecosystem: chainConfig.ecosystem,
|
|
45
183
|
start_block: chainConfig.startBlock,
|
|
46
184
|
end_block: Stdlib_Null.fromOption(chainConfig.endBlock),
|
|
47
185
|
max_reorg_depth: chainConfig.maxReorgDepth,
|
|
@@ -73,6 +211,8 @@ function makeInitialValuesQuery(pgSchema, chainConfigs) {
|
|
|
73
211
|
} else {
|
|
74
212
|
return "false";
|
|
75
213
|
}
|
|
214
|
+
} else if (match === "string") {
|
|
215
|
+
return `'` + value + `'`;
|
|
76
216
|
} else if (match === "object") {
|
|
77
217
|
return "NULL";
|
|
78
218
|
} else {
|
|
@@ -81,7 +221,7 @@ function makeInitialValuesQuery(pgSchema, chainConfigs) {
|
|
|
81
221
|
});
|
|
82
222
|
return `(` + values.join(", ") + `)`;
|
|
83
223
|
});
|
|
84
|
-
return `INSERT INTO "` + pgSchema + `"."` + table.tableName + `" (` + columnNames.join(", ") + `)
|
|
224
|
+
return `INSERT INTO "` + pgSchema + `"."` + table$2.tableName + `" (` + columnNames.join(", ") + `)
|
|
85
225
|
VALUES ` + valuesRows.join(",\n ") + `;`;
|
|
86
226
|
}
|
|
87
227
|
|
|
@@ -97,13 +237,13 @@ function makeMetaFieldsUpdateQuery(pgSchema) {
|
|
|
97
237
|
let paramIndex = index + 2 | 0;
|
|
98
238
|
return `"` + field + `" = $` + paramIndex.toString();
|
|
99
239
|
});
|
|
100
|
-
return `UPDATE "` + pgSchema + `"."` + table.tableName + `"
|
|
240
|
+
return `UPDATE "` + pgSchema + `"."` + table$2.tableName + `"
|
|
101
241
|
SET ` + setClauses.join(",\n ") + `
|
|
102
242
|
WHERE "` + "id" + `" = $1;`;
|
|
103
243
|
}
|
|
104
244
|
|
|
105
245
|
function makeSetReadyAtQuery(pgSchema) {
|
|
106
|
-
return `UPDATE "` + pgSchema + `"."` + table.tableName + `"
|
|
246
|
+
return `UPDATE "` + pgSchema + `"."` + table$2.tableName + `"
|
|
107
247
|
SET "` + "ready_at" + `" = $1
|
|
108
248
|
WHERE "` + "id" + `" = $2
|
|
109
249
|
AND "` + "ready_at" + `" IS NULL;`;
|
|
@@ -119,40 +259,15 @@ function makeGetInitialStateQuery(pgSchema) {
|
|
|
119
259
|
"` + "events_processed" + `"::float8 as "numEventsProcessed",
|
|
120
260
|
"` + "progress_block" + `" as "progressBlockNumber",
|
|
121
261
|
"` + "source_block" + `" as "sourceBlockNumber"
|
|
122
|
-
FROM "` + pgSchema + `"."` + table.tableName + `";`;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function makeGetIndexingAddressesQuery(pgSchema) {
|
|
126
|
-
return `SELECT "chain_id" as "chainId",
|
|
127
|
-
SUBSTRING("id" FROM POSITION('-' IN "id") + 1) as "address",
|
|
128
|
-
"contract_name" as "contractName",
|
|
129
|
-
"registration_block" as "registrationBlock"
|
|
130
|
-
FROM "` + pgSchema + `"."` + Config.EnvioAddresses.table.tableName + `";`;
|
|
262
|
+
FROM "` + pgSchema + `"."` + table$2.tableName + `";`;
|
|
131
263
|
}
|
|
132
264
|
|
|
133
265
|
async function getInitialState(sql, pgSchema) {
|
|
134
266
|
let match = await Promise.all([
|
|
135
267
|
sql.unsafe(makeGetInitialStateQuery(pgSchema)),
|
|
136
|
-
sql.unsafe(
|
|
268
|
+
sql.unsafe(makeGetRowsQuery(pgSchema))
|
|
137
269
|
]);
|
|
138
|
-
let
|
|
139
|
-
match[1].forEach(row => {
|
|
140
|
-
let key = ChainId.toString(ChainId.normalizeOrThrow(row.chainId));
|
|
141
|
-
let addresses = indexingAddressesByChainId[key];
|
|
142
|
-
let addresses$1;
|
|
143
|
-
if (addresses !== undefined) {
|
|
144
|
-
addresses$1 = addresses;
|
|
145
|
-
} else {
|
|
146
|
-
let addresses$2 = [];
|
|
147
|
-
indexingAddressesByChainId[key] = addresses$2;
|
|
148
|
-
addresses$1 = addresses$2;
|
|
149
|
-
}
|
|
150
|
-
addresses$1.push({
|
|
151
|
-
address: row.address,
|
|
152
|
-
contractName: row.contractName,
|
|
153
|
-
registrationBlock: row.registrationBlock
|
|
154
|
-
});
|
|
155
|
-
});
|
|
270
|
+
let addressRowsByChainId = AddressRows.group(match[1]);
|
|
156
271
|
return match[0].map(rawInitialState => {
|
|
157
272
|
let id = ChainId.normalizeOrThrow(rawInitialState.id);
|
|
158
273
|
return {
|
|
@@ -164,7 +279,7 @@ async function getInitialState(sql, pgSchema) {
|
|
|
164
279
|
timestampCaughtUpToHeadOrEndblock: rawInitialState.timestampCaughtUpToHeadOrEndblock,
|
|
165
280
|
numEventsProcessed: rawInitialState.numEventsProcessed,
|
|
166
281
|
progressBlockNumber: rawInitialState.progressBlockNumber,
|
|
167
|
-
|
|
282
|
+
addressRows: Stdlib_Option.getOr(addressRowsByChainId[ChainId.toString(id)], AddressRows.emptySeedRows()),
|
|
168
283
|
sourceBlockNumber: rawInitialState.sourceBlockNumber
|
|
169
284
|
};
|
|
170
285
|
});
|
|
@@ -181,7 +296,7 @@ function makeProgressFieldsUpdateQuery(pgSchema) {
|
|
|
181
296
|
let paramIndex = index + 2 | 0;
|
|
182
297
|
return `"` + field + `" = $` + paramIndex.toString();
|
|
183
298
|
});
|
|
184
|
-
return `UPDATE "` + pgSchema + `"."` + table.tableName + `"
|
|
299
|
+
return `UPDATE "` + pgSchema + `"."` + table$2.tableName + `"
|
|
185
300
|
SET ` + setClauses.join(",\n ") + `
|
|
186
301
|
WHERE "id" = $1;`;
|
|
187
302
|
}
|
|
@@ -219,14 +334,13 @@ function setProgressedChains(sql, pgSchema, progressedChains) {
|
|
|
219
334
|
|
|
220
335
|
let Chains = {
|
|
221
336
|
fields: fields,
|
|
222
|
-
table: table,
|
|
337
|
+
table: table$2,
|
|
223
338
|
initialFromConfig: initialFromConfig,
|
|
224
339
|
makeInitialValuesQuery: makeInitialValuesQuery,
|
|
225
340
|
metaFields: metaFields,
|
|
226
341
|
makeMetaFieldsUpdateQuery: makeMetaFieldsUpdateQuery,
|
|
227
342
|
makeSetReadyAtQuery: makeSetReadyAtQuery,
|
|
228
343
|
makeGetInitialStateQuery: makeGetInitialStateQuery,
|
|
229
|
-
makeGetIndexingAddressesQuery: makeGetIndexingAddressesQuery,
|
|
230
344
|
getInitialState: getInitialState,
|
|
231
345
|
progressFields: progressFields,
|
|
232
346
|
makeProgressFieldsUpdateQuery: makeProgressFieldsUpdateQuery,
|
|
@@ -234,26 +348,19 @@ let Chains = {
|
|
|
234
348
|
setProgressedChains: setProgressedChains
|
|
235
349
|
};
|
|
236
350
|
|
|
237
|
-
let table$
|
|
351
|
+
let table$3 = Table.mkTable("envio_info", undefined, [
|
|
238
352
|
Table.mkField("id", "Int32", S$RescriptSchema.int, "1", undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
239
353
|
Table.mkField("config", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
240
354
|
], undefined);
|
|
241
355
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
async function read(sql, pgSchema) {
|
|
356
|
+
async function read$1(sql, pgSchema) {
|
|
245
357
|
let rows;
|
|
246
358
|
try {
|
|
247
|
-
rows = await sql.unsafe(`SELECT "config" FROM "` + pgSchema + `"."` + table$
|
|
359
|
+
rows = await sql.unsafe(`SELECT "config" FROM "` + pgSchema + `"."` + table$3.tableName + `" LIMIT 1;`);
|
|
248
360
|
} catch (raw_exn) {
|
|
249
361
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (e._1.code === undefinedTableSqlState) {
|
|
253
|
-
rows = [];
|
|
254
|
-
} else {
|
|
255
|
-
throw exn;
|
|
256
|
-
}
|
|
362
|
+
if (isUndefinedTable(exn)) {
|
|
363
|
+
rows = [];
|
|
257
364
|
} else {
|
|
258
365
|
throw exn;
|
|
259
366
|
}
|
|
@@ -262,13 +369,12 @@ async function read(sql, pgSchema) {
|
|
|
262
369
|
}
|
|
263
370
|
|
|
264
371
|
function write(sql, pgSchema, envioInfo) {
|
|
265
|
-
return sql.unsafe(`INSERT INTO "` + pgSchema + `"."` + table$
|
|
372
|
+
return sql.unsafe(`INSERT INTO "` + pgSchema + `"."` + table$3.tableName + `" ("id", "config") VALUES (1, $1) ON CONFLICT ("id") DO UPDATE SET "config" = EXCLUDED."config";`, [JSON.stringify(envioInfo)], {prepare: true});
|
|
266
373
|
}
|
|
267
374
|
|
|
268
375
|
let EnvioInfo = {
|
|
269
|
-
table: table$
|
|
270
|
-
|
|
271
|
-
read: read,
|
|
376
|
+
table: table$3,
|
|
377
|
+
read: read$1,
|
|
272
378
|
write: write
|
|
273
379
|
};
|
|
274
380
|
|
|
@@ -283,7 +389,7 @@ let dbSchema = S$RescriptSchema.object(s => ({
|
|
|
283
389
|
events_processed: s.f("events_processed", S$RescriptSchema.int)
|
|
284
390
|
}));
|
|
285
391
|
|
|
286
|
-
let table$
|
|
392
|
+
let table$4 = Table.mkTable("envio_checkpoints", undefined, [
|
|
287
393
|
Table.mkField("id", "UInt64", S$RescriptSchema.bigint, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
288
394
|
Table.mkField("chain_id", "ChainId", ChainId.schema, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
289
395
|
Table.mkField("block_number", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
@@ -296,7 +402,7 @@ function makeGetReorgCheckpointsQuery(pgSchema) {
|
|
|
296
402
|
SELECT
|
|
297
403
|
"` + "id" + `" as id,
|
|
298
404
|
"` + "source_block" + `" - "` + "max_reorg_depth" + `" AS safe_block
|
|
299
|
-
FROM "` + pgSchema + `"."` + table.tableName + `"
|
|
405
|
+
FROM "` + pgSchema + `"."` + table$2.tableName + `"
|
|
300
406
|
WHERE "` + "max_reorg_depth" + `" > 0
|
|
301
407
|
AND "` + "progress_block" + `" > "` + "source_block" + `" - "` + "max_reorg_depth" + `"
|
|
302
408
|
)
|
|
@@ -305,7 +411,7 @@ SELECT
|
|
|
305
411
|
cp."` + "chain_id" + `",
|
|
306
412
|
cp."` + "block_number" + `",
|
|
307
413
|
cp."` + "block_hash" + `"
|
|
308
|
-
FROM "` + pgSchema + `"."` + table$
|
|
414
|
+
FROM "` + pgSchema + `"."` + table$4.tableName + `" cp
|
|
309
415
|
INNER JOIN reorg_chains rc
|
|
310
416
|
ON cp."` + "chain_id" + `" = rc.id
|
|
311
417
|
WHERE cp."` + "block_hash" + `" IS NOT NULL
|
|
@@ -313,17 +419,17 @@ WHERE cp."` + "block_hash" + `" IS NOT NULL
|
|
|
313
419
|
}
|
|
314
420
|
|
|
315
421
|
function makeCommitedCheckpointIdQuery(pgSchema) {
|
|
316
|
-
return `SELECT COALESCE(MAX(` + "id" + `), ` + (0n).toString() + `) AS id FROM "` + pgSchema + `"."` + table$
|
|
422
|
+
return `SELECT COALESCE(MAX(` + "id" + `), ` + (0n).toString() + `) AS id FROM "` + pgSchema + `"."` + table$4.tableName + `";`;
|
|
317
423
|
}
|
|
318
424
|
|
|
319
425
|
function makeInsertCheckpointQuery(pgSchema, chainIdModeOpt) {
|
|
320
426
|
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
321
|
-
let chainIdArrayType =
|
|
322
|
-
return `INSERT INTO "` + pgSchema + `"."` + table$
|
|
323
|
-
SELECT * FROM unnest($1::` + "BIGINT" + `[],$2::` + chainIdArrayType + `,$3::` + "INTEGER" + `[],$4::` + "TEXT" + `[],$5::` + "INTEGER" + `[]);`;
|
|
427
|
+
let chainIdArrayType$1 = chainIdArrayType(pgSchema, chainIdMode);
|
|
428
|
+
return `INSERT INTO "` + pgSchema + `"."` + table$4.tableName + `" ("` + "id" + `", "` + "chain_id" + `", "` + "block_number" + `", "` + "block_hash" + `", "` + "events_processed" + `")
|
|
429
|
+
SELECT * FROM unnest($1::` + "BIGINT" + `[],$2::` + chainIdArrayType$1 + `,$3::` + "INTEGER" + `[],$4::` + "TEXT" + `[],$5::` + "INTEGER" + `[]);`;
|
|
324
430
|
}
|
|
325
431
|
|
|
326
|
-
function insert(sql, pgSchema, checkpointIds, checkpointChainIds, checkpointBlockNumbers, checkpointBlockHashes, checkpointEventsProcessed, chainIdModeOpt) {
|
|
432
|
+
function insert$2(sql, pgSchema, checkpointIds, checkpointChainIds, checkpointBlockNumbers, checkpointBlockHashes, checkpointEventsProcessed, chainIdModeOpt) {
|
|
327
433
|
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
328
434
|
let query = makeInsertCheckpointQuery(pgSchema, chainIdMode);
|
|
329
435
|
let checkpointIdStrings = Utils.$$BigInt.arrayToStringArray(checkpointIds);
|
|
@@ -337,11 +443,11 @@ function insert(sql, pgSchema, checkpointIds, checkpointChainIds, checkpointBloc
|
|
|
337
443
|
}
|
|
338
444
|
|
|
339
445
|
function rollback(sql, pgSchema, rollbackTargetCheckpointId) {
|
|
340
|
-
return sql.unsafe(`DELETE FROM "` + pgSchema + `"."` + table$
|
|
446
|
+
return sql.unsafe(`DELETE FROM "` + pgSchema + `"."` + table$4.tableName + `" WHERE "` + "id" + `" > $1;`, [rollbackTargetCheckpointId.toString()], {prepare: true});
|
|
341
447
|
}
|
|
342
448
|
|
|
343
449
|
function makePruneStaleCheckpointsQuery(pgSchema) {
|
|
344
|
-
return `DELETE FROM "` + pgSchema + `"."` + table$
|
|
450
|
+
return `DELETE FROM "` + pgSchema + `"."` + table$4.tableName + `" WHERE "` + "id" + `" < $1;`;
|
|
345
451
|
}
|
|
346
452
|
|
|
347
453
|
function pruneStaleCheckpoints(sql, pgSchema, safeCheckpointId) {
|
|
@@ -349,7 +455,7 @@ function pruneStaleCheckpoints(sql, pgSchema, safeCheckpointId) {
|
|
|
349
455
|
}
|
|
350
456
|
|
|
351
457
|
function makeGetRollbackTargetCheckpointQuery(pgSchema) {
|
|
352
|
-
return `SELECT "` + "id" + `" FROM "` + pgSchema + `"."` + table$
|
|
458
|
+
return `SELECT "` + "id" + `" FROM "` + pgSchema + `"."` + table$4.tableName + `"
|
|
353
459
|
WHERE
|
|
354
460
|
"` + "chain_id" + `" = $1 AND
|
|
355
461
|
"` + "block_number" + `" <= $2
|
|
@@ -370,7 +476,7 @@ function makeGetRollbackProgressDiffQuery(pgSchema) {
|
|
|
370
476
|
"` + "chain_id" + `"::float8 as "` + "chain_id" + `",
|
|
371
477
|
SUM("` + "events_processed" + `") as events_processed_diff,
|
|
372
478
|
MIN("` + "block_number" + `") - 1 as new_progress_block_number
|
|
373
|
-
FROM "` + pgSchema + `"."` + table$
|
|
479
|
+
FROM "` + pgSchema + `"."` + table$4.tableName + `"
|
|
374
480
|
WHERE "` + "id" + `" > $1
|
|
375
481
|
GROUP BY "` + "chain_id" + `";`;
|
|
376
482
|
}
|
|
@@ -382,11 +488,11 @@ function getRollbackProgressDiff(sql, pgSchema, rollbackTargetCheckpointId) {
|
|
|
382
488
|
let Checkpoints = {
|
|
383
489
|
dbSchema: dbSchema,
|
|
384
490
|
initialCheckpointId: 0n,
|
|
385
|
-
table: table$
|
|
491
|
+
table: table$4,
|
|
386
492
|
makeGetReorgCheckpointsQuery: makeGetReorgCheckpointsQuery,
|
|
387
493
|
makeCommitedCheckpointIdQuery: makeCommitedCheckpointIdQuery,
|
|
388
494
|
makeInsertCheckpointQuery: makeInsertCheckpointQuery,
|
|
389
|
-
insert: insert,
|
|
495
|
+
insert: insert$2,
|
|
390
496
|
rollback: rollback,
|
|
391
497
|
makePruneStaleCheckpointsQuery: makePruneStaleCheckpointsQuery,
|
|
392
498
|
pruneStaleCheckpoints: pruneStaleCheckpoints,
|
|
@@ -411,7 +517,7 @@ let schema = S$RescriptSchema.schema(s => ({
|
|
|
411
517
|
params: s.m(S$RescriptSchema.json(false))
|
|
412
518
|
}));
|
|
413
519
|
|
|
414
|
-
let table$
|
|
520
|
+
let table$5 = Table.mkTable("raw_events", undefined, [
|
|
415
521
|
Table.mkField("chain_id", "ChainId", ChainId.schema, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
416
522
|
Table.mkField("event_id", "UInt64", S$RescriptSchema.bigint, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
417
523
|
Table.mkField("event_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
@@ -429,7 +535,7 @@ let table$3 = Table.mkTable("raw_events", undefined, [
|
|
|
429
535
|
|
|
430
536
|
let RawEvents = {
|
|
431
537
|
schema: schema,
|
|
432
|
-
table: table$
|
|
538
|
+
table: table$5
|
|
433
539
|
};
|
|
434
540
|
|
|
435
541
|
let metaViewName = "_meta";
|
|
@@ -440,6 +546,7 @@ function makeMetaViewQuery(pgSchema) {
|
|
|
440
546
|
return `CREATE VIEW "` + pgSchema + `"."` + metaViewName + `" AS
|
|
441
547
|
SELECT
|
|
442
548
|
"` + "id" + `" AS "chainId",
|
|
549
|
+
"` + "ecosystem" + `" AS "ecosystem",
|
|
443
550
|
"` + "start_block" + `" AS "startBlock",
|
|
444
551
|
"` + "end_block" + `" AS "endBlock",
|
|
445
552
|
"` + "progress_block" + `" AS "progressBlock",
|
|
@@ -449,7 +556,7 @@ SELECT
|
|
|
449
556
|
"` + "source_block" + `" AS "sourceBlock",
|
|
450
557
|
"` + "ready_at" + `" AS "readyAt",
|
|
451
558
|
("` + "ready_at" + `" IS NOT NULL) AS "isReady"
|
|
452
|
-
FROM "` + pgSchema + `"."` + table.tableName + `"
|
|
559
|
+
FROM "` + pgSchema + `"."` + table$2.tableName + `"
|
|
453
560
|
ORDER BY "` + "id" + `";`;
|
|
454
561
|
}
|
|
455
562
|
|
|
@@ -458,6 +565,7 @@ function makeChainMetadataViewQuery(pgSchema) {
|
|
|
458
565
|
SELECT
|
|
459
566
|
"` + "source_block" + `" AS "block_height",
|
|
460
567
|
"` + "id" + `" AS "chain_id",
|
|
568
|
+
"` + "ecosystem" + `" AS "ecosystem",
|
|
461
569
|
"` + "end_block" + `" AS "end_block",
|
|
462
570
|
"` + "first_event_block" + `" AS "first_event_block_number",
|
|
463
571
|
"` + "_is_hyper_sync" + `" AS "is_hyper_sync",
|
|
@@ -467,7 +575,7 @@ SELECT
|
|
|
467
575
|
"` + "events_processed" + `"::float4 AS "num_events_processed",
|
|
468
576
|
"` + "start_block" + `" AS "start_block",
|
|
469
577
|
"` + "ready_at" + `" AS "timestamp_caught_up_to_head_or_endblock"
|
|
470
|
-
FROM "` + pgSchema + `"."` + table.tableName + `";`;
|
|
578
|
+
FROM "` + pgSchema + `"."` + table$2.tableName + `";`;
|
|
471
579
|
}
|
|
472
580
|
|
|
473
581
|
let Views = {
|
|
@@ -483,12 +591,14 @@ let isNullable = true;
|
|
|
483
591
|
|
|
484
592
|
let isIndex = true;
|
|
485
593
|
|
|
486
|
-
let EnvioAddresses;
|
|
487
|
-
|
|
488
594
|
export {
|
|
489
595
|
isPrimaryKey,
|
|
490
596
|
isNullable,
|
|
491
597
|
isIndex,
|
|
598
|
+
undefinedTableSqlState,
|
|
599
|
+
isUndefinedTable,
|
|
600
|
+
chainIdArrayType,
|
|
601
|
+
EnvioContracts,
|
|
492
602
|
EnvioAddresses,
|
|
493
603
|
Chains,
|
|
494
604
|
EnvioInfo,
|
package/src/db/Table.res
CHANGED
|
@@ -21,6 +21,10 @@ type fieldType =
|
|
|
21
21
|
| Boolean
|
|
22
22
|
| Uint32
|
|
23
23
|
| UInt52
|
|
24
|
+
| SmallInt
|
|
25
|
+
// Raw bytes. Only the internal tables use it — the one column that stores an
|
|
26
|
+
// address in the binary form the Rust address store keys on.
|
|
27
|
+
| Bytea
|
|
24
28
|
| UInt64
|
|
25
29
|
| Int32
|
|
26
30
|
// Resolved to Int32 or UInt64 storage from the config's `ChainId.mode`, so
|
|
@@ -141,6 +145,20 @@ let getPgFieldName = fieldOrDerived =>
|
|
|
141
145
|
|
|
142
146
|
let idFieldName = "id"
|
|
143
147
|
|
|
148
|
+
let maxPgTableNameLength = 63
|
|
149
|
+
|
|
150
|
+
// Postgres truncates identifiers past its limit on its own, which would collapse
|
|
151
|
+
// two long names onto one. Cutting the readable half and keeping `uniqueSuffix`
|
|
152
|
+
// whole makes every generated name distinct by construction, so the suffix has
|
|
153
|
+
// to be something already unique to the table it names.
|
|
154
|
+
let fitPgTableName = (fullName, ~uniqueSuffix) =>
|
|
155
|
+
if fullName->String.length > maxPgTableNameLength {
|
|
156
|
+
fullName->String.slice(~start=0, ~end=maxPgTableNameLength - uniqueSuffix->String.length) ++
|
|
157
|
+
uniqueSuffix
|
|
158
|
+
} else {
|
|
159
|
+
fullName
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
let getPgFieldType = (
|
|
145
163
|
~fieldType: fieldType,
|
|
146
164
|
~pgSchema,
|
|
@@ -160,6 +178,8 @@ let getPgFieldType = (
|
|
|
160
178
|
}
|
|
161
179
|
| Uint32 => (Postgres.BigInt :> string)
|
|
162
180
|
| UInt52 => (Postgres.BigInt :> string)
|
|
181
|
+
| SmallInt => (Postgres.SmallInt :> string)
|
|
182
|
+
| Bytea => (Postgres.Bytea :> string)
|
|
163
183
|
| UInt64 => (Postgres.BigInt :> string)
|
|
164
184
|
| Number => (Postgres.DoublePrecision :> string)
|
|
165
185
|
| BigInt({?precision}) =>
|
|
@@ -327,6 +347,9 @@ type queryField = {
|
|
|
327
347
|
// Loads are served by Postgres only (ClickHouse is a write-only sink), so
|
|
328
348
|
// no ClickHouse counterpart is needed here.
|
|
329
349
|
pgDbFieldName: string,
|
|
350
|
+
// The chain-id column a per-chain entity's table is partitioned by, which a
|
|
351
|
+
// filter has to write into the SQL rather than bind. See `makeFilterCondition`.
|
|
352
|
+
isChainId: bool,
|
|
330
353
|
}
|
|
331
354
|
let queryFields: table => dict<queryField> = Utils.WeakMap.memoize(table => {
|
|
332
355
|
let dict = Dict.make()
|
|
@@ -339,6 +362,7 @@ let queryFields: table => dict<queryField> = Utils.WeakMap.memoize(table => {
|
|
|
339
362
|
fieldSchema: field.fieldSchema,
|
|
340
363
|
arrayFieldSchema: S.array(field.fieldSchema)->S.toUnknown,
|
|
341
364
|
pgDbFieldName: field->getPgDbFieldName,
|
|
365
|
+
isChainId: field.isChainId,
|
|
342
366
|
},
|
|
343
367
|
)
|
|
344
368
|
| DerivedFrom(_) => ()
|
package/src/db/Table.res.mjs
CHANGED
|
@@ -98,6 +98,14 @@ function getPgFieldName(fieldOrDerived) {
|
|
|
98
98
|
|
|
99
99
|
let idFieldName = "id";
|
|
100
100
|
|
|
101
|
+
function fitPgTableName(fullName, uniqueSuffix) {
|
|
102
|
+
if (fullName.length > 63) {
|
|
103
|
+
return fullName.slice(0, 63 - uniqueSuffix.length | 0) + uniqueSuffix;
|
|
104
|
+
} else {
|
|
105
|
+
return fullName;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
101
109
|
function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNullable, chainIdModeOpt) {
|
|
102
110
|
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
103
111
|
let columnType;
|
|
@@ -109,6 +117,12 @@ function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNu
|
|
|
109
117
|
case "Boolean" :
|
|
110
118
|
columnType = "BOOLEAN";
|
|
111
119
|
break;
|
|
120
|
+
case "SmallInt" :
|
|
121
|
+
columnType = "SMALLINT";
|
|
122
|
+
break;
|
|
123
|
+
case "Bytea" :
|
|
124
|
+
columnType = "BYTEA";
|
|
125
|
+
break;
|
|
112
126
|
case "Int32" :
|
|
113
127
|
columnType = "INTEGER";
|
|
114
128
|
break;
|
|
@@ -296,7 +310,8 @@ let queryFields = Utils.$$WeakMap.memoize(table => {
|
|
|
296
310
|
dict[getApiFieldName(field$1)] = {
|
|
297
311
|
fieldSchema: field$1.fieldSchema,
|
|
298
312
|
arrayFieldSchema: S$RescriptSchema.array(field$1.fieldSchema),
|
|
299
|
-
pgDbFieldName: getPgDbFieldName(field$1)
|
|
313
|
+
pgDbFieldName: getPgDbFieldName(field$1),
|
|
314
|
+
isChainId: field$1.isChainId
|
|
300
315
|
};
|
|
301
316
|
});
|
|
302
317
|
return dict;
|
|
@@ -467,6 +482,8 @@ function getCompositeIndexes(table) {
|
|
|
467
482
|
return getUnfilteredCompositeIndexesUnsafe(table).filter(ind => ind.length > 1);
|
|
468
483
|
}
|
|
469
484
|
|
|
485
|
+
let maxPgTableNameLength = 63;
|
|
486
|
+
|
|
470
487
|
export {
|
|
471
488
|
makeEnumConfig,
|
|
472
489
|
mkField,
|
|
@@ -478,6 +495,8 @@ export {
|
|
|
478
495
|
getClickHouseDbFieldName,
|
|
479
496
|
getPgFieldName,
|
|
480
497
|
idFieldName,
|
|
498
|
+
maxPgTableNameLength,
|
|
499
|
+
fitPgTableName,
|
|
481
500
|
getPgFieldType,
|
|
482
501
|
mkTable,
|
|
483
502
|
getPgPrimaryKeyFieldNames,
|
|
@@ -1,47 +1,25 @@
|
|
|
1
|
-
// Binding to the Rust `AddressSet` napi class: an immutable, ordered snapshot
|
|
2
|
-
// of some of a chain's indexed addresses, handed to a fetch-state partition
|
|
3
|
-
// instead of a JS address array. Sets are ordered by
|
|
4
|
-
// `(effectiveStartBlock, address)`, so the same addresses always produce the
|
|
5
|
-
// same set however they were registered or restored. Everything a query derives
|
|
6
|
-
// from one (padded topics, the routing owner index, per-contract counts) is
|
|
7
|
-
// built once inside Rust and shared by every query the partition makes.
|
|
8
1
|
type t
|
|
9
2
|
|
|
10
3
|
type startBlockGroup = {startBlock: int, count: int}
|
|
11
4
|
|
|
12
5
|
@send external size: t => int = "size"
|
|
13
6
|
|
|
14
|
-
// Live addresses of one contract, derived once per set inside Rust — so the
|
|
15
|
-
// fetch state can size and split partitions without ever walking the addresses.
|
|
16
7
|
@send external countFor: (t, string) => int = "countFor"
|
|
17
8
|
|
|
18
|
-
// This set holds the address under the contract and it has already started at
|
|
19
|
-
// the block — the gate a real source's router applies to a server-side
|
|
20
|
-
// address-filtered query. The temporal half still comes from the store: a
|
|
21
|
-
// merged partition's addresses don't all start at the same block.
|
|
22
9
|
@send external containsAt: (t, Address.t, string, int) => bool = "containsAt"
|
|
23
10
|
|
|
24
11
|
@send external contractNames: t => array<string> = "contractNames"
|
|
25
12
|
|
|
26
|
-
// Distinct effective start blocks in this set, ascending — how partition
|
|
27
|
-
// creation decides where one partition ends and the next begins.
|
|
28
13
|
@send external startBlockGroups: t => array<startBlockGroup> = "startBlockGroups"
|
|
29
14
|
|
|
30
15
|
@send external slice: (t, ~offset: int, ~limit: option<int>) => t = "slice"
|
|
31
16
|
|
|
32
|
-
// Keeps only the named contracts' addresses, in set order.
|
|
33
17
|
@send external filterByContracts: (t, array<string>) => t = "filterByContracts"
|
|
34
18
|
|
|
35
|
-
// Drops addresses registered after the target block, and any the store has
|
|
36
|
-
// tombstoned since this set was built.
|
|
37
19
|
@send external filterByRegistrationBlock: (t, int) => t = "filterByRegistrationBlock"
|
|
38
20
|
|
|
39
|
-
// Union with another set of the same store, keeping set order; duplicates
|
|
40
|
-
// collapse.
|
|
41
21
|
@send external merge: (t, t) => t = "merge"
|
|
42
22
|
|
|
43
|
-
// Canonical address strings in set order. Not on a query path — queries read
|
|
44
|
-
// the set's cached slices inside Rust.
|
|
45
23
|
@send external addresses: t => array<Address.t> = "addresses"
|
|
46
24
|
|
|
47
25
|
@send external entries: t => array<Internal.indexingContract> = "entries"
|