@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/LICENSE +55 -0
- package/lib/chunk-DYOBLZD3.js +80341 -0
- package/lib/chunk-DYOBLZD3.js.map +1 -0
- package/lib/index.d.ts +663 -0
- package/lib/index.js +127 -0
- package/lib/index.js.map +1 -0
- package/lib/processor-runner.d.ts +34 -0
- package/lib/processor-runner.js +41155 -0
- package/lib/processor-runner.js.map +1 -0
- package/package.json +63 -0
- package/src/action-server.ts +18 -0
- package/src/chain-config.ts +5 -0
- package/src/db-context.ts +227 -0
- package/src/decode-benchmark.ts +28 -0
- package/src/endpoints.ts +11 -0
- package/src/full-service.ts +339 -0
- package/src/gen/google/protobuf/empty.ts +56 -0
- package/src/gen/google/protobuf/struct.ts +494 -0
- package/src/gen/google/protobuf/timestamp.ts +106 -0
- package/src/gen/processor/protos/processor.ts +13640 -0
- package/src/gen/service/common/protos/common.ts +14452 -0
- package/src/global-config.ts +33 -0
- package/src/index.ts +10 -0
- package/src/logger.ts +59 -0
- package/src/metrics.ts +202 -0
- package/src/multicall.ts +1615 -0
- package/src/otlp.ts +59 -0
- package/src/plugin.ts +120 -0
- package/src/processor-runner.ts +226 -0
- package/src/provider.ts +195 -0
- package/src/service-manager.ts +263 -0
- package/src/service-worker.ts +116 -0
- package/src/service.ts +505 -0
- package/src/state.ts +83 -0
- package/src/tsup.config.ts +16 -0
- package/src/utils.ts +93 -0
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,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')
|
package/src/endpoints.ts
ADDED
@@ -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
|
+
//
|