@sentio/runtime 2.40.0-rc.4 → 2.40.0-rc.41
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/lib/chunk-QYVWD4BX.js +131 -0
- package/lib/chunk-QYVWD4BX.js.map +1 -0
- package/lib/index.d.ts +24 -9
- package/lib/index.js +2 -91
- package/lib/index.js.map +1 -0
- package/lib/processor-runner.d.ts +3 -0
- package/lib/processor-runner.js +58 -51468
- package/lib/processor-runner.js.map +1 -0
- package/package.json +1 -1
- package/src/db-context.ts +51 -44
- package/src/gen/processor/protos/processor.ts +121 -76
- package/src/index.ts +1 -0
- package/src/metrics.ts +138 -0
- package/src/multicall.ts +1615 -0
- package/src/plugin.ts +7 -3
- package/src/processor-runner.ts +64 -21
- package/src/provider.ts +3 -9
- package/src/service.ts +105 -42
- package/src/tsup.config.ts +2 -0
- package/src/utils.ts +11 -3
- package/lib/chunk-FGIYODHE.js +0 -78810
package/src/plugin.ts
CHANGED
@@ -28,7 +28,7 @@ export abstract class Plugin {
|
|
28
28
|
return ProcessResult.create()
|
29
29
|
}
|
30
30
|
|
31
|
-
async preprocessBinding(request: DataBinding): Promise<PreprocessResult> {
|
31
|
+
async preprocessBinding(request: DataBinding, preprocessStore: { [k: string]: any }): Promise<PreprocessResult> {
|
32
32
|
return PreprocessResult.create()
|
33
33
|
}
|
34
34
|
}
|
@@ -84,13 +84,17 @@ export class PluginManager {
|
|
84
84
|
})
|
85
85
|
}
|
86
86
|
|
87
|
-
preprocessBinding(
|
87
|
+
preprocessBinding(
|
88
|
+
request: DataBinding,
|
89
|
+
preprocessStore: { [k: string]: any },
|
90
|
+
dbContext?: StoreContext
|
91
|
+
): Promise<PreprocessResult> {
|
88
92
|
const plugin = this.typesToPlugin.get(request.handlerType)
|
89
93
|
if (!plugin) {
|
90
94
|
throw new Error(`No plugin for ${request.handlerType}`)
|
91
95
|
}
|
92
96
|
return this.dbContextLocalStorage.run(dbContext, () => {
|
93
|
-
return plugin.preprocessBinding(request)
|
97
|
+
return plugin.preprocessBinding(request, preprocessStore)
|
94
98
|
})
|
95
99
|
}
|
96
100
|
}
|
package/src/processor-runner.ts
CHANGED
@@ -7,9 +7,9 @@ import { compressionAlgorithms } from '@grpc/grpc-js'
|
|
7
7
|
import commandLineArgs from 'command-line-args'
|
8
8
|
import { createServer } from 'nice-grpc'
|
9
9
|
import { errorDetailsServerMiddleware } from 'nice-grpc-error-details'
|
10
|
-
import { registry as niceGrpcRegistry
|
10
|
+
// import { registry as niceGrpcRegistry } from 'nice-grpc-prometheus'
|
11
11
|
import { openTelemetryServerMiddleware } from 'nice-grpc-opentelemetry'
|
12
|
-
import { register as globalRegistry, Registry } from 'prom-client'
|
12
|
+
// import { register as globalRegistry, Registry } from 'prom-client'
|
13
13
|
import http from 'http'
|
14
14
|
// @ts-ignore inspector promises is not included in @type/node
|
15
15
|
import { Session } from 'node:inspector/promises'
|
@@ -21,22 +21,17 @@ import { FullProcessorServiceImpl } from './full-service.js'
|
|
21
21
|
import { ChainConfig } from './chain-config.js'
|
22
22
|
import { setupLogger } from './logger.js'
|
23
23
|
|
24
|
-
import { NodeSDK } from '@opentelemetry/sdk-node'
|
24
|
+
// import { NodeSDK } from '@opentelemetry/sdk-node'
|
25
|
+
import { envDetector } from '@opentelemetry/resources'
|
25
26
|
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'
|
26
27
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'
|
27
|
-
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
|
28
|
+
import { PeriodicExportingMetricReader, MeterProvider } from '@opentelemetry/sdk-metrics'
|
29
|
+
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
30
|
+
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
|
31
|
+
import { diag, DiagConsoleLogger, DiagLogLevel, metrics, trace } from '@opentelemetry/api'
|
32
|
+
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'
|
28
33
|
|
29
|
-
const
|
30
|
-
traceExporter: new OTLPTraceExporter(),
|
31
|
-
metricReader: new PeriodicExportingMetricReader({
|
32
|
-
exporter: new OTLPMetricExporter()
|
33
|
-
})
|
34
|
-
// instrumentations: [getNodeAutoInstrumentations()],
|
35
|
-
})
|
36
|
-
|
37
|
-
sdk.start()
|
38
|
-
|
39
|
-
const mergedRegistry = Registry.merge([globalRegistry, niceGrpcRegistry])
|
34
|
+
// const mergedRegistry = Registry.merge([globalRegistry, niceGrpcRegistry])
|
40
35
|
|
41
36
|
const optionDefinitions = [
|
42
37
|
{ name: 'target', type: String, defaultOption: true },
|
@@ -58,9 +53,57 @@ const optionDefinitions = [
|
|
58
53
|
|
59
54
|
const options = commandLineArgs(optionDefinitions, { partial: true })
|
60
55
|
|
61
|
-
|
56
|
+
const logLevel = process.env['LOG_LEVEL']?.toUpperCase()
|
57
|
+
|
58
|
+
setupLogger(options['log-format'] === 'json', logLevel === 'debug' ? true : options.debug)
|
62
59
|
console.debug('Starting with', options.target)
|
63
60
|
|
61
|
+
if (options.debug) {
|
62
|
+
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG)
|
63
|
+
}
|
64
|
+
|
65
|
+
const resource = await envDetector.detect()
|
66
|
+
|
67
|
+
const meterProvider = new MeterProvider({
|
68
|
+
resource,
|
69
|
+
readers: [
|
70
|
+
new PeriodicExportingMetricReader({
|
71
|
+
exporter: new OTLPMetricExporter()
|
72
|
+
}),
|
73
|
+
new PrometheusExporter({
|
74
|
+
// http://localhost:4041/metrics
|
75
|
+
port: 4041
|
76
|
+
})
|
77
|
+
]
|
78
|
+
})
|
79
|
+
|
80
|
+
const traceProvider = new NodeTracerProvider({
|
81
|
+
resource: resource
|
82
|
+
})
|
83
|
+
const exporter = new OTLPTraceExporter() // new ConsoleSpanExporter();
|
84
|
+
const processor = new BatchSpanProcessor(exporter)
|
85
|
+
traceProvider.addSpanProcessor(processor)
|
86
|
+
traceProvider.register()
|
87
|
+
|
88
|
+
metrics.setGlobalMeterProvider(meterProvider)
|
89
|
+
trace.setGlobalTracerProvider(traceProvider)
|
90
|
+
;['SIGINT', 'SIGTERM'].forEach((signal) => {
|
91
|
+
process.on(signal as any, () => shutdownProvider())
|
92
|
+
})
|
93
|
+
|
94
|
+
export async function shutdownProvider() {
|
95
|
+
const traceProvider = trace.getTracerProvider()
|
96
|
+
if (traceProvider instanceof NodeTracerProvider) {
|
97
|
+
traceProvider.shutdown().catch(console.error)
|
98
|
+
}
|
99
|
+
const meterProvider = metrics.getMeterProvider()
|
100
|
+
if (meterProvider instanceof MeterProvider) {
|
101
|
+
meterProvider.shutdown().catch(console.error)
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
metrics.getMeter('processor').createGauge('up').record(1)
|
106
|
+
|
64
107
|
Error.stackTraceLimit = 20
|
65
108
|
|
66
109
|
const fullPath = path.resolve(options['chains-config'])
|
@@ -99,7 +142,7 @@ const server = createServer({
|
|
99
142
|
'grpc.max_receive_message_length': 384 * 1024 * 1024,
|
100
143
|
'grpc.default_compression_algorithm': compressionAlgorithms.gzip
|
101
144
|
})
|
102
|
-
.use(prometheusServerMiddleware())
|
145
|
+
// .use(prometheusServerMiddleware())
|
103
146
|
.use(openTelemetryServerMiddleware())
|
104
147
|
.use(errorDetailsServerMiddleware)
|
105
148
|
const baseService = new ProcessorServiceImpl(async () => {
|
@@ -122,10 +165,10 @@ const httpServer = http
|
|
122
165
|
const reqUrl = new URL(req.url, `http://${req.headers.host}`)
|
123
166
|
const queries = reqUrl.searchParams
|
124
167
|
switch (reqUrl.pathname) {
|
125
|
-
case '/metrics':
|
126
|
-
|
127
|
-
|
128
|
-
|
168
|
+
// case '/metrics':
|
169
|
+
// const metrics = await mergedRegistry.metrics()
|
170
|
+
// res.write(metrics)
|
171
|
+
// break
|
129
172
|
case '/profile': {
|
130
173
|
try {
|
131
174
|
const profileTime = parseInt(queries.get('t') || '1000', 10) || 1000
|
package/src/provider.ts
CHANGED
@@ -4,17 +4,11 @@ import PQueue from 'p-queue'
|
|
4
4
|
import { Endpoints } from './endpoints.js'
|
5
5
|
import { EthChainId } from '@sentio/chain'
|
6
6
|
import { LRUCache } from 'lru-cache'
|
7
|
-
import {
|
7
|
+
import { providerMetrics } from './metrics.js'
|
8
|
+
const { miss_count, hit_count, total_duration, total_queued, queue_size } = providerMetrics
|
8
9
|
|
9
10
|
export const DummyProvider = new JsonRpcProvider('', Network.from(1))
|
10
11
|
|
11
|
-
const meter = metrics.getMeter('processor_provider')
|
12
|
-
const hit_count = meter.createCounter('provider_hit_count')
|
13
|
-
const miss_count = meter.createCounter('provider_miss_count')
|
14
|
-
const queue_size = meter.createGauge('provider_queue_size')
|
15
|
-
const total_duration = meter.createCounter('provider_total_duration')
|
16
|
-
const total_queued = meter.createCounter('provider_total_queued')
|
17
|
-
|
18
12
|
const providers = new Map<string, JsonRpcProvider>()
|
19
13
|
|
20
14
|
// export function getEthChainId(networkish?: EthContext | EthChainId): EthChainId {
|
@@ -38,7 +32,7 @@ export function getProvider(chainId?: EthChainId): Provider {
|
|
38
32
|
const address = Endpoints.INSTANCE.chainServer.get(chainId)
|
39
33
|
const key = network.chainId.toString() + '-' + address
|
40
34
|
|
41
|
-
console.debug(`init provider for ${chainId}, address: ${address}`)
|
35
|
+
// console.debug(`init provider for ${chainId}, address: ${address}`)
|
42
36
|
let provider = providers.get(key)
|
43
37
|
|
44
38
|
if (provider) {
|
package/src/service.ts
CHANGED
@@ -25,20 +25,18 @@ import {
|
|
25
25
|
} from '@sentio/protos'
|
26
26
|
|
27
27
|
import { PluginManager } from './plugin.js'
|
28
|
-
import { errorString, mergeProcessResults } from './utils.js'
|
28
|
+
import { errorString, makeEthCallKey, mergeProcessResults } from './utils.js'
|
29
29
|
import { freezeGlobalConfig, GLOBAL_CONFIG } from './global-config.js'
|
30
30
|
|
31
31
|
import { StoreContext } from './db-context.js'
|
32
32
|
import { Subject } from 'rxjs'
|
33
|
-
import { metrics } from '@opentelemetry/api'
|
34
33
|
import { getProvider } from './provider.js'
|
35
34
|
import { EthChainId } from '@sentio/chain'
|
36
|
-
import { Provider
|
35
|
+
import { Provider } from 'ethers'
|
36
|
+
import { decodeMulticallResult, encodeMulticallData, getMulticallAddress, Multicall3Call } from './multicall.js'
|
37
37
|
|
38
|
-
|
39
|
-
const process_binding_count =
|
40
|
-
const process_binding_time = meter.createCounter('process_binding_time')
|
41
|
-
const process_binding_error = meter.createCounter('process_binding_error')
|
38
|
+
import { processMetrics, providerMetrics, dbMetrics } from './metrics.js'
|
39
|
+
const { process_binding_count, process_binding_time, process_binding_error } = processMetrics
|
42
40
|
|
43
41
|
;(BigInt.prototype as any).toJSON = function () {
|
44
42
|
return this.toString()
|
@@ -54,6 +52,8 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
54
52
|
|
55
53
|
private readonly shutdownHandler?: () => void
|
56
54
|
|
55
|
+
private preparedData: PreparedData | undefined
|
56
|
+
|
57
57
|
constructor(loader: () => Promise<any>, shutdownHandler?: () => void) {
|
58
58
|
this.loader = loader
|
59
59
|
this.shutdownHandler = shutdownHandler
|
@@ -126,11 +126,11 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
126
126
|
}
|
127
127
|
|
128
128
|
async processBindings(request: ProcessBindingsRequest, options?: CallContext): Promise<ProcessBindingResponse> {
|
129
|
-
const
|
129
|
+
const preparedData = await this.preprocessBindings(request.bindings, {}, undefined, options)
|
130
130
|
|
131
131
|
const promises = []
|
132
132
|
for (const binding of request.bindings) {
|
133
|
-
const promise = this.processBinding(binding,
|
133
|
+
const promise = this.processBinding(binding, preparedData)
|
134
134
|
if (GLOBAL_CONFIG.execution.sequential) {
|
135
135
|
await promise
|
136
136
|
}
|
@@ -139,7 +139,9 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
139
139
|
let promise
|
140
140
|
try {
|
141
141
|
promise = await Promise.all(promises)
|
142
|
+
processMetrics.process_binding_count.add(request.bindings.length)
|
142
143
|
} catch (e) {
|
144
|
+
processMetrics.process_binding_error.add(request.bindings.length)
|
143
145
|
throw e
|
144
146
|
}
|
145
147
|
const result = mergeProcessResults(promise)
|
@@ -157,13 +159,14 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
157
159
|
|
158
160
|
async preprocessBindings(
|
159
161
|
bindings: DataBinding[],
|
162
|
+
preprocessStore: { [k: string]: any },
|
160
163
|
dbContext?: StoreContext,
|
161
164
|
options?: CallContext
|
162
|
-
): Promise<
|
163
|
-
console.
|
165
|
+
): Promise<PreparedData> {
|
166
|
+
// console.debug(`preprocessBindings start, bindings: ${bindings.length}`)
|
164
167
|
const promises = []
|
165
168
|
for (const binding of bindings) {
|
166
|
-
promises.push(this.preprocessBinding(binding, dbContext, options))
|
169
|
+
promises.push(this.preprocessBinding(binding, preprocessStore, dbContext, options))
|
167
170
|
}
|
168
171
|
let preprocessResults: PreprocessResult[]
|
169
172
|
try {
|
@@ -171,18 +174,15 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
171
174
|
} catch (e) {
|
172
175
|
throw e
|
173
176
|
}
|
174
|
-
console.log(
|
175
|
-
'ethCallParams: ',
|
176
|
-
preprocessResults.map((r) => r.ethCallParams)
|
177
|
-
)
|
178
177
|
const groupedRequests = new Map<string, EthCallParam[]>()
|
179
178
|
const providers = new Map<string, Provider>()
|
180
179
|
for (const result of preprocessResults) {
|
181
180
|
for (const param of result.ethCallParams) {
|
182
|
-
|
183
|
-
|
181
|
+
const { chainId, blockTag } = param.context!
|
182
|
+
if (!providers.has(chainId)) {
|
183
|
+
providers.set(chainId, getProvider(chainId as EthChainId))
|
184
184
|
}
|
185
|
-
const key =
|
185
|
+
const key = [chainId, blockTag].join('|')
|
186
186
|
if (!groupedRequests.has(key)) {
|
187
187
|
groupedRequests.set(key, [])
|
188
188
|
}
|
@@ -191,35 +191,84 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
191
191
|
}
|
192
192
|
|
193
193
|
const start = Date.now()
|
194
|
-
const
|
194
|
+
const MULTICALL_THRESHOLD = 1
|
195
|
+
const callPromises: Promise<[string, string]>[] = []
|
196
|
+
const multicallPromises: Promise<[string, string][]>[] = []
|
197
|
+
|
195
198
|
for (const params of groupedRequests.values()) {
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
const
|
200
|
-
|
199
|
+
const { chainId, blockTag } = params[0].context!
|
200
|
+
const multicallAddress = getMulticallAddress(chainId as EthChainId)
|
201
|
+
if (params.length <= MULTICALL_THRESHOLD || !multicallAddress) {
|
202
|
+
for (const param of params) {
|
203
|
+
callPromises.push(
|
204
|
+
providers
|
205
|
+
.get(chainId)!
|
206
|
+
.call({
|
207
|
+
to: param.context!.address,
|
208
|
+
data: param.calldata,
|
209
|
+
blockTag
|
210
|
+
})
|
211
|
+
.then((result) => [makeEthCallKey(param), result])
|
212
|
+
)
|
213
|
+
}
|
214
|
+
continue
|
215
|
+
}
|
216
|
+
|
217
|
+
// construct multicalls
|
218
|
+
const CHUNK_SIZE = 128
|
219
|
+
for (let i = 0; i < params.length; i += CHUNK_SIZE) {
|
220
|
+
const chunk = params.slice(i, i + CHUNK_SIZE)
|
221
|
+
const calls: Multicall3Call[] = chunk.map((param) => ({
|
222
|
+
target: param.context!.address,
|
223
|
+
callData: param.calldata
|
224
|
+
}))
|
225
|
+
const data = encodeMulticallData(calls)
|
226
|
+
multicallPromises.push(
|
201
227
|
providers
|
202
|
-
.get(
|
228
|
+
.get(chainId)!
|
203
229
|
.call({
|
204
|
-
to:
|
205
|
-
data:
|
230
|
+
to: multicallAddress,
|
231
|
+
data: data,
|
232
|
+
blockTag
|
233
|
+
})
|
234
|
+
.then((raw) => {
|
235
|
+
const result = decodeMulticallResult(raw).returnData
|
236
|
+
if (result.length != chunk.length) {
|
237
|
+
throw new Error(`multicall result length mismatch, params: ${chunk.length}, result: ${result.length}`)
|
238
|
+
}
|
239
|
+
const ret: [string, string][] = []
|
240
|
+
for (let i = 0; i < chunk.length; i++) {
|
241
|
+
ret.push([makeEthCallKey(chunk[i]), result[i]])
|
242
|
+
}
|
243
|
+
return ret
|
206
244
|
})
|
207
|
-
.then((ret) => [calldata, frag.decodeFunctionResult(param.function, ret).toArray()] as [string, any[]])
|
208
245
|
)
|
209
246
|
}
|
210
247
|
}
|
211
|
-
|
248
|
+
|
249
|
+
let results: { [p: string]: string } = {}
|
212
250
|
try {
|
213
251
|
results = Object.fromEntries(await Promise.all(callPromises))
|
252
|
+
for (const multicallResult of await Promise.all(multicallPromises)) {
|
253
|
+
results = {
|
254
|
+
...results,
|
255
|
+
...Object.fromEntries(multicallResult)
|
256
|
+
}
|
257
|
+
}
|
214
258
|
} catch (e) {
|
215
259
|
console.error(`eth call error: ${e}`)
|
216
260
|
}
|
217
|
-
console.
|
218
|
-
|
261
|
+
// console.debug(
|
262
|
+
// `${Object.keys(results).length} calls finished, actual calls: ${callPromises.length + multicallPromises.length}, elapsed: ${Date.now() - start}ms`
|
263
|
+
// )
|
264
|
+
return {
|
265
|
+
ethCallResults: results
|
266
|
+
}
|
219
267
|
}
|
220
268
|
|
221
269
|
async preprocessBinding(
|
222
270
|
request: DataBinding,
|
271
|
+
preprocessStore: { [k: string]: any },
|
223
272
|
dbContext?: StoreContext,
|
224
273
|
options?: CallContext
|
225
274
|
): Promise<PreprocessResult> {
|
@@ -238,7 +287,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
238
287
|
]
|
239
288
|
)
|
240
289
|
}
|
241
|
-
return await PluginManager.INSTANCE.preprocessBinding(request, dbContext)
|
290
|
+
return await PluginManager.INSTANCE.preprocessBinding(request, preprocessStore, dbContext)
|
242
291
|
}
|
243
292
|
|
244
293
|
async processBinding(
|
@@ -274,6 +323,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
274
323
|
const subject = new Subject<DeepPartial<ProcessStreamResponse>>()
|
275
324
|
this.handleRequests(requests, subject)
|
276
325
|
.then(() => {
|
326
|
+
this.preparedData = { ethCallResults: {} }
|
277
327
|
subject.complete()
|
278
328
|
})
|
279
329
|
.catch((e) => {
|
@@ -288,16 +338,23 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
288
338
|
subject: Subject<DeepPartial<PreprocessStreamResponse>>
|
289
339
|
) {
|
290
340
|
const contexts = new Contexts()
|
341
|
+
const preprocessStore: { [k: string]: any } = {}
|
291
342
|
|
292
343
|
for await (const request of requests) {
|
293
344
|
try {
|
294
|
-
console.debug('received request:', request)
|
295
345
|
if (request.bindings) {
|
296
346
|
const bindings = request.bindings.bindings
|
297
347
|
const dbContext = contexts.new(request.processId, subject)
|
298
348
|
const start = Date.now()
|
299
|
-
this.preprocessBindings(bindings, dbContext)
|
300
|
-
.then(() => {
|
349
|
+
this.preprocessBindings(bindings, preprocessStore, dbContext, undefined)
|
350
|
+
.then((preparedData) => {
|
351
|
+
// TODO maybe not proper to pass data in this way
|
352
|
+
this.preparedData = {
|
353
|
+
ethCallResults: {
|
354
|
+
...this.preparedData?.ethCallResults,
|
355
|
+
...preparedData.ethCallResults
|
356
|
+
}
|
357
|
+
}
|
301
358
|
subject.next({
|
302
359
|
processId: request.processId
|
303
360
|
})
|
@@ -305,12 +362,10 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
305
362
|
.catch((e) => {
|
306
363
|
console.debug(e)
|
307
364
|
dbContext.error(request.processId, e)
|
308
|
-
process_binding_error.add(1)
|
309
365
|
})
|
310
366
|
.finally(() => {
|
311
367
|
const cost = Date.now() - start
|
312
368
|
console.debug('preprocessBinding', request.processId, ' took', cost, 'ms')
|
313
|
-
process_binding_time.add(cost)
|
314
369
|
contexts.delete(request.processId)
|
315
370
|
})
|
316
371
|
}
|
@@ -350,14 +405,16 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
350
405
|
|
351
406
|
for await (const request of requests) {
|
352
407
|
try {
|
353
|
-
console.debug('received request:', request)
|
408
|
+
// console.debug('received request:', request)
|
354
409
|
if (request.binding) {
|
355
410
|
process_binding_count.add(1)
|
356
411
|
const binding = request.binding
|
357
412
|
const dbContext = contexts.new(request.processId, subject)
|
358
413
|
const start = Date.now()
|
359
|
-
PluginManager.INSTANCE.processBinding(binding,
|
360
|
-
.then((result) => {
|
414
|
+
PluginManager.INSTANCE.processBinding(binding, this.preparedData, dbContext)
|
415
|
+
.then(async (result) => {
|
416
|
+
// await all pending db requests
|
417
|
+
await dbContext.awaitPendings()
|
361
418
|
subject.next({
|
362
419
|
result,
|
363
420
|
processId: request.processId
|
@@ -374,11 +431,17 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
|
|
374
431
|
console.debug('processBinding', request.processId, ' took', cost, 'ms')
|
375
432
|
process_binding_time.add(cost)
|
376
433
|
contexts.delete(request.processId)
|
434
|
+
console.debug('db stats', JSON.stringify(dbMetrics.stats()))
|
435
|
+
console.debug('provider stats', JSON.stringify(providerMetrics.stats()))
|
377
436
|
})
|
378
437
|
}
|
379
438
|
if (request.dbResult) {
|
380
439
|
const dbContext = contexts.get(request.processId)
|
381
|
-
|
440
|
+
try {
|
441
|
+
dbContext?.result(request.dbResult)
|
442
|
+
} catch (e) {
|
443
|
+
subject.error(new Error('db result error, process should stop'))
|
444
|
+
}
|
382
445
|
}
|
383
446
|
} catch (e) {
|
384
447
|
// should not happen
|
package/src/tsup.config.ts
CHANGED
package/src/utils.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ProcessResult } from '@sentio/protos'
|
1
|
+
import { EthCallParam, ProcessResult } from '@sentio/protos'
|
2
2
|
|
3
3
|
// TODO better handling this, because old proto doesn't have this
|
4
4
|
import { StateResult, ProcessResult as ProcessResultFull } from './gen/processor/protos/processor.js'
|
@@ -8,7 +8,7 @@ import { Required } from 'utility-types'
|
|
8
8
|
export function mergeProcessResults(results: ProcessResult[]): Required<ProcessResult, 'states'> {
|
9
9
|
const res = {
|
10
10
|
...ProcessResultFull.create(),
|
11
|
-
states: StateResult.create()
|
11
|
+
states: StateResult.create()
|
12
12
|
}
|
13
13
|
|
14
14
|
for (const r of results) {
|
@@ -17,7 +17,7 @@ export function mergeProcessResults(results: ProcessResult[]): Required<ProcessR
|
|
17
17
|
res.events = res.events.concat(r.events)
|
18
18
|
res.exports = res.exports.concat(r.exports)
|
19
19
|
res.states = {
|
20
|
-
configUpdated: res.states?.configUpdated || r.states?.configUpdated || false
|
20
|
+
configUpdated: res.states?.configUpdated || r.states?.configUpdated || false
|
21
21
|
}
|
22
22
|
}
|
23
23
|
return res
|
@@ -28,3 +28,11 @@ export function errorString(e: Error): string {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
export const USER_PROCESSOR = 'user_processor'
|
31
|
+
|
32
|
+
export function makeEthCallKey(param: EthCallParam) {
|
33
|
+
if (!param.context) {
|
34
|
+
throw new Error('null context for eth call')
|
35
|
+
}
|
36
|
+
const { chainId, address, blockTag } = param.context
|
37
|
+
return `${chainId}|${address}|${blockTag}|${param.calldata}`.toLowerCase()
|
38
|
+
}
|