envio 2.30.2 → 2.31.0-alpha.1
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/package.json +5 -5
- package/src/Batch.res +400 -28
- package/src/Batch.res.js +286 -24
- package/src/EventRegister.res +9 -3
- package/src/EventRegister.res.js +6 -3
- package/src/EventRegister.resi +4 -1
- package/src/FetchState.res +116 -155
- package/src/FetchState.res.js +116 -106
- package/src/Internal.res +49 -0
- package/src/InternalConfig.res +1 -1
- package/src/Persistence.res +16 -1
- package/src/Persistence.res.js +1 -1
- package/src/PgStorage.res +51 -63
- package/src/PgStorage.res.js +45 -38
- package/src/Prometheus.res +7 -1
- package/src/Prometheus.res.js +8 -1
- package/src/ReorgDetection.res +222 -235
- package/src/ReorgDetection.res.js +34 -28
- package/src/SafeCheckpointTracking.res +132 -0
- package/src/SafeCheckpointTracking.res.js +95 -0
- package/src/Utils.res +64 -21
- package/src/Utils.res.js +61 -30
- package/src/db/EntityHistory.res +172 -294
- package/src/db/EntityHistory.res.js +98 -218
- package/src/db/InternalTable.gen.ts +13 -13
- package/src/db/InternalTable.res +286 -77
- package/src/db/InternalTable.res.js +160 -79
- package/src/db/Table.res +1 -0
- package/src/db/Table.res.js +1 -1
- package/src/sources/EventRouter.res +1 -1
- package/src/sources/RpcSource.res +6 -13
- package/src/sources/RpcSource.res.js +5 -19
- package/src/sources/Source.res +1 -1
package/src/db/InternalTable.res
CHANGED
|
@@ -5,6 +5,72 @@ let isPrimaryKey = true
|
|
|
5
5
|
let isNullable = true
|
|
6
6
|
let isIndex = true
|
|
7
7
|
|
|
8
|
+
module DynamicContractRegistry = {
|
|
9
|
+
let name = "dynamic_contract_registry"
|
|
10
|
+
|
|
11
|
+
let makeId = (~chainId, ~contractAddress) => {
|
|
12
|
+
chainId->Belt.Int.toString ++ "-" ++ contractAddress->Address.toString
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// @genType Used for Test DB
|
|
16
|
+
@genType
|
|
17
|
+
type t = {
|
|
18
|
+
id: string,
|
|
19
|
+
@as("chain_id") chainId: int,
|
|
20
|
+
@as("registering_event_block_number") registeringEventBlockNumber: int,
|
|
21
|
+
@as("registering_event_log_index") registeringEventLogIndex: int,
|
|
22
|
+
@as("registering_event_block_timestamp") registeringEventBlockTimestamp: int,
|
|
23
|
+
@as("registering_event_contract_name") registeringEventContractName: string,
|
|
24
|
+
@as("registering_event_name") registeringEventName: string,
|
|
25
|
+
@as("registering_event_src_address") registeringEventSrcAddress: Address.t,
|
|
26
|
+
@as("contract_address") contractAddress: Address.t,
|
|
27
|
+
@as("contract_name") contractName: string,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let schema = S.schema(s => {
|
|
31
|
+
id: s.matches(S.string),
|
|
32
|
+
chainId: s.matches(S.int),
|
|
33
|
+
registeringEventBlockNumber: s.matches(S.int),
|
|
34
|
+
registeringEventLogIndex: s.matches(S.int),
|
|
35
|
+
registeringEventContractName: s.matches(S.string),
|
|
36
|
+
registeringEventName: s.matches(S.string),
|
|
37
|
+
registeringEventSrcAddress: s.matches(Address.schema),
|
|
38
|
+
registeringEventBlockTimestamp: s.matches(S.int),
|
|
39
|
+
contractAddress: s.matches(Address.schema),
|
|
40
|
+
contractName: s.matches(S.string),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
let rowsSchema = S.array(schema)
|
|
44
|
+
|
|
45
|
+
let table = mkTable(
|
|
46
|
+
name,
|
|
47
|
+
~fields=[
|
|
48
|
+
mkField("id", Text, ~isPrimaryKey, ~fieldSchema=S.string),
|
|
49
|
+
mkField("chain_id", Integer, ~fieldSchema=S.int),
|
|
50
|
+
mkField("registering_event_block_number", Integer, ~fieldSchema=S.int),
|
|
51
|
+
mkField("registering_event_log_index", Integer, ~fieldSchema=S.int),
|
|
52
|
+
mkField("registering_event_block_timestamp", Integer, ~fieldSchema=S.int),
|
|
53
|
+
mkField("registering_event_contract_name", Text, ~fieldSchema=S.string),
|
|
54
|
+
mkField("registering_event_name", Text, ~fieldSchema=S.string),
|
|
55
|
+
mkField("registering_event_src_address", Text, ~fieldSchema=Address.schema),
|
|
56
|
+
mkField("contract_address", Text, ~fieldSchema=Address.schema),
|
|
57
|
+
mkField("contract_name", Text, ~fieldSchema=S.string),
|
|
58
|
+
],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
let entityHistory = table->EntityHistory.fromTable(~schema)
|
|
62
|
+
|
|
63
|
+
external castToInternal: t => Internal.entity = "%identity"
|
|
64
|
+
|
|
65
|
+
let config = {
|
|
66
|
+
name,
|
|
67
|
+
schema,
|
|
68
|
+
rowsSchema,
|
|
69
|
+
table,
|
|
70
|
+
entityHistory,
|
|
71
|
+
}->Internal.fromGenericEntityConfig
|
|
72
|
+
}
|
|
73
|
+
|
|
8
74
|
module Chains = {
|
|
9
75
|
type progressFields = [
|
|
10
76
|
| #progress_block
|
|
@@ -16,6 +82,7 @@ module Chains = {
|
|
|
16
82
|
| #id
|
|
17
83
|
| #start_block
|
|
18
84
|
| #end_block
|
|
85
|
+
| #max_reorg_depth
|
|
19
86
|
| #source_block
|
|
20
87
|
| #first_event_block
|
|
21
88
|
| #buffer_block
|
|
@@ -28,6 +95,7 @@ module Chains = {
|
|
|
28
95
|
#id,
|
|
29
96
|
#start_block,
|
|
30
97
|
#end_block,
|
|
98
|
+
#max_reorg_depth,
|
|
31
99
|
#source_block,
|
|
32
100
|
#first_event_block,
|
|
33
101
|
#buffer_block,
|
|
@@ -52,6 +120,7 @@ module Chains = {
|
|
|
52
120
|
@as("id") id: int,
|
|
53
121
|
@as("start_block") startBlock: int,
|
|
54
122
|
@as("end_block") endBlock: Js.null<int>,
|
|
123
|
+
@as("max_reorg_depth") maxReorgDepth: int,
|
|
55
124
|
@as("progress_block") progressBlockNumber: int,
|
|
56
125
|
@as("events_processed") numEventsProcessed: int,
|
|
57
126
|
...metaFields,
|
|
@@ -64,6 +133,7 @@ module Chains = {
|
|
|
64
133
|
// Values populated from config
|
|
65
134
|
mkField((#start_block: field :> string), Integer, ~fieldSchema=S.int),
|
|
66
135
|
mkField((#end_block: field :> string), Integer, ~fieldSchema=S.null(S.int), ~isNullable),
|
|
136
|
+
mkField((#max_reorg_depth: field :> string), Integer, ~fieldSchema=S.int),
|
|
67
137
|
// Block number of the latest block that was fetched from the source
|
|
68
138
|
mkField((#buffer_block: field :> string), Integer, ~fieldSchema=S.int),
|
|
69
139
|
// Block number of the currently active source
|
|
@@ -98,6 +168,7 @@ module Chains = {
|
|
|
98
168
|
id: chainConfig.id,
|
|
99
169
|
startBlock: chainConfig.startBlock,
|
|
100
170
|
endBlock: chainConfig.endBlock->Js.Null.fromOption,
|
|
171
|
+
maxReorgDepth: chainConfig.maxReorgDepth,
|
|
101
172
|
blockHeight: 0,
|
|
102
173
|
firstEventBlockNumber: Js.Null.empty,
|
|
103
174
|
latestFetchedBlockNumber: -1,
|
|
@@ -160,7 +231,51 @@ VALUES ${valuesRows->Js.Array2.joinWith(",\n ")};`,
|
|
|
160
231
|
|
|
161
232
|
`UPDATE "${pgSchema}"."${table.tableName}"
|
|
162
233
|
SET ${setClauses->Js.Array2.joinWith(",\n ")}
|
|
163
|
-
WHERE "id" = $1;`
|
|
234
|
+
WHERE "${(#id: field :> string)}" = $1;`
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
type rawInitialState = {
|
|
238
|
+
id: int,
|
|
239
|
+
startBlock: int,
|
|
240
|
+
endBlock: Js.Null.t<int>,
|
|
241
|
+
maxReorgDepth: int,
|
|
242
|
+
firstEventBlockNumber: Js.Null.t<int>,
|
|
243
|
+
timestampCaughtUpToHeadOrEndblock: Js.Null.t<Js.Date.t>,
|
|
244
|
+
numEventsProcessed: int,
|
|
245
|
+
progressBlockNumber: int,
|
|
246
|
+
dynamicContracts: array<Internal.indexingContract>,
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// FIXME: Using registering_event_block_number for startBlock
|
|
250
|
+
// seems incorrect, since there might be a custom start block
|
|
251
|
+
// for the contract.
|
|
252
|
+
// TODO: Write a repro test where it might break something and fix
|
|
253
|
+
let makeGetInitialStateQuery = (~pgSchema) => {
|
|
254
|
+
`SELECT "${(#id: field :> string)}" as "id",
|
|
255
|
+
"${(#start_block: field :> string)}" as "startBlock",
|
|
256
|
+
"${(#end_block: field :> string)}" as "endBlock",
|
|
257
|
+
"${(#max_reorg_depth: field :> string)}" as "maxReorgDepth",
|
|
258
|
+
"${(#first_event_block: field :> string)}" as "firstEventBlockNumber",
|
|
259
|
+
"${(#ready_at: field :> string)}" as "timestampCaughtUpToHeadOrEndblock",
|
|
260
|
+
"${(#events_processed: field :> string)}" as "numEventsProcessed",
|
|
261
|
+
"${(#progress_block: field :> string)}" as "progressBlockNumber",
|
|
262
|
+
(
|
|
263
|
+
SELECT COALESCE(json_agg(json_build_object(
|
|
264
|
+
'address', "contract_address",
|
|
265
|
+
'contractName', "contract_name",
|
|
266
|
+
'startBlock', "registering_event_block_number",
|
|
267
|
+
'registrationBlock', "registering_event_block_number"
|
|
268
|
+
)), '[]'::json)
|
|
269
|
+
FROM "${pgSchema}"."${DynamicContractRegistry.table.tableName}"
|
|
270
|
+
WHERE "chain_id" = chains."${(#id: field :> string)}"
|
|
271
|
+
) as "dynamicContracts"
|
|
272
|
+
FROM "${pgSchema}"."${table.tableName}" as chains;`
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let getInitialState = (sql, ~pgSchema) => {
|
|
276
|
+
sql
|
|
277
|
+
->Postgres.unsafe(makeGetInitialStateQuery(~pgSchema))
|
|
278
|
+
->(Utils.magic: promise<array<unknown>> => promise<array<rawInitialState>>)
|
|
164
279
|
}
|
|
165
280
|
|
|
166
281
|
let progressFields: array<progressFields> = [#progress_block, #events_processed]
|
|
@@ -182,7 +297,7 @@ WHERE "id" = $1;`
|
|
|
182
297
|
|
|
183
298
|
let promises = []
|
|
184
299
|
|
|
185
|
-
chainsData->Utils.Dict.forEachWithKey((
|
|
300
|
+
chainsData->Utils.Dict.forEachWithKey((data, chainId) => {
|
|
186
301
|
let params = []
|
|
187
302
|
|
|
188
303
|
// Push id first (for WHERE clause)
|
|
@@ -201,7 +316,13 @@ WHERE "id" = $1;`
|
|
|
201
316
|
Promise.all(promises)
|
|
202
317
|
}
|
|
203
318
|
|
|
204
|
-
|
|
319
|
+
type progressedChain = {
|
|
320
|
+
chainId: int,
|
|
321
|
+
progressBlockNumber: int,
|
|
322
|
+
totalEventsProcessed: int,
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
let setProgressedChains = (sql, ~pgSchema, ~progressedChains: array<progressedChain>) => {
|
|
205
326
|
let query = makeProgressFieldsUpdateQuery(~pgSchema)
|
|
206
327
|
|
|
207
328
|
let promises = []
|
|
@@ -254,21 +375,175 @@ module PersistedState = {
|
|
|
254
375
|
)
|
|
255
376
|
}
|
|
256
377
|
|
|
257
|
-
module
|
|
378
|
+
module Checkpoints = {
|
|
379
|
+
type field = [
|
|
380
|
+
| #id
|
|
381
|
+
| #chain_id
|
|
382
|
+
| #block_number
|
|
383
|
+
| #block_hash
|
|
384
|
+
| #events_processed
|
|
385
|
+
]
|
|
386
|
+
|
|
258
387
|
type t = {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
388
|
+
id: int,
|
|
389
|
+
@as("chain_id")
|
|
390
|
+
chainId: int,
|
|
391
|
+
@as("block_number")
|
|
392
|
+
blockNumber: int,
|
|
393
|
+
@as("block_hash")
|
|
394
|
+
blockHash: Js.null<string>,
|
|
395
|
+
@as("events_processed")
|
|
396
|
+
eventsProcessed: int,
|
|
262
397
|
}
|
|
263
398
|
|
|
399
|
+
let initialCheckpointId = 0
|
|
400
|
+
|
|
264
401
|
let table = mkTable(
|
|
265
|
-
"
|
|
402
|
+
"envio_checkpoints",
|
|
266
403
|
~fields=[
|
|
267
|
-
mkField(
|
|
268
|
-
mkField(
|
|
269
|
-
mkField(
|
|
404
|
+
mkField((#id: field :> string), Integer, ~fieldSchema=S.int, ~isPrimaryKey),
|
|
405
|
+
mkField((#chain_id: field :> string), Integer, ~fieldSchema=S.int),
|
|
406
|
+
mkField((#block_number: field :> string), Integer, ~fieldSchema=S.int),
|
|
407
|
+
mkField((#block_hash: field :> string), Text, ~fieldSchema=S.null(S.string), ~isNullable),
|
|
408
|
+
mkField((#events_processed: field :> string), Integer, ~fieldSchema=S.int),
|
|
270
409
|
],
|
|
271
410
|
)
|
|
411
|
+
|
|
412
|
+
let makeGetReorgCheckpointsQuery = (~pgSchema): string => {
|
|
413
|
+
// Use CTE to pre-filter chains and compute safe_block once per chain
|
|
414
|
+
// This is faster because:
|
|
415
|
+
// 1. Chains table is small, so filtering it first is cheap
|
|
416
|
+
// 2. safe_block is computed once per chain, not per checkpoint
|
|
417
|
+
// 3. Query planner can materialize the small CTE result before joining
|
|
418
|
+
`WITH reorg_chains AS (
|
|
419
|
+
SELECT
|
|
420
|
+
"${(#id: Chains.field :> string)}" as id,
|
|
421
|
+
"${(#source_block: Chains.field :> string)}" - "${(#max_reorg_depth: Chains.field :> string)}" AS safe_block
|
|
422
|
+
FROM "${pgSchema}"."${Chains.table.tableName}"
|
|
423
|
+
WHERE "${(#max_reorg_depth: Chains.field :> string)}" > 0
|
|
424
|
+
AND "${(#progress_block: Chains.field :> string)}" > "${(#source_block: Chains.field :> string)}" - "${(#max_reorg_depth: Chains.field :> string)}"
|
|
425
|
+
)
|
|
426
|
+
SELECT
|
|
427
|
+
cp."${(#id: field :> string)}",
|
|
428
|
+
cp."${(#chain_id: field :> string)}",
|
|
429
|
+
cp."${(#block_number: field :> string)}",
|
|
430
|
+
cp."${(#block_hash: field :> string)}"
|
|
431
|
+
FROM "${pgSchema}"."${table.tableName}" cp
|
|
432
|
+
INNER JOIN reorg_chains rc
|
|
433
|
+
ON cp."${(#chain_id: field :> string)}" = rc.id
|
|
434
|
+
WHERE cp."${(#block_hash: field :> string)}" IS NOT NULL
|
|
435
|
+
AND cp."${(#block_number: field :> string)}" >= rc.safe_block;` // Include safe_block checkpoint to use it for safe checkpoint tracking
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
let makeCommitedCheckpointIdQuery = (~pgSchema) => {
|
|
439
|
+
`SELECT COALESCE(MAX(${(#id: field :> string)}), ${initialCheckpointId->Belt.Int.toString}) AS id FROM "${pgSchema}"."${table.tableName}";`
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
let makeInsertCheckpointQuery = (~pgSchema) => {
|
|
443
|
+
`INSERT INTO "${pgSchema}"."${table.tableName}" ("${(#id: field :> string)}", "${(#chain_id: field :> string)}", "${(#block_number: field :> string)}", "${(#block_hash: field :> string)}", "${(#events_processed: field :> string)}")
|
|
444
|
+
SELECT * FROM unnest($1::${(Integer :> string)}[],$2::${(Integer :> string)}[],$3::${(Integer :> string)}[],$4::${(Text :> string)}[],$5::${(Integer :> string)}[]);`
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
let insert = (
|
|
448
|
+
sql,
|
|
449
|
+
~pgSchema,
|
|
450
|
+
~checkpointIds,
|
|
451
|
+
~checkpointChainIds,
|
|
452
|
+
~checkpointBlockNumbers,
|
|
453
|
+
~checkpointBlockHashes,
|
|
454
|
+
~checkpointEventsProcessed,
|
|
455
|
+
) => {
|
|
456
|
+
let query = makeInsertCheckpointQuery(~pgSchema)
|
|
457
|
+
|
|
458
|
+
sql
|
|
459
|
+
->Postgres.preparedUnsafe(
|
|
460
|
+
query,
|
|
461
|
+
(
|
|
462
|
+
checkpointIds,
|
|
463
|
+
checkpointChainIds,
|
|
464
|
+
checkpointBlockNumbers,
|
|
465
|
+
checkpointBlockHashes,
|
|
466
|
+
checkpointEventsProcessed,
|
|
467
|
+
)->(
|
|
468
|
+
Utils.magic: (
|
|
469
|
+
(array<int>, array<int>, array<int>, array<Js.Null.t<string>>, array<int>)
|
|
470
|
+
) => unknown
|
|
471
|
+
),
|
|
472
|
+
)
|
|
473
|
+
->Promise.ignoreValue
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
let rollback = (sql, ~pgSchema, ~rollbackTargetCheckpointId: int) => {
|
|
477
|
+
sql
|
|
478
|
+
->Postgres.preparedUnsafe(
|
|
479
|
+
`DELETE FROM "${pgSchema}"."${table.tableName}" WHERE "${(#id: field :> string)}" > $1;`,
|
|
480
|
+
[rollbackTargetCheckpointId]->Utils.magic,
|
|
481
|
+
)
|
|
482
|
+
->Promise.ignoreValue
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
let makePruneStaleCheckpointsQuery = (~pgSchema) => {
|
|
486
|
+
`DELETE FROM "${pgSchema}"."${table.tableName}" WHERE "${(#id: field :> string)}" < $1;`
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let pruneStaleCheckpoints = (sql, ~pgSchema, ~safeCheckpointId: int) => {
|
|
490
|
+
sql
|
|
491
|
+
->Postgres.preparedUnsafe(
|
|
492
|
+
makePruneStaleCheckpointsQuery(~pgSchema),
|
|
493
|
+
[safeCheckpointId]->Obj.magic,
|
|
494
|
+
)
|
|
495
|
+
->Promise.ignoreValue
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
let makeGetRollbackTargetCheckpointQuery = (~pgSchema) => {
|
|
499
|
+
`SELECT "${(#id: field :> string)}" FROM "${pgSchema}"."${table.tableName}"
|
|
500
|
+
WHERE
|
|
501
|
+
"${(#chain_id: field :> string)}" = $1 AND
|
|
502
|
+
"${(#block_number: field :> string)}" <= $2
|
|
503
|
+
ORDER BY "${(#id: field :> string)}" DESC
|
|
504
|
+
LIMIT 1;`
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
let getRollbackTargetCheckpoint = (
|
|
508
|
+
sql,
|
|
509
|
+
~pgSchema,
|
|
510
|
+
~reorgChainId: int,
|
|
511
|
+
~lastKnownValidBlockNumber: int,
|
|
512
|
+
) => {
|
|
513
|
+
sql
|
|
514
|
+
->Postgres.preparedUnsafe(
|
|
515
|
+
makeGetRollbackTargetCheckpointQuery(~pgSchema),
|
|
516
|
+
(reorgChainId, lastKnownValidBlockNumber)->Obj.magic,
|
|
517
|
+
)
|
|
518
|
+
->(Utils.magic: promise<unknown> => promise<array<{"id": int}>>)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
let makeGetRollbackProgressDiffQuery = (~pgSchema) => {
|
|
522
|
+
`SELECT
|
|
523
|
+
"${(#chain_id: field :> string)}",
|
|
524
|
+
SUM("${(#events_processed: field :> string)}") as events_processed_diff,
|
|
525
|
+
MIN("${(#block_number: field :> string)}") - 1 as new_progress_block_number
|
|
526
|
+
FROM "${pgSchema}"."${table.tableName}"
|
|
527
|
+
WHERE "${(#id: field :> string)}" > $1
|
|
528
|
+
GROUP BY "${(#chain_id: field :> string)}";`
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
let getRollbackProgressDiff = (sql, ~pgSchema, ~rollbackTargetCheckpointId: int) => {
|
|
532
|
+
sql
|
|
533
|
+
->Postgres.preparedUnsafe(
|
|
534
|
+
makeGetRollbackProgressDiffQuery(~pgSchema),
|
|
535
|
+
[rollbackTargetCheckpointId]->Obj.magic,
|
|
536
|
+
)
|
|
537
|
+
->(
|
|
538
|
+
Utils.magic: promise<unknown> => promise<
|
|
539
|
+
array<{
|
|
540
|
+
"chain_id": int,
|
|
541
|
+
"events_processed_diff": string,
|
|
542
|
+
"new_progress_block_number": int,
|
|
543
|
+
}>,
|
|
544
|
+
>
|
|
545
|
+
)
|
|
546
|
+
}
|
|
272
547
|
}
|
|
273
548
|
|
|
274
549
|
module RawEvents = {
|
|
@@ -363,69 +638,3 @@ module Views = {
|
|
|
363
638
|
FROM "${pgSchema}"."${Chains.table.tableName}";`
|
|
364
639
|
}
|
|
365
640
|
}
|
|
366
|
-
|
|
367
|
-
module DynamicContractRegistry = {
|
|
368
|
-
let name = "dynamic_contract_registry"
|
|
369
|
-
|
|
370
|
-
let makeId = (~chainId, ~contractAddress) => {
|
|
371
|
-
chainId->Belt.Int.toString ++ "-" ++ contractAddress->Address.toString
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// @genType Used for Test DB
|
|
375
|
-
@genType
|
|
376
|
-
type t = {
|
|
377
|
-
id: string,
|
|
378
|
-
@as("chain_id") chainId: int,
|
|
379
|
-
@as("registering_event_block_number") registeringEventBlockNumber: int,
|
|
380
|
-
@as("registering_event_log_index") registeringEventLogIndex: int,
|
|
381
|
-
@as("registering_event_block_timestamp") registeringEventBlockTimestamp: int,
|
|
382
|
-
@as("registering_event_contract_name") registeringEventContractName: string,
|
|
383
|
-
@as("registering_event_name") registeringEventName: string,
|
|
384
|
-
@as("registering_event_src_address") registeringEventSrcAddress: Address.t,
|
|
385
|
-
@as("contract_address") contractAddress: Address.t,
|
|
386
|
-
@as("contract_name") contractName: string,
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
let schema = S.schema(s => {
|
|
390
|
-
id: s.matches(S.string),
|
|
391
|
-
chainId: s.matches(S.int),
|
|
392
|
-
registeringEventBlockNumber: s.matches(S.int),
|
|
393
|
-
registeringEventLogIndex: s.matches(S.int),
|
|
394
|
-
registeringEventContractName: s.matches(S.string),
|
|
395
|
-
registeringEventName: s.matches(S.string),
|
|
396
|
-
registeringEventSrcAddress: s.matches(Address.schema),
|
|
397
|
-
registeringEventBlockTimestamp: s.matches(S.int),
|
|
398
|
-
contractAddress: s.matches(Address.schema),
|
|
399
|
-
contractName: s.matches(S.string),
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
let rowsSchema = S.array(schema)
|
|
403
|
-
|
|
404
|
-
let table = mkTable(
|
|
405
|
-
name,
|
|
406
|
-
~fields=[
|
|
407
|
-
mkField("id", Text, ~isPrimaryKey, ~fieldSchema=S.string),
|
|
408
|
-
mkField("chain_id", Integer, ~fieldSchema=S.int),
|
|
409
|
-
mkField("registering_event_block_number", Integer, ~fieldSchema=S.int),
|
|
410
|
-
mkField("registering_event_log_index", Integer, ~fieldSchema=S.int),
|
|
411
|
-
mkField("registering_event_block_timestamp", Integer, ~fieldSchema=S.int),
|
|
412
|
-
mkField("registering_event_contract_name", Text, ~fieldSchema=S.string),
|
|
413
|
-
mkField("registering_event_name", Text, ~fieldSchema=S.string),
|
|
414
|
-
mkField("registering_event_src_address", Text, ~fieldSchema=Address.schema),
|
|
415
|
-
mkField("contract_address", Text, ~fieldSchema=Address.schema),
|
|
416
|
-
mkField("contract_name", Text, ~fieldSchema=S.string),
|
|
417
|
-
],
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
let entityHistory = table->EntityHistory.fromTable(~schema)
|
|
421
|
-
|
|
422
|
-
external castToInternal: t => Internal.entity = "%identity"
|
|
423
|
-
|
|
424
|
-
let config = {
|
|
425
|
-
name,
|
|
426
|
-
schema,
|
|
427
|
-
rowsSchema,
|
|
428
|
-
table,
|
|
429
|
-
entityHistory,
|
|
430
|
-
}->Internal.fromGenericEntityConfig
|
|
431
|
-
}
|