@sentio/runtime 4.0.0-rc.1 → 4.0.0-rc.2

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.
@@ -1,416 +1,69 @@
1
- import { CallContext } from 'nice-grpc'
2
- // Different than the simple one which
1
+ import { create } from '@bufbuild/protobuf'
2
+ import { type HandlerContext, type ServiceImpl } from '@connectrpc/connect'
3
3
  import {
4
- DataBinding,
5
- ExecutionConfig,
6
- HandlerType,
7
- PreprocessStreamRequest,
8
- ProcessBindingsRequest,
9
- ProcessConfigRequest,
10
- ProcessConfigResponse,
11
- ProcessorServiceImplementation,
12
- ProcessResult,
13
- ProcessStreamRequest,
14
- StartRequest
15
- } from './gen/processor/protos/processor.js'
16
-
17
- import { DeepPartial, Empty, ProcessorV3ServiceImplementation, UpdateTemplatesRequest } from '@sentio/protos'
18
- import os from 'os'
4
+ type Empty,
5
+ ExecutionConfigSchema,
6
+ type PreprocessStreamRequest,
7
+ type ProcessBindingsRequest,
8
+ type ProcessConfigRequest,
9
+ Processor,
10
+ ProcessorV3,
11
+ type ProcessStreamRequest,
12
+ type StartRequest,
13
+ type UpdateTemplatesRequest
14
+ } from '@sentio/protos'
15
+ import { ProcessorServiceImpl } from './service.js'
16
+ import { ProcessorServiceImplV3 } from './service-v3.js'
19
17
  import { GLOBAL_CONFIG } from './global-config.js'
20
- import { compareSemver, locatePackageJson, parseSemver, Semver } from './utils.js'
21
- import { LRUCache } from 'lru-cache'
22
- import { createHash } from 'crypto'
23
-
24
- const FUEL_PROTO_UPDATE_VERSION = parseSemver('2.54.0-rc.7')
25
- const FUEL_PROTO_NO_FUEL_TRANSACTION_AS_CALL_VERSION = parseSemver('2.55.0-rc.1')
26
-
27
- const MOVE_USE_RAW_VERSION = parseSemver('2.55.0-rc.1')
28
- const ETH_USE_RAW_VERSION = parseSemver('2.57.9-rc.12')
29
- // new driver (after MOVE_USE_RAW_VERSION) will sent the same event multiple times when fetch all true
30
- // so we need to cache it, key will be tx-handler_id
31
- const PROCESSED_MOVE_EVENT_TX_HANDLER = new LRUCache<string, boolean>({
32
- max: 10000
33
- })
34
-
35
- const enableTxCache = process.env.ENABLE_PARSE_CACHE === 'true'
36
-
37
- // Cache for parsed JSON data
38
- const PARSED_DATA_CACHE = new LRUCache<string, any>({
39
- max: enableTxCache ? 5000 : 1
40
- })
41
-
42
- /**
43
- * Gets parsed JSON data from a string, using a cache to avoid repeated parsing
44
- * @param rawData The raw string data to parse
45
- * @returns The parsed JSON object
46
- */
47
- function getParsedData(rawData: string): any {
48
- if (!enableTxCache) {
49
- return JSON.parse(rawData)
50
- }
51
-
52
- // Create a digest of the raw data for cache key
53
- const digest = createHash('md5').update(rawData).digest('hex')
54
-
55
- // Check if we already have this data parsed
56
- let parsedData = PARSED_DATA_CACHE.get(digest)
57
- if (!parsedData) {
58
- // Parse and cache the data
59
- parsedData = JSON.parse(rawData)
60
- PARSED_DATA_CACHE.set(digest, parsedData)
61
- }
62
-
63
- return parsedData
64
- }
65
-
66
- /**
67
- * The RuntimeServicePatcher class is responsible for providing backward compatibility
68
- * patches for different SDK versions. It ensures that the runtime can adapt to changes
69
- * in the SDK by applying necessary adjustments to data bindings and other configurations.
70
- */
71
- export class RuntimeServicePatcher {
72
- sdkVersion: Semver
73
-
74
- constructor() {
75
- const sdkPackageJson = locatePackageJson('@sentio/sdk')
76
- this.sdkVersion = parseSemver(sdkPackageJson.version)
77
- }
78
-
79
- adjustDataBinding(dataBinding?: DataBinding): void {
80
- const isBeforeMoveUseRawVersion = compareSemver(this.sdkVersion, MOVE_USE_RAW_VERSION) < 0
81
- // const isBeforeEthUseRawVersion = compareSemver(this.sdkVersion,ETH_USE_RAW_VERSION) < 0
82
-
83
- if (!dataBinding) {
84
- return
85
- }
86
- switch (dataBinding.handlerType) {
87
- case HandlerType.ETH_LOG:
88
- const ethLog = dataBinding.data?.ethLog
89
- if (ethLog?.log == null && ethLog?.rawLog) {
90
- ethLog.log = JSON.parse(ethLog.rawLog)
91
-
92
- if (ethLog.rawTransaction) {
93
- ethLog.transaction = getParsedData(ethLog.rawTransaction)
94
- }
95
- if (ethLog.rawBlock) {
96
- ethLog.block = getParsedData(ethLog.rawBlock)
97
- }
98
- if (ethLog.rawTransactionReceipt) {
99
- ethLog.transactionReceipt = getParsedData(ethLog.rawTransactionReceipt)
100
- }
101
- }
102
- break
103
- case HandlerType.ETH_TRANSACTION:
104
- const ethTx = dataBinding.data?.ethTransaction
105
- if (ethTx?.transaction == null && ethTx?.rawTransaction) {
106
- ethTx.transaction = getParsedData(ethTx.rawTransaction)
107
- if (ethTx.rawBlock) {
108
- ethTx.block = getParsedData(ethTx.rawBlock)
109
- } else {
110
- ethTx.block = undefined
111
- }
112
- if (ethTx.rawTransactionReceipt) {
113
- ethTx.transactionReceipt = getParsedData(ethTx.rawTransactionReceipt)
114
- } else {
115
- ethTx.transactionReceipt = undefined
116
- }
117
- }
118
- break
119
- case HandlerType.FUEL_TRANSACTION:
120
- if (compareSemver(this.sdkVersion, FUEL_PROTO_UPDATE_VERSION) < 0) {
121
- dataBinding.handlerType = HandlerType.FUEL_CALL
122
- if (dataBinding.data) {
123
- dataBinding.data.fuelCall = dataBinding.data?.fuelTransaction
124
- }
125
- }
126
- break
127
- case HandlerType.FUEL_RECEIPT:
128
- if (compareSemver(this.sdkVersion, FUEL_PROTO_UPDATE_VERSION) < 0) {
129
- dataBinding.handlerType = HandlerType.FUEL_CALL
130
- if (dataBinding.data) {
131
- dataBinding.data.fuelCall = dataBinding.data?.fuelLog
132
- }
133
- }
134
-
135
- break
136
- case HandlerType.APT_EVENT:
137
- const aptEvent = dataBinding.data?.aptEvent
138
- if (aptEvent) {
139
- if (isBeforeMoveUseRawVersion && aptEvent.rawTransaction) {
140
- const transaction = getParsedData(aptEvent.rawTransaction)
141
-
142
- const key = `${transaction.hash}-${dataBinding.handlerIds[0]}`
143
- if (PROCESSED_MOVE_EVENT_TX_HANDLER.has(key)) {
144
- console.debug('skip binding', key)
145
- dataBinding.handlerType = HandlerType.UNKNOWN
146
- return
147
- }
148
- PROCESSED_MOVE_EVENT_TX_HANDLER.set(key, true)
149
-
150
- aptEvent.transaction = transaction
151
- if (!transaction.events?.length) {
152
- // when fetch all is not true, then events is empty, we need to fill it to old format
153
- transaction.events = [JSON.parse(aptEvent.rawEvent)]
154
- }
155
- }
156
- }
157
- break
158
- case HandlerType.APT_CALL:
159
- const aptCall = dataBinding.data?.aptCall
160
- if (aptCall) {
161
- if (isBeforeMoveUseRawVersion && aptCall.rawTransaction) {
162
- aptCall.transaction = getParsedData(aptCall.rawTransaction)
163
- }
164
- }
165
- break
166
- case HandlerType.APT_RESOURCE:
167
- const aptResource = dataBinding.data?.aptResource
168
- if (aptResource) {
169
- if (isBeforeMoveUseRawVersion && aptResource.rawResources) {
170
- aptResource.resources = aptResource.rawResources.map((e) => JSON.parse(e))
171
- }
172
- }
173
- break
174
- case HandlerType.SUI_EVENT:
175
- const suiEvent = dataBinding.data?.suiEvent
176
- if (suiEvent) {
177
- if (isBeforeMoveUseRawVersion && suiEvent.rawTransaction) {
178
- const transaction = getParsedData(suiEvent.rawTransaction)
179
18
 
180
- const key = `${transaction.digest}-${dataBinding.handlerIds[0]}`
181
- if (PROCESSED_MOVE_EVENT_TX_HANDLER.has(key)) {
182
- console.debug('skip binding', key)
183
- dataBinding.handlerType = HandlerType.UNKNOWN
184
- return
185
- }
186
- PROCESSED_MOVE_EVENT_TX_HANDLER.set(key, true)
19
+ export class FullProcessorServiceImpl implements ServiceImpl<typeof Processor> {
20
+ constructor(readonly instance: ProcessorServiceImpl) {}
187
21
 
188
- suiEvent.transaction = transaction
189
- if (!transaction.events?.length) {
190
- // when fetch all is not true, then events is empty, we need to fill it to old format
191
- transaction.events = [JSON.parse(suiEvent.rawEvent)]
192
- }
193
- }
194
- }
195
- break
196
- case HandlerType.SUI_CALL:
197
- const suiCall = dataBinding.data?.suiCall
198
- if (suiCall) {
199
- if (isBeforeMoveUseRawVersion && suiCall.rawTransaction) {
200
- suiCall.transaction = getParsedData(suiCall.rawTransaction)
201
- }
202
- }
203
- break
204
- case HandlerType.SUI_OBJECT:
205
- const suiObject = dataBinding.data?.suiObject
206
- if (suiObject) {
207
- if (isBeforeMoveUseRawVersion && (suiObject.rawSelf || suiObject.rawObjects)) {
208
- if (suiObject.rawSelf) {
209
- suiObject.self = JSON.parse(suiObject.rawSelf)
210
- }
211
- suiObject.objects = suiObject.rawObjects.map((e) => JSON.parse(e))
212
- }
213
- }
214
- break
215
- case HandlerType.SUI_OBJECT_CHANGE:
216
- const suiObjectChange = dataBinding.data?.suiObjectChange
217
- if (suiObjectChange) {
218
- if (isBeforeMoveUseRawVersion && suiObjectChange.rawChanges) {
219
- suiObjectChange.changes = suiObjectChange.rawChanges.map((e) => JSON.parse(e))
220
- }
221
- }
222
- break
223
- case HandlerType.UNKNOWN:
224
- // if (dataBinding.data?.ethBlock) {
225
- // if (dataBinding.data.raw.length === 0) {
226
- // // This is actually not needed in current system, just as initla test propose, move to test only
227
- // // when this is stable
228
- // dataBinding.data.raw = new TextEncoder().encode(JSON.stringify(dataBinding.data.ethBlock.block))
229
- // }
230
- // }
231
- break
232
- default:
233
- break
234
- }
235
- }
236
-
237
- patchConfig(config: DeepPartial<ProcessConfigResponse>): void {
238
- config.executionConfig = ExecutionConfig.fromPartial(GLOBAL_CONFIG.execution)
239
-
240
- if (config.contractConfigs) {
241
- for (const contract of config.contractConfigs) {
242
- // for old fuel processor
243
- if (
244
- compareSemver(this.sdkVersion, FUEL_PROTO_NO_FUEL_TRANSACTION_AS_CALL_VERSION) < 0 &&
245
- contract.fuelCallConfigs
246
- ) {
247
- contract.fuelTransactionConfigs = contract.fuelCallConfigs
248
- contract.fuelCallConfigs = undefined
249
- }
250
-
251
- // @ts-ignore convert old fuelLogConfigs to fuelReceiptConfigs
252
- if (contract.fuelLogConfigs) {
253
- contract.fuelReceiptConfigs = contract.fuelLogConfigs.map((e) => ({
254
- handlerId: e.handlerId,
255
- handlerName: e.handlerName,
256
- log: {
257
- logIds: e.logIds
258
- }
259
- }))
260
- }
261
-
262
- // @ts-ignore old fields
263
- if (contract.aptosCallConfigs) {
264
- // @ts-ignore old fields
265
- contract.moveCallConfigs = contract.aptosCallConfigs
266
- }
267
- // @ts-ignore old fields
268
- if (contract.aptosEventConfigs) {
269
- // @ts-ignore old fields
270
- contract.moveEventConfigs = contract.aptosEventConfigs
271
- }
272
- }
273
- }
274
- }
275
- }
276
-
277
- export class FullProcessorServiceImpl implements ProcessorServiceImplementation {
278
- constructor(instance: ProcessorServiceImplementation) {
279
- this.instance = instance
280
- const sdkPackageJson = locatePackageJson('@sentio/sdk')
281
- this.sdkVersion = parseSemver(sdkPackageJson.version)
282
- }
283
-
284
- instance: ProcessorServiceImplementation
285
- sdkVersion: Semver
286
- patcher: RuntimeServicePatcher = new RuntimeServicePatcher()
287
-
288
- async getConfig(request: ProcessConfigRequest, context: CallContext) {
22
+ async getConfig(request: ProcessConfigRequest, context: HandlerContext) {
289
23
  const config = await this.instance.getConfig(request, context)
290
- this.patcher.patchConfig(config)
291
-
292
- if (compareSemver(this.sdkVersion, MOVE_USE_RAW_VERSION) < 0) {
293
- PROCESSED_MOVE_EVENT_TX_HANDLER.clear()
294
- }
295
-
24
+ config.executionConfig = create(ExecutionConfigSchema, GLOBAL_CONFIG.execution)
296
25
  return config
297
26
  }
298
27
 
299
- async start(request: StartRequest, context: CallContext) {
28
+ async start(request: StartRequest, context: HandlerContext) {
300
29
  return await this.instance.start(request, context)
301
30
  }
302
31
 
303
- async stop(request: Empty, context: CallContext) {
32
+ async stop(request: Empty, context: HandlerContext) {
304
33
  return await this.instance.stop(request, context)
305
34
  }
306
35
 
307
- async processBindings(request: ProcessBindingsRequest, options: CallContext) {
308
- // if (GLOBAL_CONFIG.execution.sequential) {
309
- // request.bindings = request.bindings.sort(dataCompare)
310
- // }
311
-
312
- for (const binding of request.bindings) {
313
- this.patcher.adjustDataBinding(binding)
314
- }
315
- try {
316
- const result = await this.instance.processBindings(request, options)
317
- this.adjustResult(result.result as ProcessResult)
318
- if (!result.configUpdated && result.result?.states?.configUpdated) {
319
- result.configUpdated = result.result?.states?.configUpdated
320
- }
321
- return result
322
- } catch (e: any) {
323
- if (this.sdkVersion.minor <= 16) {
324
- // Old sdk doesn't handle this well
325
- if (
326
- e.code === os.constants.errno.ECONNRESET ||
327
- e.code === os.constants.errno.ECONNREFUSED ||
328
- e.code === os.constants.errno.ECONNABORTED
329
- ) {
330
- process.exit(1)
331
- }
332
- }
333
- throw e
334
- }
335
- }
336
-
337
- async *adjustBindingsStream(requests: AsyncIterable<ProcessStreamRequest>): AsyncIterable<ProcessStreamRequest> {
338
- for await (const request of requests) {
339
- this.patcher.adjustDataBinding(request.binding)
340
- yield request
341
- }
36
+ async processBindings(request: ProcessBindingsRequest, context: HandlerContext) {
37
+ return await this.instance.processBindings(request, context)
342
38
  }
343
39
 
344
- async *processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: CallContext) {
345
- yield* this.instance.processBindingsStream(this.adjustBindingsStream(requests), context)
40
+ async *processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: HandlerContext) {
41
+ yield* this.instance.processBindingsStream(requests, context)
346
42
  }
347
43
 
348
- async *preprocessBindingsStream(requests: AsyncIterable<PreprocessStreamRequest>, context: CallContext) {
349
- yield* this.instance.preprocessBindingsStream(this.adjustBindingsStream(requests), context)
44
+ async *preprocessBindingsStream(requests: AsyncIterable<PreprocessStreamRequest>, context: HandlerContext) {
45
+ yield* this.instance.preprocessBindingsStream(requests, context)
350
46
  }
351
-
352
- private adjustResult(res: ProcessResult): void {}
353
47
  }
354
48
 
355
- // function dataCompare(a: DataBinding, b: DataBinding): number {
356
- // const timeA = getTimestamp(a) || new Date(0)
357
- // const timeB = getTimestamp(b) || new Date(0)
358
- // const timeCmp = timeA.getTime() - timeB.getTime()
359
- // if (timeCmp !== 0) {
360
- // return timeCmp
361
- // }
362
- // return getSecondary(a) - getSecondary(b)
363
- // }
364
- //
365
- // function getTimestamp(d: DataBinding): Date | undefined {
366
- // return (
367
- // d.data?.ethLog?.timestamp ||
368
- // d.data?.ethTransaction?.timestamp ||
369
- // (d.data?.ethBlock?.block?.timestamp ? new Date(Number(d.data.ethBlock.block.timestamp) * 1000) : undefined) ||
370
- // d.data?.ethTrace?.timestamp ||
371
- // (d.data?.aptCall?.transaction ? new Date(Number(d.data.aptCall.transaction.timestamp) / 1000) : undefined) ||
372
- // (d.data?.aptEvent?.transaction ? new Date(Number(d.data.aptEvent.transaction.timestamp) / 1000) : undefined) ||
373
- // (d.data?.aptResource?.timestampMicros ? new Date(Number(d.data.aptResource.timestampMicros) / 1000) : undefined) ||
374
- // d.data?.fuelCall?.timestamp
375
- // )
376
- // }
377
- //
378
- // function getSecondary(d: DataBinding) {
379
- // return (
380
- // d.data?.ethLog?.log?.logIndex ||
381
- // d.data?.ethTransaction?.transaction?.transactionIndex ||
382
- // d.data?.ethBlock?.block?.number ||
383
- // d.data?.ethTrace?.trace?.transactionPosition
384
- // )
385
- // }
386
-
387
- export class FullProcessorServiceV3Impl implements ProcessorV3ServiceImplementation {
388
- patcher: RuntimeServicePatcher = new RuntimeServicePatcher()
389
-
390
- constructor(readonly instance: ProcessorV3ServiceImplementation) {}
49
+ export class FullProcessorServiceV3Impl implements ServiceImpl<typeof ProcessorV3> {
50
+ constructor(readonly instance: ProcessorServiceImplV3) {}
391
51
 
392
- async start(request: StartRequest, context: CallContext): Promise<DeepPartial<Empty>> {
52
+ async start(request: StartRequest, context: HandlerContext) {
393
53
  return this.instance.start(request, context)
394
54
  }
395
55
 
396
- async getConfig(request: ProcessConfigRequest, context: CallContext): Promise<DeepPartial<ProcessConfigResponse>> {
56
+ async getConfig(request: ProcessConfigRequest, context: HandlerContext) {
397
57
  const config = await this.instance.getConfig(request, context)
398
- this.patcher.patchConfig(config)
58
+ config.executionConfig = create(ExecutionConfigSchema, GLOBAL_CONFIG.execution)
399
59
  return config
400
60
  }
401
61
 
402
- async *processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: CallContext) {
403
- yield* this.instance.processBindingsStream(this.adjustBindingsStream(requests), context)
404
- }
405
-
406
- async *adjustBindingsStream(requests: AsyncIterable<ProcessStreamRequest>): AsyncIterable<ProcessStreamRequest> {
407
- for await (const request of requests) {
408
- this.patcher.adjustDataBinding(request.binding)
409
- yield request
410
- }
62
+ async *processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: HandlerContext) {
63
+ yield* this.instance.processBindingsStream(requests, context)
411
64
  }
412
65
 
413
- async updateTemplates(request: UpdateTemplatesRequest, context: CallContext): Promise<DeepPartial<Empty>> {
66
+ async updateTemplates(request: UpdateTemplatesRequest, context: HandlerContext) {
414
67
  return this.instance.updateTemplates(request, context)
415
68
  }
416
69
  }
@@ -0,0 +1,41 @@
1
+ // @generated by protoc-gen-es v2.12.0 with parameter "target=ts,import_extension=js,keep_empty_files=true"
2
+ // @generated from file google/type/money.proto (package google.type, syntax proto3)
3
+ /* eslint-disable */
4
+
5
+ import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
6
+ import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
7
+ import type { Message } from "@bufbuild/protobuf";
8
+
9
+ /**
10
+ * Describes the file google/type/money.proto.
11
+ */
12
+ export const file_google_type_money: GenFile = /*@__PURE__*/
13
+ fileDesc("Chdnb29nbGUvdHlwZS9tb25leS5wcm90bxILZ29vZ2xlLnR5cGUiPAoFTW9uZXkSFQoNY3VycmVuY3lfY29kZRgBIAEoCRINCgV1bml0cxgCIAEoAxINCgVuYW5vcxgDIAEoBUJdCg9jb20uZ29vZ2xlLnR5cGVCCk1vbmV5UHJvdG9QAVo2Z29vZ2xlLmdvbGFuZy5vcmcvZ2VucHJvdG8vZ29vZ2xlYXBpcy90eXBlL21vbmV5O21vbmV5ogIDR1RQYgZwcm90bzM");
14
+
15
+ /**
16
+ * @generated from message google.type.Money
17
+ */
18
+ export type Money = Message<"google.type.Money"> & {
19
+ /**
20
+ * @generated from field: string currency_code = 1;
21
+ */
22
+ currencyCode: string;
23
+
24
+ /**
25
+ * @generated from field: int64 units = 2;
26
+ */
27
+ units: bigint;
28
+
29
+ /**
30
+ * @generated from field: int32 nanos = 3;
31
+ */
32
+ nanos: number;
33
+ };
34
+
35
+ /**
36
+ * Describes the message google.type.Money.
37
+ * Use `create(MoneySchema)` to create a new message.
38
+ */
39
+ export const MoneySchema: GenMessage<Money> = /*@__PURE__*/
40
+ messageDesc(file_google_type_money, 0);
41
+