@sentio/runtime 0.0.0-rc.a

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 ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@sentio/runtime",
3
+ "version": "0.0.0-rc.a",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./lib/index.js",
8
+ "./service-worker": "./lib/service-worker.js"
9
+ },
10
+ "bin": {
11
+ "processor-runner": "./lib/processor-runner.js"
12
+ },
13
+ "files": [
14
+ "{lib,src}",
15
+ "!**/*.test.{js,ts}",
16
+ "!{lib,src}/tests"
17
+ ],
18
+ "dependencies": {
19
+ "@grpc/grpc-js": "^1.9.14",
20
+ "@opentelemetry/exporter-metrics-otlp-grpc": "^0.57.0",
21
+ "@opentelemetry/exporter-prometheus": "^0.57.0",
22
+ "@opentelemetry/sdk-node": "^0.57.0",
23
+ "command-line-args": "^6.0.0",
24
+ "command-line-usage": "^7.0.1",
25
+ "ethers": "npm:@sentio/ethers@6.13.1-patch.5",
26
+ "fs-extra": "^11.2.0",
27
+ "google-protobuf": "^3.21.2",
28
+ "ix": "^7.0.0",
29
+ "long": "^5.2.3",
30
+ "nice-grpc": "^2.1.10",
31
+ "nice-grpc-client-middleware-retry": "^3.1.6",
32
+ "nice-grpc-common": "^2.0.2",
33
+ "nice-grpc-error-details": "^0.2.4",
34
+ "nice-grpc-opentelemetry": "^0.1.15",
35
+ "nice-grpc-prometheus": "^0.2.2",
36
+ "protobufjs": "^7.2.6",
37
+ "rxjs": "^7.8.1",
38
+ "utility-types": "^3.11.0",
39
+ "winston": "^3.11.0",
40
+ "@sentio/protos": "0.0.0-rc.a"
41
+ },
42
+ "devDependencies": {
43
+ "@types/command-line-args": "^5.2.3",
44
+ "@types/command-line-usage": "^5.0.4",
45
+ "@types/fs-extra": "^11.0.4",
46
+ "@types/google-protobuf": "^3.15.12",
47
+ "piscina": "5.0.0-alpha.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=20"
51
+ },
52
+ "scripts": {
53
+ "build": "pnpm tsc --noEmit && pnpm bundle",
54
+ "build:all": "pnpm --filter=$(node -p \"require('./package.json').name\")... build",
55
+ "bundle": "tsup --config src/tsup.config.ts",
56
+ "compile": "tsc",
57
+ "run": "tsx src/processor-runner.ts --log-format=json",
58
+ "run-benchmark": "tsx src/decode-benchmark.ts",
59
+ "start_js": "tsx ./lib/processor-runner.js $PWD/../../debug/dist/lib.js",
60
+ "start_ts": "tsx ./lib/processor-runner.js --log-format=json $PWD/../../debug/src/processor.ts",
61
+ "test": "glob -c 'tsx --test' '**/*.test.ts'"
62
+ }
63
+ }
@@ -0,0 +1,18 @@
1
+ import { PluginManager } from './plugin.js'
2
+ import { ProcessConfigResponse } from '@sentio/protos'
3
+
4
+ export class ActionServer {
5
+ constructor(readonly loader: () => Promise<void>) {}
6
+
7
+ async listen(port: number) {
8
+ const pluginManager = PluginManager.INSTANCE
9
+ await this.loader()
10
+ await pluginManager.configure(ProcessConfigResponse.create())
11
+ console.log('Starting Action Server at:', port)
12
+ await pluginManager.startServer(port)
13
+ }
14
+
15
+ forceShutdown() {
16
+ PluginManager.INSTANCE.shutdown()
17
+ }
18
+ }
@@ -0,0 +1,5 @@
1
+ export interface ChainConfig {
2
+ ChainID: string
3
+ Https?: string[]
4
+ ChainServer?: string
5
+ }
@@ -0,0 +1,227 @@
1
+ import { Subject } from 'rxjs'
2
+ import {
3
+ DBRequest,
4
+ DBRequest_DBUpsert,
5
+ DBResponse,
6
+ DeepPartial,
7
+ ProcessResult,
8
+ ProcessStreamResponse
9
+ } from '@sentio/protos'
10
+ import * as process from 'node:process'
11
+ import { dbMetrics } from './metrics.js'
12
+ const {
13
+ request_errors,
14
+ unsolved_requests,
15
+ request_times,
16
+ batched_request_count,
17
+ batched_total_count,
18
+ send_counts,
19
+ recv_counts
20
+ } = dbMetrics
21
+ const STORE_BATCH_IDLE = process.env['STORE_BATCH_MAX_IDLE'] ? parseInt(process.env['STORE_BATCH_MAX_IDLE']) : 1
22
+ const STORE_BATCH_SIZE = process.env['STORE_BATCH_SIZE'] ? parseInt(process.env['STORE_BATCH_SIZE']) : 10
23
+ const STORE_UPSERT_NO_WAIT = process.env['STORE_UPSERT_NO_WAIT'] === 'true'
24
+
25
+ type Request = Omit<DBRequest, 'opId'>
26
+ type RequestType = keyof Request
27
+
28
+ export const timeoutError = new Error('timeout')
29
+
30
+ export class StoreContext {
31
+ private static opCounter = 0n
32
+ private defers = new Map<
33
+ bigint,
34
+ { resolve: (value: any) => void; reject: (reason?: any) => void; requestType?: RequestType }
35
+ >()
36
+ private statsInterval: NodeJS.Timeout | undefined
37
+ private pendings: Promise<unknown>[] = []
38
+
39
+ constructor(
40
+ readonly subject: Subject<DeepPartial<ProcessStreamResponse>>,
41
+ readonly processId: number
42
+ ) {}
43
+
44
+ newPromise<T>(opId: bigint, requestType?: RequestType) {
45
+ return new Promise<T>((resolve, reject) => {
46
+ this.defers.set(opId, { resolve, reject, requestType })
47
+ unsolved_requests.record(this.defers.size, { processId: this.processId })
48
+ })
49
+ }
50
+
51
+ sendRequest(request: DeepPartial<Request>, timeoutSecs?: number): Promise<DBResponse> {
52
+ if (STORE_BATCH_IDLE > 0 && STORE_BATCH_SIZE > 1 && request.upsert) {
53
+ // batch upsert if possible
54
+ return this.sendUpsertInBatch(request.upsert as DBRequest_DBUpsert)
55
+ }
56
+
57
+ const requestType = Object.keys(request)[0] as RequestType
58
+ const opId = StoreContext.opCounter++
59
+ const promise = this.newPromise(opId, requestType)
60
+
61
+ const start = Date.now()
62
+ const promises = [promise]
63
+ // console.debug('sending db request ', opId, request)
64
+ let timer: NodeJS.Timeout | undefined
65
+ if (timeoutSecs) {
66
+ const timeoutPromise = new Promise((_r, rej) => (timer = setTimeout(rej, timeoutSecs * 1000, timeoutError)))
67
+ promises.push(timeoutPromise)
68
+ }
69
+
70
+ this.subject.next({
71
+ dbRequest: {
72
+ ...request,
73
+ opId
74
+ },
75
+ processId: this.processId
76
+ })
77
+
78
+ send_counts[requestType]?.add(1)
79
+
80
+ if (requestType === 'upsert' && STORE_UPSERT_NO_WAIT) {
81
+ this.pendings.push(promise)
82
+ return Promise.resolve({
83
+ opId,
84
+ } as DBResponse)
85
+ }
86
+
87
+ return Promise.race(promises)
88
+ .then((result: DBResponse) => {
89
+ if (timeoutSecs) {
90
+ console.debug('db request', requestType, 'op', opId, ' took', Date.now() - start, 'ms')
91
+ }
92
+ request_times[requestType]?.add(Date.now() - start)
93
+ return result
94
+ })
95
+ .catch((e) => {
96
+ if (e === timeoutError) {
97
+ console.error('db request', requestType, 'op:', opId, ' timeout')
98
+ }
99
+ request_errors[requestType]?.add(1)
100
+ throw e
101
+ })
102
+ .finally(() => {
103
+ if (timer) {
104
+ clearTimeout(timer)
105
+ }
106
+ })
107
+ }
108
+
109
+ result(dbResult: DBResponse) {
110
+ const opId = dbResult.opId
111
+ const defer = this.defers.get(opId)
112
+ // console.debug('received db result ', opId, dbResult)
113
+ if (defer) {
114
+ if (defer.requestType) {
115
+ recv_counts[defer.requestType]?.add(1)
116
+ }
117
+ if (dbResult.error) {
118
+ defer.reject(new Error(dbResult.error))
119
+ } else {
120
+ defer.resolve(dbResult)
121
+ }
122
+ this.defers.delete(opId)
123
+ }
124
+ unsolved_requests.record(this.defers.size, { processId: this.processId })
125
+ }
126
+
127
+ error(processId: number, e: any) {
128
+ console.error('process error', processId, e)
129
+ const errorResult = ProcessResult.create({
130
+ states: {
131
+ error: e?.toString()
132
+ }
133
+ })
134
+ this.subject.next({
135
+ result: errorResult,
136
+ processId
137
+ })
138
+ }
139
+
140
+ close() {
141
+ for (const [opId, defer] of this.defers) {
142
+ // console.warn('context closed before db response', opId)
143
+ defer.reject(new Error('context closed before db response, processId: ' + this.processId + ' opId: ' + opId))
144
+ }
145
+ this.defers.clear()
146
+ if (this.statsInterval) {
147
+ clearInterval(this.statsInterval)
148
+ }
149
+ }
150
+
151
+ upsertBatch:
152
+ | {
153
+ opId: bigint
154
+ request: DBRequest_DBUpsert
155
+ promise: Promise<DBResponse>
156
+ timer: NodeJS.Timeout
157
+ }
158
+ | undefined = undefined
159
+
160
+ private async sendUpsertInBatch(req: DBRequest_DBUpsert): Promise<DBResponse> {
161
+ if (this.upsertBatch) {
162
+ // merge the upserts
163
+ const { request, promise } = this.upsertBatch
164
+ request.entity = this.upsertBatch.request.entity.concat(req.entity)
165
+ request.entityData = this.upsertBatch.request.entityData.concat(req.entityData)
166
+ request.id = this.upsertBatch.request.id.concat(req.id)
167
+ if (request.entity.length >= STORE_BATCH_SIZE) {
168
+ this.sendBatch()
169
+ }
170
+ if (STORE_UPSERT_NO_WAIT) {
171
+ return {
172
+ opId: this.upsertBatch.opId
173
+ }
174
+ }
175
+
176
+ return promise
177
+ } else {
178
+ const opId = StoreContext.opCounter++
179
+ const timeout = setTimeout(() => {
180
+ this.sendBatch()
181
+ }, STORE_BATCH_IDLE)
182
+ const start = Date.now()
183
+ const promise = this.newPromise<DBResponse>(opId, 'upsert').finally(() => {
184
+ request_times['upsert'].add(Date.now() - start)
185
+ })
186
+
187
+ this.upsertBatch = {
188
+ opId,
189
+ request: req,
190
+ promise,
191
+ timer: timeout,
192
+ }
193
+
194
+ if (STORE_UPSERT_NO_WAIT) {
195
+ this.pendings.push(promise)
196
+ return {
197
+ opId: this.upsertBatch.opId
198
+ }
199
+ } else {
200
+ return promise
201
+ }
202
+ }
203
+ }
204
+
205
+ private sendBatch() {
206
+ if (this.upsertBatch) {
207
+ const { request, opId, timer } = this.upsertBatch
208
+ // console.debug('sending batch upsert', opId, 'batch size', request?.entity.length)
209
+ clearTimeout(timer)
210
+ this.upsertBatch = undefined
211
+ this.subject.next({
212
+ dbRequest: {
213
+ upsert: request,
214
+ opId
215
+ },
216
+ processId: this.processId
217
+ })
218
+ send_counts['upsert']?.add(1)
219
+ batched_request_count.add(1)
220
+ batched_total_count.add(request.entity.length)
221
+ }
222
+ }
223
+
224
+ async awaitPendings() {
225
+ await Promise.all(this.pendings)
226
+ }
227
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs'
4
+
5
+ const fileContent = fs.readFileSync('../../../chain/aptos/testdata/block-0-9999.json', { encoding: 'utf-8' })
6
+ // console.log(fileContent)
7
+
8
+ const contents: object[] = JSON.parse(fileContent)
9
+
10
+ console.log(contents.length)
11
+
12
+ const raws: Uint8Array[] = []
13
+ for (const content of contents) {
14
+ raws.push(new TextEncoder().encode(JSON.stringify(content)))
15
+ }
16
+
17
+ console.log('test begin')
18
+
19
+ const start = Date.now()
20
+
21
+ for (let i = 0; i < 10; i++) {
22
+ for (const raw of raws) {
23
+ const x = JSON.parse(new TextDecoder().decode(raw))
24
+ }
25
+ }
26
+
27
+ const end = Date.now()
28
+ console.log((end - start) / 1000.0, 'seconds')
@@ -0,0 +1,11 @@
1
+ export class Endpoints {
2
+ static INSTANCE: Endpoints = new Endpoints()
3
+
4
+ concurrency = 8
5
+ chainQueryAPI = ''
6
+ priceFeedAPI = ''
7
+
8
+ chainServer = new Map<string, string>()
9
+
10
+ batchCount = 1
11
+ }
@@ -0,0 +1,339 @@
1
+ import { CallContext } from 'nice-grpc'
2
+ import { createRequire } from 'module'
3
+ // Different than the simple one which
4
+ import {
5
+ DataBinding,
6
+ ExecutionConfig,
7
+ HandlerType,
8
+ PreprocessStreamRequest,
9
+ ProcessBindingsRequest,
10
+ ProcessConfigRequest,
11
+ ProcessorServiceImplementation,
12
+ ProcessResult,
13
+ ProcessStreamRequest,
14
+ StartRequest
15
+ } from './gen/processor/protos/processor.js'
16
+
17
+ import { Empty } from '@sentio/protos'
18
+ import fs from 'fs-extra'
19
+ import path from 'path'
20
+ import os from 'os'
21
+ import { GLOBAL_CONFIG } from './global-config.js'
22
+ import { compareSemver, parseSemver, Semver } from './utils.js'
23
+ import { LRUCache } from 'lru-cache'
24
+
25
+ const require = createRequire(import.meta.url)
26
+
27
+ const FUEL_PROTO_UPDATE_VERSION = parseSemver('2.54.0-rc.7')
28
+ const FUEL_PROTO_NO_FUEL_TRANSACTION_AS_CALL_VERSION = parseSemver('2.55.0-rc.1')
29
+
30
+ const MOVE_USE_RAW_VERSION = parseSemver('2.55.0-rc.1')
31
+ const ETH_USE_RAW_VERSION = parseSemver('2.57.9-rc.12')
32
+ // new driver (after MOVE_USE_RAW_VERSION) will sent the same event multiple times when fetch all true
33
+ // so we need to cache it, key will be tx-handler_id
34
+ const PROCESSED_MOVE_EVENT_TX_HANDLER = new LRUCache<string, boolean>({
35
+ max: 10000
36
+ })
37
+
38
+ function locatePackageJson(pkgId: string) {
39
+ const m = require.resolve(pkgId)
40
+
41
+ let dir = path.dirname(m)
42
+ while (!fs.existsSync(path.join(dir, 'package.json'))) {
43
+ dir = path.dirname(dir)
44
+ }
45
+ const content = fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')
46
+ return JSON.parse(content)
47
+ }
48
+
49
+ export class FullProcessorServiceImpl implements ProcessorServiceImplementation {
50
+ constructor(instance: ProcessorServiceImplementation) {
51
+ this.instance = instance
52
+ const sdkPackageJson = locatePackageJson('@sentio/sdk')
53
+ const runtimePackageJson = locatePackageJson('@sentio/runtime')
54
+
55
+ console.log('Runtime version:', runtimePackageJson.version, 'SDK version:', sdkPackageJson.version)
56
+
57
+ this.sdkVersion = parseSemver(sdkPackageJson.version)
58
+ }
59
+
60
+ instance: ProcessorServiceImplementation
61
+ sdkVersion: Semver
62
+
63
+ async getConfig(request: ProcessConfigRequest, context: CallContext) {
64
+ const config = await this.instance.getConfig(request, context)
65
+ config.executionConfig = ExecutionConfig.fromPartial(GLOBAL_CONFIG.execution)
66
+
67
+ if (config.contractConfigs) {
68
+ for (const contract of config.contractConfigs) {
69
+ // for old fuel processor
70
+ if (
71
+ compareSemver(this.sdkVersion, FUEL_PROTO_NO_FUEL_TRANSACTION_AS_CALL_VERSION) < 0 &&
72
+ contract.fuelCallConfigs
73
+ ) {
74
+ contract.fuelTransactionConfigs = contract.fuelCallConfigs
75
+ contract.fuelCallConfigs = undefined
76
+ }
77
+
78
+ // @ts-ignore convert old fuelLogConfigs to fuelReceiptConfigs
79
+ if (contract.fuelLogConfigs) {
80
+ contract.fuelReceiptConfigs = contract.fuelLogConfigs.map((e) => ({
81
+ handlerId: e.handlerId,
82
+ handlerName: e.handlerName,
83
+ log: {
84
+ logIds: e.logIds
85
+ }
86
+ }))
87
+ }
88
+
89
+ // @ts-ignore old fields
90
+ if (contract.aptosCallConfigs) {
91
+ // @ts-ignore old fields
92
+ contract.moveCallConfigs = contract.aptosCallConfigs
93
+ }
94
+ // @ts-ignore old fields
95
+ if (contract.aptosEventConfigs) {
96
+ // @ts-ignore old fields
97
+ contract.moveEventConfigs = contract.aptosEventConfigs
98
+ }
99
+ }
100
+ }
101
+
102
+ if (compareSemver(this.sdkVersion, MOVE_USE_RAW_VERSION) < 0) {
103
+ PROCESSED_MOVE_EVENT_TX_HANDLER.clear()
104
+ }
105
+
106
+ return config
107
+ }
108
+
109
+ async start(request: StartRequest, context: CallContext) {
110
+ return await this.instance.start(request, context)
111
+ }
112
+
113
+ async stop(request: Empty, context: CallContext) {
114
+ return await this.instance.stop(request, context)
115
+ }
116
+
117
+ async processBindings(request: ProcessBindingsRequest, options: CallContext) {
118
+ // if (GLOBAL_CONFIG.execution.sequential) {
119
+ // request.bindings = request.bindings.sort(dataCompare)
120
+ // }
121
+
122
+ for (const binding of request.bindings) {
123
+ this.adjustDataBinding(binding)
124
+ }
125
+ try {
126
+ const result = await this.instance.processBindings(request, options)
127
+ this.adjustResult(result.result as ProcessResult)
128
+ if (!result.configUpdated && result.result?.states?.configUpdated) {
129
+ result.configUpdated = result.result?.states?.configUpdated
130
+ }
131
+ return result
132
+ } catch (e) {
133
+ if (this.sdkVersion.minor <= 16) {
134
+ // Old sdk doesn't handle this well
135
+ if (
136
+ e.code === os.constants.errno.ECONNRESET ||
137
+ e.code === os.constants.errno.ECONNREFUSED ||
138
+ e.code === os.constants.errno.ECONNABORTED
139
+ ) {
140
+ process.exit(1)
141
+ }
142
+ }
143
+ throw e
144
+ }
145
+ }
146
+
147
+ async *adjustBindingsStream(requests: AsyncIterable<ProcessStreamRequest>): AsyncIterable<ProcessStreamRequest> {
148
+ for await (const request of requests) {
149
+ this.adjustDataBinding(request.binding)
150
+ yield request
151
+ }
152
+ }
153
+
154
+ async *processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: CallContext) {
155
+ yield* this.instance.processBindingsStream(this.adjustBindingsStream(requests), context)
156
+ }
157
+
158
+ async *preprocessBindingsStream(requests: AsyncIterable<PreprocessStreamRequest>, context: CallContext) {
159
+ yield* this.instance.preprocessBindingsStream(this.adjustBindingsStream(requests), context)
160
+ }
161
+
162
+ private adjustResult(res: ProcessResult): void {}
163
+
164
+ private adjustDataBinding(dataBinding?: DataBinding): void {
165
+ const isBeforeMoveUseRawVersion = compareSemver(this.sdkVersion, MOVE_USE_RAW_VERSION) < 0
166
+ // const isBeforeEthUseRawVersion = compareSemver(this.sdkVersion,ETH_USE_RAW_VERSION) < 0
167
+
168
+ if (!dataBinding) {
169
+ return
170
+ }
171
+ switch (dataBinding.handlerType) {
172
+ case HandlerType.ETH_LOG:
173
+ const ethLog = dataBinding.data?.ethLog
174
+ if (ethLog?.log == null && ethLog?.rawLog) {
175
+ ethLog.log = JSON.parse(ethLog.rawLog)
176
+ ethLog.transaction = ethLog.rawTransaction ? JSON.parse(ethLog.rawTransaction) : undefined
177
+ ethLog.block = ethLog.rawBlock ? JSON.parse(ethLog.rawBlock) : undefined
178
+ ethLog.transactionReceipt = ethLog.rawTransactionReceipt
179
+ ? JSON.parse(ethLog.rawTransactionReceipt)
180
+ : undefined
181
+ }
182
+ break
183
+ case HandlerType.ETH_TRANSACTION:
184
+ const ethTx = dataBinding.data?.ethTransaction
185
+ if (ethTx?.transaction == null && ethTx?.rawTransaction) {
186
+ ethTx.transaction = JSON.parse(ethTx.rawTransaction)
187
+ ethTx.block = ethTx.rawBlock ? JSON.parse(ethTx.rawBlock) : undefined
188
+ ethTx.transactionReceipt = ethTx.rawTransactionReceipt ? JSON.parse(ethTx.rawTransactionReceipt) : undefined
189
+ }
190
+ break
191
+ case HandlerType.FUEL_TRANSACTION:
192
+ if (compareSemver(this.sdkVersion, FUEL_PROTO_UPDATE_VERSION) < 0) {
193
+ dataBinding.handlerType = HandlerType.FUEL_CALL
194
+ if (dataBinding.data) {
195
+ dataBinding.data.fuelCall = dataBinding.data?.fuelTransaction
196
+ }
197
+ }
198
+ break
199
+ case HandlerType.FUEL_RECEIPT:
200
+ if (compareSemver(this.sdkVersion, FUEL_PROTO_UPDATE_VERSION) < 0) {
201
+ dataBinding.handlerType = HandlerType.FUEL_CALL
202
+ if (dataBinding.data) {
203
+ dataBinding.data.fuelCall = dataBinding.data?.fuelLog
204
+ }
205
+ }
206
+
207
+ break
208
+ case HandlerType.APT_EVENT:
209
+ const aptEvent = dataBinding.data?.aptEvent
210
+ if (aptEvent) {
211
+ if (isBeforeMoveUseRawVersion && aptEvent.rawTransaction) {
212
+ const transaction = JSON.parse(aptEvent.rawTransaction)
213
+ const key = `${transaction.hash}-${dataBinding.handlerIds[0]}`
214
+ if (PROCESSED_MOVE_EVENT_TX_HANDLER.has(key)) {
215
+ console.debug('skip binding', key)
216
+ dataBinding.handlerType = HandlerType.UNKNOWN
217
+ return
218
+ }
219
+ PROCESSED_MOVE_EVENT_TX_HANDLER.set(key, true)
220
+
221
+ aptEvent.transaction = transaction
222
+ if (!transaction.events?.length) {
223
+ // when fetch all is not true, then events is empty, we need to fill it to old format
224
+ transaction.events = [JSON.parse(aptEvent.rawEvent)]
225
+ }
226
+ }
227
+ }
228
+ break
229
+ case HandlerType.APT_CALL:
230
+ const aptCall = dataBinding.data?.aptCall
231
+ if (aptCall) {
232
+ if (isBeforeMoveUseRawVersion && aptCall.rawTransaction) {
233
+ aptCall.transaction = JSON.parse(aptCall.rawTransaction)
234
+ }
235
+ }
236
+ break
237
+ case HandlerType.APT_RESOURCE:
238
+ const aptResource = dataBinding.data?.aptResource
239
+ if (aptResource) {
240
+ if (isBeforeMoveUseRawVersion && aptResource.rawResources) {
241
+ aptResource.resources = aptResource.rawResources.map((e) => JSON.parse(e))
242
+ }
243
+ }
244
+ break
245
+ case HandlerType.SUI_EVENT:
246
+ const suiEvent = dataBinding.data?.suiEvent
247
+ if (suiEvent) {
248
+ if (isBeforeMoveUseRawVersion && suiEvent.rawTransaction) {
249
+ const transaction = JSON.parse(suiEvent.rawTransaction)
250
+ const key = `${transaction.digest}-${dataBinding.handlerIds[0]}`
251
+ if (PROCESSED_MOVE_EVENT_TX_HANDLER.has(key)) {
252
+ console.debug('skip binding', key)
253
+ dataBinding.handlerType = HandlerType.UNKNOWN
254
+ return
255
+ }
256
+ PROCESSED_MOVE_EVENT_TX_HANDLER.set(key, true)
257
+
258
+ suiEvent.transaction = transaction
259
+ if (!transaction.events?.length) {
260
+ // when fetch all is not true, then events is empty, we need to fill it to old format
261
+ transaction.events = [JSON.parse(suiEvent.rawEvent)]
262
+ }
263
+ }
264
+ }
265
+ break
266
+ case HandlerType.SUI_CALL:
267
+ const suiCall = dataBinding.data?.suiCall
268
+ if (suiCall) {
269
+ if (isBeforeMoveUseRawVersion && suiCall.rawTransaction) {
270
+ suiCall.transaction = JSON.parse(suiCall.rawTransaction)
271
+ }
272
+ }
273
+ break
274
+ case HandlerType.SUI_OBJECT:
275
+ const suiObject = dataBinding.data?.suiObject
276
+ if (suiObject) {
277
+ if (isBeforeMoveUseRawVersion && (suiObject.rawSelf || suiObject.rawObjects)) {
278
+ if (suiObject.rawSelf) {
279
+ suiObject.self = JSON.parse(suiObject.rawSelf)
280
+ }
281
+ suiObject.objects = suiObject.rawObjects.map((e) => JSON.parse(e))
282
+ }
283
+ }
284
+ break
285
+ case HandlerType.SUI_OBJECT_CHANGE:
286
+ const suiObjectChange = dataBinding.data?.suiObjectChange
287
+ if (suiObjectChange) {
288
+ if (isBeforeMoveUseRawVersion && suiObjectChange.rawChanges) {
289
+ suiObjectChange.changes = suiObjectChange.rawChanges.map((e) => JSON.parse(e))
290
+ }
291
+ }
292
+ break
293
+ case HandlerType.UNKNOWN:
294
+ // if (dataBinding.data?.ethBlock) {
295
+ // if (dataBinding.data.raw.length === 0) {
296
+ // // This is actually not needed in current system, just as initla test propose, move to test only
297
+ // // when this is stable
298
+ // dataBinding.data.raw = new TextEncoder().encode(JSON.stringify(dataBinding.data.ethBlock.block))
299
+ // }
300
+ // }
301
+ break
302
+ default:
303
+ break
304
+ }
305
+ }
306
+ }
307
+
308
+ // function dataCompare(a: DataBinding, b: DataBinding): number {
309
+ // const timeA = getTimestamp(a) || new Date(0)
310
+ // const timeB = getTimestamp(b) || new Date(0)
311
+ // const timeCmp = timeA.getTime() - timeB.getTime()
312
+ // if (timeCmp !== 0) {
313
+ // return timeCmp
314
+ // }
315
+ // return getSecondary(a) - getSecondary(b)
316
+ // }
317
+ //
318
+ // function getTimestamp(d: DataBinding): Date | undefined {
319
+ // return (
320
+ // d.data?.ethLog?.timestamp ||
321
+ // d.data?.ethTransaction?.timestamp ||
322
+ // (d.data?.ethBlock?.block?.timestamp ? new Date(Number(d.data.ethBlock.block.timestamp) * 1000) : undefined) ||
323
+ // d.data?.ethTrace?.timestamp ||
324
+ // (d.data?.aptCall?.transaction ? new Date(Number(d.data.aptCall.transaction.timestamp) / 1000) : undefined) ||
325
+ // (d.data?.aptEvent?.transaction ? new Date(Number(d.data.aptEvent.transaction.timestamp) / 1000) : undefined) ||
326
+ // (d.data?.aptResource?.timestampMicros ? new Date(Number(d.data.aptResource.timestampMicros) / 1000) : undefined) ||
327
+ // d.data?.fuelCall?.timestamp
328
+ // )
329
+ // }
330
+ //
331
+ // function getSecondary(d: DataBinding) {
332
+ // return (
333
+ // d.data?.ethLog?.log?.logIndex ||
334
+ // d.data?.ethTransaction?.transaction?.transactionIndex ||
335
+ // d.data?.ethBlock?.block?.number ||
336
+ // d.data?.ethTrace?.trace?.transactionPosition
337
+ // )
338
+ // }
339
+ //