envio 3.13.0-alpha.0 → 3.13.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/package.json +6 -8
- package/src/BatchProcessing.res +4 -5
- package/src/BatchProcessing.res.mjs +4 -11
- package/src/ChainFetching.res +18 -38
- package/src/ChainFetching.res.mjs +14 -20
- package/src/ChainState.res +113 -77
- package/src/ChainState.res.mjs +90 -73
- package/src/ChainState.resi +14 -5
- package/src/Config.res +14 -17
- package/src/Config.res.mjs +5 -20
- package/src/CrossChainState.res +68 -20
- package/src/CrossChainState.res.mjs +48 -5
- package/src/CrossChainState.resi +1 -0
- package/src/Env.res +2 -2
- package/src/ErrorHandling.res +15 -4
- package/src/ErrorHandling.res.mjs +16 -5
- package/src/FinalizeBackfill.res +21 -9
- package/src/FinalizeBackfill.res.mjs +17 -4
- package/src/HandlerRegister.res +0 -37
- package/src/HandlerRegister.res.mjs +0 -18
- package/src/IndexerState.res +2 -0
- package/src/IndexerState.res.mjs +5 -0
- package/src/IndexerState.resi +1 -0
- package/src/Logging.res +6 -38
- package/src/Logging.res.mjs +5 -32
- package/src/Main.res +6 -9
- package/src/Main.res.mjs +3 -5
- package/src/Metrics.res +9 -4
- package/src/Metrics.res.mjs +3 -3
- package/src/Persistence.res +6 -3
- package/src/Persistence.res.mjs +5 -3
- package/src/PgStorage.res +2 -2
- package/src/PgStorage.res.mjs +2 -2
- package/src/Rollback.res +3 -3
- package/src/Server.res +0 -3
- package/src/SimulateItems.res +1 -1
- package/src/SimulateItems.res.mjs +1 -1
- package/src/Supervisor.res +236 -109
- package/src/Supervisor.res.mjs +185 -55
- package/src/TestIndexer.res +6 -3
- package/src/TestIndexer.res.mjs +3 -3
- package/src/Worker.res +6 -0
- package/src/Worker.res.mjs +2 -1
- package/src/bindings/NodeJs.res +25 -16
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/sources/AddressSet.res +5 -3
- package/src/sources/AddressStore.res +19 -11
- package/src/sources/AddressStore.res.mjs +2 -7
- package/src/sources/BlockStore.res +10 -9
- package/src/sources/BlockStore.res.mjs +4 -4
- package/src/sources/ChainSources.res +4 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -0
- package/src/sources/EvmChain.res.mjs +3 -1
- package/src/sources/EvmEventItem.res +56 -0
- package/src/sources/EvmEventItem.res.mjs +32 -0
- package/src/sources/EvmHyperSyncSource.res +7 -37
- package/src/sources/EvmHyperSyncSource.res.mjs +8 -29
- package/src/sources/EvmRpcClient.res +41 -59
- package/src/sources/EvmRpcClient.res.mjs +4 -54
- package/src/sources/EvmRpcWs.res +4 -1
- package/src/sources/EvmRpcWs.res.mjs +6 -2
- package/src/sources/FuelHyperSyncSource.res +6 -4
- package/src/sources/FuelHyperSyncSource.res.mjs +7 -9
- package/src/sources/HeightFeed.res +7 -1
- package/src/sources/HeightFeed.res.mjs +9 -7
- package/src/sources/HyperSyncClient.res +1 -14
- package/src/sources/RequestStat.res +7 -0
- package/src/sources/RequestStat.res.mjs +14 -1
- package/src/sources/RpcSource.res +100 -1043
- package/src/sources/RpcSource.res.mjs +81 -1056
- package/src/sources/SimulateSource.res +2 -5
- package/src/sources/SimulateSource.res.mjs +2 -3
- package/src/sources/Source.res +34 -12
- package/src/sources/Source.res.mjs +11 -0
- package/src/sources/SourceManager.res +111 -31
- package/src/sources/SourceManager.res.mjs +65 -31
- package/src/sources/SourceManager.resi +4 -0
- package/src/sources/StartBlockResolver.res +8 -5
- package/src/sources/StartBlockResolver.res.mjs +4 -2
- package/src/sources/SvmHyperSyncSource.res +4 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -6
- package/src/sources/TransactionStore.res +9 -6
- package/src/sources/TransactionStore.res.mjs +2 -2
- package/src/tui/Tui.res +4 -18
- package/src/tui/Tui.res.mjs +3 -6
- package/src/LazyLoader.res +0 -135
- package/src/LazyLoader.res.mjs +0 -118
- package/src/bindings/SDSL.res +0 -12
- package/src/bindings/SDSL.res.mjs +0 -9
- package/src/bindings/Yargs.res +0 -8
- package/src/bindings/Yargs.res.mjs +0 -2
- package/src/sources/Rpc.res +0 -185
- package/src/sources/Rpc.res.mjs +0 -183
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Source from "./Source.res.mjs";
|
|
4
4
|
import * as HyperSync from "./HyperSync.res.mjs";
|
|
5
5
|
import * as Performance from "../bindings/Performance.res.mjs";
|
|
6
|
+
import * as RequestStat from "./RequestStat.res.mjs";
|
|
6
7
|
import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
|
|
7
8
|
import * as HyperSyncSSE from "./HyperSyncSSE.res.mjs";
|
|
8
9
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -136,17 +137,15 @@ function make(param) {
|
|
|
136
137
|
TAG: "WithBackoff",
|
|
137
138
|
message: `Unexpected issue while fetching instructions from SVM HyperSync. Attempt a retry.`,
|
|
138
139
|
backoffMillis: retry !== 0 ? 1000 * retry | 0 : 500
|
|
139
|
-
}
|
|
140
|
+
},
|
|
141
|
+
requestStats: RequestStat.single("getInstructions", pageFetchRef)
|
|
140
142
|
},
|
|
141
143
|
Error: new Error()
|
|
142
144
|
};
|
|
143
145
|
}
|
|
144
146
|
let resp = match[0];
|
|
145
147
|
let pageFetchTime = Performance.secondsSince(pageFetchRef);
|
|
146
|
-
let requestStats =
|
|
147
|
-
method: "getInstructions",
|
|
148
|
-
seconds: pageFetchTime
|
|
149
|
-
}];
|
|
148
|
+
let requestStats = RequestStat.single("getInstructions", pageFetchRef);
|
|
150
149
|
let parsingRef = Performance.now();
|
|
151
150
|
let parsedQueueItems = resp.items.map(item => {
|
|
152
151
|
let onEventRegistration = onEventRegistrations[item.onEventRegistrationIndex];
|
|
@@ -171,7 +170,6 @@ function make(param) {
|
|
|
171
170
|
parsedQueueItems: parsedQueueItems,
|
|
172
171
|
transactionStore: Primitive_option.some(match[1]),
|
|
173
172
|
blockStore: match[2],
|
|
174
|
-
fromBlockQueried: fromBlock,
|
|
175
173
|
latestFetchedBlockNumber: highestSlot,
|
|
176
174
|
stats: {
|
|
177
175
|
"total time elapsed (s)": totalTimeElapsed,
|
|
@@ -6,16 +6,15 @@
|
|
|
6
6
|
// in columnar form and zipped into plain JS objects on the main thread.
|
|
7
7
|
type t
|
|
8
8
|
|
|
9
|
-
@send external newEvm:
|
|
9
|
+
@send external newEvm: Core.transactionStoreCtor => t = "newEvm"
|
|
10
10
|
@send external newSvm: Core.transactionStoreCtor => t = "newSvm"
|
|
11
11
|
@send external newFuel: Core.transactionStoreCtor => t = "newFuel"
|
|
12
12
|
|
|
13
|
-
// The store's ecosystem is fixed here, from the chain's config.
|
|
14
|
-
|
|
15
|
-
let make = (~ecosystem: Ecosystem.name, ~shouldChecksum: bool): t => {
|
|
13
|
+
// The store's ecosystem is fixed here, from the chain's config.
|
|
14
|
+
let make = (~ecosystem: Ecosystem.name): t => {
|
|
16
15
|
let ctor = Core.getAddon().transactionStore
|
|
17
16
|
switch ecosystem {
|
|
18
|
-
| Evm => ctor->newEvm
|
|
17
|
+
| Evm => ctor->newEvm
|
|
19
18
|
| Svm => ctor->newSvm
|
|
20
19
|
| Fuel => ctor->newFuel
|
|
21
20
|
}
|
|
@@ -71,13 +70,17 @@ let fromSvmJs = (transactions: array<svmTxInput>, activities: array<svmActivityI
|
|
|
71
70
|
|
|
72
71
|
// Bulk-materialise transactions off the JS thread, one row per
|
|
73
72
|
// (blockNumbers[i], transactionIndices[i]) key, decoding only the fields set in
|
|
74
|
-
// that row's own masks[i]. Result is aligned with the input.
|
|
73
|
+
// that row's own masks[i]. Result is aligned with the input. `shouldChecksum` is
|
|
74
|
+
// the caller's spelling for the addresses decoded out of the store: the rows
|
|
75
|
+
// themselves are raw bytes, so a page merged from a differently configured store
|
|
76
|
+
// can't fix it in.
|
|
75
77
|
@send
|
|
76
78
|
external materialize: (
|
|
77
79
|
t,
|
|
78
80
|
~blockNumbers: array<int>,
|
|
79
81
|
~transactionIndices: array<int>,
|
|
80
82
|
~masks: array<float>,
|
|
83
|
+
~shouldChecksum: bool,
|
|
81
84
|
) => promise<array<Internal.eventTransaction>> = "materialize"
|
|
82
85
|
|
|
83
86
|
// Drop transactions for blocks at or below the given block (already processed).
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import * as Core from "../Core.res.mjs";
|
|
4
4
|
import * as FieldMask from "./FieldMask.res.mjs";
|
|
5
5
|
|
|
6
|
-
function make(ecosystem
|
|
6
|
+
function make(ecosystem) {
|
|
7
7
|
let ctor = Core.getAddon().TransactionStore;
|
|
8
8
|
switch (ecosystem) {
|
|
9
9
|
case "evm" :
|
|
10
|
-
return ctor.newEvm(
|
|
10
|
+
return ctor.newEvm();
|
|
11
11
|
case "fuel" :
|
|
12
12
|
return ctor.newFuel();
|
|
13
13
|
case "svm" :
|
package/src/tui/Tui.res
CHANGED
|
@@ -248,29 +248,15 @@ module App = {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
@get external argv: process => 'a = "argv"
|
|
256
|
-
|
|
257
|
-
type mainArgs = Yargs.parsedArgs<args>
|
|
258
|
-
|
|
259
|
-
// Whether this process draws the progress display: `--tui-off` first, then
|
|
260
|
-
// `ENVIO_TUI`, then whether anything is watching. A supervisor asks the same
|
|
261
|
-
// question its workers would have, since it is the one drawing for the run.
|
|
262
|
-
let shouldUse = (~suppressed=false) => {
|
|
263
|
-
let mainArgs: mainArgs = process->argv->Yargs.hideBin->Yargs.yargs->Yargs.argv
|
|
264
|
-
let explicitTui = switch mainArgs.tuiOff {
|
|
265
|
-
| Some(off) => Some(!off)
|
|
266
|
-
| None => Env.tuiEnvVar
|
|
267
|
-
}
|
|
251
|
+
// Whether this process draws the progress display: `ENVIO_TUI` first, then
|
|
252
|
+
// whether anything is watching. A supervisor asks the same question its
|
|
253
|
+
// workers would have, since it is the one drawing for the run.
|
|
254
|
+
let shouldUse = (~suppressed=false, ~explicitTui=Env.tuiEnvVar) =>
|
|
268
255
|
switch (suppressed, explicitTui) {
|
|
269
256
|
| (true, _) => false
|
|
270
257
|
| (_, Some(tui)) => tui
|
|
271
258
|
| (_, None) => !Envio.isNonInteractive()
|
|
272
259
|
}
|
|
273
|
-
}
|
|
274
260
|
|
|
275
261
|
let start = (~config, ~getMetrics) => {
|
|
276
262
|
let {rerender} = render(<App config getMetrics />)
|
package/src/tui/Tui.res.mjs
CHANGED
|
@@ -8,13 +8,12 @@ import * as React from "react";
|
|
|
8
8
|
import * as SyncETA from "./components/SyncETA.res.mjs";
|
|
9
9
|
import * as TuiData from "./components/TuiData.res.mjs";
|
|
10
10
|
import * as Messages from "./components/Messages.res.mjs";
|
|
11
|
-
import Yargs from "yargs/yargs";
|
|
12
11
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
13
12
|
import InkBigText from "ink-big-text";
|
|
14
13
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
15
14
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
16
|
-
import * as Helpers from "yargs/helpers";
|
|
17
15
|
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
|
|
16
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
18
17
|
import * as JsxRuntime from "react/jsx-runtime";
|
|
19
18
|
import * as BufferedProgressBar from "./components/BufferedProgressBar.res.mjs";
|
|
20
19
|
|
|
@@ -325,11 +324,9 @@ let App = {
|
|
|
325
324
|
make: Tui$App
|
|
326
325
|
};
|
|
327
326
|
|
|
328
|
-
function shouldUse(suppressedOpt) {
|
|
327
|
+
function shouldUse(suppressedOpt, explicitTuiOpt) {
|
|
329
328
|
let suppressed = suppressedOpt !== undefined ? suppressedOpt : false;
|
|
330
|
-
let
|
|
331
|
-
let off = mainArgs["tui-off"];
|
|
332
|
-
let explicitTui = off !== undefined ? !off : Env.tuiEnvVar;
|
|
329
|
+
let explicitTui = explicitTuiOpt !== undefined ? Primitive_option.valFromOption(explicitTuiOpt) : Env.tuiEnvVar;
|
|
333
330
|
if (suppressed) {
|
|
334
331
|
return false;
|
|
335
332
|
} else if (explicitTui !== undefined) {
|
package/src/LazyLoader.res
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
exception LoaderTimeout(string)
|
|
2
|
-
|
|
3
|
-
type rec asyncMap<'key, 'value> = {
|
|
4
|
-
// The number of loaded results to keep cached. (For block loading this should be our maximum block interval)
|
|
5
|
-
_cacheSize: int,
|
|
6
|
-
// The maximum number of results we can try to load simultaneously.
|
|
7
|
-
_loaderPoolSize: int,
|
|
8
|
-
// How long to wait before retrying failures
|
|
9
|
-
// TODO: Add randomized exponential back-off (outdated)
|
|
10
|
-
_retryDelayMillis: int,
|
|
11
|
-
// How long to wait before cancelling a load request
|
|
12
|
-
_timeoutMillis: int,
|
|
13
|
-
// The promises we return to callers. We satisfy them asynchronously.
|
|
14
|
-
externalPromises: Utils.Map.t<'key, promise<'value>>,
|
|
15
|
-
// The handled used to populate the external promises once we have loaded their data.
|
|
16
|
-
resolvers: Utils.Map.t<'key, 'value => unit>,
|
|
17
|
-
// The keys currently being loaded
|
|
18
|
-
inProgress: Utils.Set.t<'key>,
|
|
19
|
-
// Keys for items that we have not started loading yet.
|
|
20
|
-
loaderQueue: SDSL.Queue.t<'key>,
|
|
21
|
-
// Keys for items that have been loaded already. Used to evict the oldest keys from cache.
|
|
22
|
-
loadedKeys: SDSL.Queue.t<'key>,
|
|
23
|
-
// The function used to load the result.
|
|
24
|
-
loaderFn: 'key => promise<'value>,
|
|
25
|
-
// Callback on load error
|
|
26
|
-
onError: option<(asyncMap<'key, 'value>, ~exn: exn) => unit>,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let make = (
|
|
30
|
-
~loaderFn,
|
|
31
|
-
~onError=?,
|
|
32
|
-
~cacheSize: int=10_000,
|
|
33
|
-
~loaderPoolSize: int=10,
|
|
34
|
-
~retryDelayMillis=5_000,
|
|
35
|
-
~timeoutMillis=300_000,
|
|
36
|
-
) => // After 5 minutes (unclear what is best to do here - crash or just keep printing the error)
|
|
37
|
-
{
|
|
38
|
-
_cacheSize: cacheSize,
|
|
39
|
-
_loaderPoolSize: loaderPoolSize,
|
|
40
|
-
_retryDelayMillis: retryDelayMillis,
|
|
41
|
-
_timeoutMillis: timeoutMillis,
|
|
42
|
-
externalPromises: Utils.Map.make(),
|
|
43
|
-
resolvers: Utils.Map.make(),
|
|
44
|
-
inProgress: Utils.Set.make(),
|
|
45
|
-
loaderQueue: SDSL.Queue.make(),
|
|
46
|
-
loadedKeys: SDSL.Queue.make(),
|
|
47
|
-
loaderFn,
|
|
48
|
-
onError,
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
let deleteKey: (dict<'value>, string) => unit = (_obj, _k) => %raw(`delete _obj[_k]`)
|
|
52
|
-
|
|
53
|
-
// If something takes longer than this to load, reject the promise and try again
|
|
54
|
-
let timeoutAfter = timeoutMillis =>
|
|
55
|
-
Utils.delay(timeoutMillis)->Promise.then(() =>
|
|
56
|
-
Promise.reject(
|
|
57
|
-
LoaderTimeout(`Query took longer than ${Int.toString(timeoutMillis / 1000)} seconds`),
|
|
58
|
-
)
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
// Remember `k` as cached, evicting the oldest entry once the cache is full.
|
|
62
|
-
let rememberLoaded = (am: asyncMap<'key, 'value>, k: 'key) => {
|
|
63
|
-
if am.loadedKeys->SDSL.Queue.push(k) > am._cacheSize {
|
|
64
|
-
switch am.loadedKeys->SDSL.Queue.pop {
|
|
65
|
-
| None => ()
|
|
66
|
-
| Some(old) =>
|
|
67
|
-
let _ = am.externalPromises->Utils.Map.delete(old)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let rec loadNext = async (am: asyncMap<'key, 'value>, k: 'key) => {
|
|
73
|
-
// Track that we are loading it now
|
|
74
|
-
let _ = am.inProgress->Utils.Set.add(k)
|
|
75
|
-
|
|
76
|
-
let awaitTaskPromiseAndLoadNextWithTimeout = async () => {
|
|
77
|
-
let val = await Promise.race([am.loaderFn(k), timeoutAfter(am._timeoutMillis)])
|
|
78
|
-
// Resolve the external promise
|
|
79
|
-
am.resolvers
|
|
80
|
-
->Utils.Map.get(k)
|
|
81
|
-
->Option.forEach(r => {
|
|
82
|
-
let _ = am.resolvers->Utils.Map.delete(k)
|
|
83
|
-
r(val)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
// Track that it is no longer in progress
|
|
87
|
-
let _ = am.inProgress->Utils.Set.delete(k)
|
|
88
|
-
|
|
89
|
-
am->rememberLoaded(k)
|
|
90
|
-
|
|
91
|
-
// Load the next one, if there is anything in the queue
|
|
92
|
-
switch am.loaderQueue->SDSL.Queue.pop {
|
|
93
|
-
| None => ()
|
|
94
|
-
| Some(next) => await loadNext(am, next)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await (
|
|
99
|
-
switch await awaitTaskPromiseAndLoadNextWithTimeout() {
|
|
100
|
-
| _ => Promise.resolve()
|
|
101
|
-
| exception err =>
|
|
102
|
-
switch am.onError {
|
|
103
|
-
| None => ()
|
|
104
|
-
| Some(onError) => onError(am, ~exn=err)
|
|
105
|
-
}
|
|
106
|
-
await Utils.delay(am._retryDelayMillis)
|
|
107
|
-
awaitTaskPromiseAndLoadNextWithTimeout()
|
|
108
|
-
}
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
let get = (am: asyncMap<'key, 'value>, k: 'key): promise<'value> => {
|
|
113
|
-
switch am.externalPromises->Utils.Map.get(k) {
|
|
114
|
-
| Some(x) => x
|
|
115
|
-
| None => {
|
|
116
|
-
// Create a promise to deliver the eventual value asynchronously
|
|
117
|
-
let promise = Promise.make((resolve, _) => {
|
|
118
|
-
// Expose the resolver externally, so that we can run it from the loader.
|
|
119
|
-
let _ = am.resolvers->Utils.Map.set(k, resolve)
|
|
120
|
-
})
|
|
121
|
-
// Cache the promise to de-duplicate requests
|
|
122
|
-
let _ = am.externalPromises->Utils.Map.set(k, promise)
|
|
123
|
-
|
|
124
|
-
// Do we have a free loader in the pool?
|
|
125
|
-
if am.inProgress->Utils.Set.size < am._loaderPoolSize {
|
|
126
|
-
loadNext(am, k)->ignore
|
|
127
|
-
} else {
|
|
128
|
-
// Queue the loader
|
|
129
|
-
let _ = am.loaderQueue->SDSL.Queue.push(k)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
promise
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
package/src/LazyLoader.res.mjs
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as JsSdsl from "js-sdsl";
|
|
5
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
7
|
-
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
8
|
-
|
|
9
|
-
let LoaderTimeout = /* @__PURE__ */Primitive_exceptions.create("LazyLoader.LoaderTimeout");
|
|
10
|
-
|
|
11
|
-
function make(loaderFn, onError, cacheSizeOpt, loaderPoolSizeOpt, retryDelayMillisOpt, timeoutMillisOpt) {
|
|
12
|
-
let cacheSize = cacheSizeOpt !== undefined ? cacheSizeOpt : 10000;
|
|
13
|
-
let loaderPoolSize = loaderPoolSizeOpt !== undefined ? loaderPoolSizeOpt : 10;
|
|
14
|
-
let retryDelayMillis = retryDelayMillisOpt !== undefined ? retryDelayMillisOpt : 5000;
|
|
15
|
-
let timeoutMillis = timeoutMillisOpt !== undefined ? timeoutMillisOpt : 300000;
|
|
16
|
-
return {
|
|
17
|
-
_cacheSize: cacheSize,
|
|
18
|
-
_loaderPoolSize: loaderPoolSize,
|
|
19
|
-
_retryDelayMillis: retryDelayMillis,
|
|
20
|
-
_timeoutMillis: timeoutMillis,
|
|
21
|
-
externalPromises: new Map(),
|
|
22
|
-
resolvers: new Map(),
|
|
23
|
-
inProgress: new Set(),
|
|
24
|
-
loaderQueue: new JsSdsl.Queue(),
|
|
25
|
-
loadedKeys: new JsSdsl.Queue(),
|
|
26
|
-
loaderFn: loaderFn,
|
|
27
|
-
onError: onError
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function deleteKey(_obj, _k) {
|
|
32
|
-
((delete _obj[_k]));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function timeoutAfter(timeoutMillis) {
|
|
36
|
-
return Utils.delay(timeoutMillis).then(() => Promise.reject({
|
|
37
|
-
RE_EXN_ID: LoaderTimeout,
|
|
38
|
-
_1: `Query took longer than ` + (timeoutMillis / 1000 | 0).toString() + ` seconds`
|
|
39
|
-
}));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function rememberLoaded(am, k) {
|
|
43
|
-
if (am.loadedKeys.push(k) <= am._cacheSize) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
let old = am.loadedKeys.pop();
|
|
47
|
-
if (old !== undefined) {
|
|
48
|
-
am.externalPromises.delete(Primitive_option.valFromOption(old));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function loadNext(am, k) {
|
|
54
|
-
am.inProgress.add(k);
|
|
55
|
-
let awaitTaskPromiseAndLoadNextWithTimeout = async () => {
|
|
56
|
-
let val = await Promise.race([
|
|
57
|
-
am.loaderFn(k),
|
|
58
|
-
timeoutAfter(am._timeoutMillis)
|
|
59
|
-
]);
|
|
60
|
-
Stdlib_Option.forEach(am.resolvers.get(k), r => {
|
|
61
|
-
am.resolvers.delete(k);
|
|
62
|
-
r(val);
|
|
63
|
-
});
|
|
64
|
-
am.inProgress.delete(k);
|
|
65
|
-
rememberLoaded(am, k);
|
|
66
|
-
let next = am.loaderQueue.pop();
|
|
67
|
-
if (next !== undefined) {
|
|
68
|
-
return await loadNext(am, Primitive_option.valFromOption(next));
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
let tmp;
|
|
72
|
-
let exit = 0;
|
|
73
|
-
let val;
|
|
74
|
-
try {
|
|
75
|
-
val = await awaitTaskPromiseAndLoadNextWithTimeout();
|
|
76
|
-
exit = 1;
|
|
77
|
-
} catch (raw_err) {
|
|
78
|
-
let err = Primitive_exceptions.internalToException(raw_err);
|
|
79
|
-
let onError = am.onError;
|
|
80
|
-
if (onError !== undefined) {
|
|
81
|
-
onError(am, err);
|
|
82
|
-
}
|
|
83
|
-
await Utils.delay(am._retryDelayMillis);
|
|
84
|
-
tmp = awaitTaskPromiseAndLoadNextWithTimeout();
|
|
85
|
-
}
|
|
86
|
-
if (exit === 1) {
|
|
87
|
-
tmp = Promise.resolve();
|
|
88
|
-
}
|
|
89
|
-
return await tmp;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function get(am, k) {
|
|
93
|
-
let x = am.externalPromises.get(k);
|
|
94
|
-
if (x !== undefined) {
|
|
95
|
-
return x;
|
|
96
|
-
}
|
|
97
|
-
let promise = new Promise((resolve, param) => {
|
|
98
|
-
am.resolvers.set(k, resolve);
|
|
99
|
-
});
|
|
100
|
-
am.externalPromises.set(k, promise);
|
|
101
|
-
if (am.inProgress.size < am._loaderPoolSize) {
|
|
102
|
-
loadNext(am, k);
|
|
103
|
-
} else {
|
|
104
|
-
am.loaderQueue.push(k);
|
|
105
|
-
}
|
|
106
|
-
return promise;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export {
|
|
110
|
-
LoaderTimeout,
|
|
111
|
-
make,
|
|
112
|
-
deleteKey,
|
|
113
|
-
timeoutAfter,
|
|
114
|
-
rememberLoaded,
|
|
115
|
-
loadNext,
|
|
116
|
-
get,
|
|
117
|
-
}
|
|
118
|
-
/* Utils Not a pure module */
|
package/src/bindings/SDSL.res
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
module Queue = {
|
|
2
|
-
type t<'a>
|
|
3
|
-
|
|
4
|
-
@module("js-sdsl") @new external make: unit => t<'a> = "Queue"
|
|
5
|
-
|
|
6
|
-
type containerSize = int
|
|
7
|
-
@send external size: t<'a> => containerSize = "size"
|
|
8
|
-
@send external push: (t<'a>, 'a) => containerSize = "push"
|
|
9
|
-
@send external pop: t<'a> => option<'a> = "pop"
|
|
10
|
-
//Returns the front item without popping it
|
|
11
|
-
@send external front: t<'a> => option<'a> = "front"
|
|
12
|
-
}
|
package/src/bindings/Yargs.res
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
type arg = string
|
|
2
|
-
|
|
3
|
-
type parsedArgs<'a> = 'a
|
|
4
|
-
|
|
5
|
-
@module("yargs/yargs") external yargs: array<arg> => parsedArgs<'a> = "default"
|
|
6
|
-
@module("yargs/helpers") external hideBin: array<arg> => array<arg> = "hideBin"
|
|
7
|
-
|
|
8
|
-
@get external argv: parsedArgs<'a> => 'a = "argv"
|
package/src/sources/Rpc.res
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
type rpcError = {code: int, message: string}
|
|
2
|
-
exception JsonRpcError(rpcError)
|
|
3
|
-
|
|
4
|
-
let makeRpcRoute = (method: string, paramsSchema, resultSchema) => {
|
|
5
|
-
let idSchema = S.literal(1)
|
|
6
|
-
let versionSchema = S.literal("2.0")
|
|
7
|
-
Rest.route(() => {
|
|
8
|
-
method: Post,
|
|
9
|
-
path: "",
|
|
10
|
-
input: s => {
|
|
11
|
-
let _ = s.field("method", S.literal(method))
|
|
12
|
-
let _ = s.field("id", idSchema)
|
|
13
|
-
let _ = s.field("jsonrpc", versionSchema)
|
|
14
|
-
s.field("params", paramsSchema)
|
|
15
|
-
},
|
|
16
|
-
responses: [
|
|
17
|
-
s => {
|
|
18
|
-
let _ = s.field("jsonrpc", versionSchema)
|
|
19
|
-
let _ = s.field("id", idSchema)
|
|
20
|
-
s.field("result", resultSchema)
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let jsonRpcFetcher: Rest.ApiFetcher.t = async args => {
|
|
27
|
-
let response = await Rest.ApiFetcher.default(args)
|
|
28
|
-
let data: {..} = response.data->Obj.magic
|
|
29
|
-
switch data["error"]->Nullable.toOption {
|
|
30
|
-
| Some(error) =>
|
|
31
|
-
throw(
|
|
32
|
-
JsonRpcError({
|
|
33
|
-
code: error["code"],
|
|
34
|
-
message: error["message"],
|
|
35
|
-
}),
|
|
36
|
-
)
|
|
37
|
-
| None => response
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let makeClient = (url, ~headers=?) => {
|
|
42
|
-
let fetcher: Rest.ApiFetcher.t = switch headers {
|
|
43
|
-
| None => jsonRpcFetcher
|
|
44
|
-
| Some(customHeaders) =>
|
|
45
|
-
async args => {
|
|
46
|
-
let headers = switch args.headers {
|
|
47
|
-
| Some(headers) => headers
|
|
48
|
-
| None => Dict.make()
|
|
49
|
-
}
|
|
50
|
-
customHeaders->Dict.forEachWithKey((value, key) => headers->Dict.set(key, value->Obj.magic))
|
|
51
|
-
await jsonRpcFetcher({...args, headers: Some(headers)})
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
Rest.client(url, ~fetcher)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type hex = string
|
|
58
|
-
let makeHexSchema = fromStr =>
|
|
59
|
-
S.string->S.transform(s => {
|
|
60
|
-
parser: str =>
|
|
61
|
-
switch str->fromStr {
|
|
62
|
-
| Some(v) => v
|
|
63
|
-
| None => s.fail("The string is not valid hex")
|
|
64
|
-
},
|
|
65
|
-
serializer: value => value->Viem.toHex->(Utils.magic: EvmTypes.Hex.t => 'a),
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
let hexBigintSchema: S.schema<bigint> = makeHexSchema(BigInt.fromString)
|
|
69
|
-
external number: string => int = "Number"
|
|
70
|
-
let hexIntSchema: S.schema<int> = makeHexSchema(v => v->number->Some)
|
|
71
|
-
|
|
72
|
-
external parseFloat: string => float = "Number"
|
|
73
|
-
let decimalFloatSchema: S.schema<float> = S.string->S.transform(s => {
|
|
74
|
-
parser: str => {
|
|
75
|
-
let v = parseFloat(str)
|
|
76
|
-
if Float.isNaN(v) {
|
|
77
|
-
s.fail("The string is not a valid decimal number")
|
|
78
|
-
} else {
|
|
79
|
-
v
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
module GetLogs = {
|
|
85
|
-
type log = {
|
|
86
|
-
address: Address.t,
|
|
87
|
-
topics: array<hex>,
|
|
88
|
-
blockNumber: int,
|
|
89
|
-
transactionHash: hex,
|
|
90
|
-
transactionIndex: int,
|
|
91
|
-
blockHash: hex,
|
|
92
|
-
logIndex: int,
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
module GetBlockByNumber = {
|
|
97
|
-
type block = {
|
|
98
|
-
difficulty: option<bigint>,
|
|
99
|
-
extraData: hex,
|
|
100
|
-
gasLimit: bigint,
|
|
101
|
-
gasUsed: bigint,
|
|
102
|
-
hash: hex,
|
|
103
|
-
logsBloom: hex,
|
|
104
|
-
mutable miner: Address.t,
|
|
105
|
-
mixHash: option<hex>,
|
|
106
|
-
nonce: option<bigint>,
|
|
107
|
-
number: int,
|
|
108
|
-
parentHash: hex,
|
|
109
|
-
receiptsRoot: hex,
|
|
110
|
-
sha3Uncles: hex,
|
|
111
|
-
size: bigint,
|
|
112
|
-
stateRoot: hex,
|
|
113
|
-
timestamp: int,
|
|
114
|
-
totalDifficulty: option<bigint>,
|
|
115
|
-
transactions: array<JSON.t>,
|
|
116
|
-
transactionsRoot: hex,
|
|
117
|
-
uncles: option<array<hex>>,
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let blockSchema = S.object((s): block => {
|
|
121
|
-
difficulty: s.field("difficulty", S.null(hexBigintSchema)),
|
|
122
|
-
extraData: s.field("extraData", S.string),
|
|
123
|
-
gasLimit: s.field("gasLimit", hexBigintSchema),
|
|
124
|
-
gasUsed: s.field("gasUsed", hexBigintSchema),
|
|
125
|
-
hash: s.field("hash", S.string),
|
|
126
|
-
logsBloom: s.field("logsBloom", S.string),
|
|
127
|
-
miner: s.field("miner", Address.schema),
|
|
128
|
-
mixHash: s.field("mixHash", S.null(S.string)),
|
|
129
|
-
nonce: s.field("nonce", S.null(hexBigintSchema)),
|
|
130
|
-
number: s.field("number", hexIntSchema),
|
|
131
|
-
parentHash: s.field("parentHash", S.string),
|
|
132
|
-
receiptsRoot: s.field("receiptsRoot", S.string),
|
|
133
|
-
sha3Uncles: s.field("sha3Uncles", S.string),
|
|
134
|
-
size: s.field("size", hexBigintSchema),
|
|
135
|
-
stateRoot: s.field("stateRoot", S.string),
|
|
136
|
-
timestamp: s.field("timestamp", hexIntSchema),
|
|
137
|
-
totalDifficulty: s.field("totalDifficulty", S.null(hexBigintSchema)),
|
|
138
|
-
transactions: s.field("transactions", S.array(S.json(~validate=false))),
|
|
139
|
-
transactionsRoot: s.field("transactionsRoot", S.string),
|
|
140
|
-
uncles: s.field("uncles", S.null(S.array(S.string))),
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
let paramsSchema = S.tuple(s =>
|
|
144
|
-
{
|
|
145
|
-
"blockNumber": s.item(0, hexIntSchema),
|
|
146
|
-
"includeTransactions": s.item(1, S.bool),
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
let resultSchema = S.null(blockSchema)
|
|
151
|
-
|
|
152
|
-
let route = makeRpcRoute("eth_getBlockByNumber", paramsSchema, resultSchema)
|
|
153
|
-
|
|
154
|
-
let rawRoute = makeRpcRoute("eth_getBlockByNumber", paramsSchema, S.null(S.json(~validate=false)))
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
module GetTransactionByHash = {
|
|
158
|
-
let rawRoute = makeRpcRoute(
|
|
159
|
-
"eth_getTransactionByHash",
|
|
160
|
-
S.tuple1(S.string),
|
|
161
|
-
S.null(S.json(~validate=false)),
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
module GetTransactionReceipt = {
|
|
166
|
-
let rawRoute = makeRpcRoute(
|
|
167
|
-
"eth_getTransactionReceipt",
|
|
168
|
-
S.tuple1(S.string),
|
|
169
|
-
S.null(S.json(~validate=false)),
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
let getBlock = async (~client: Rest.client, ~blockNumber: int) => {
|
|
174
|
-
await GetBlockByNumber.route->Rest.fetch(
|
|
175
|
-
{"blockNumber": blockNumber, "includeTransactions": false},
|
|
176
|
-
~client,
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
let getRawBlock = async (~client: Rest.client, ~blockNumber: int) => {
|
|
181
|
-
await GetBlockByNumber.rawRoute->Rest.fetch(
|
|
182
|
-
{"blockNumber": blockNumber, "includeTransactions": false},
|
|
183
|
-
~client,
|
|
184
|
-
)
|
|
185
|
-
}
|