@subsquid/evm-stream 0.0.1-2-0.3887d2
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/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +19 -0
- package/lib/index.js.map +1 -0
- package/lib/query.d.ts +43 -0
- package/lib/query.d.ts.map +1 -0
- package/lib/query.js +148 -0
- package/lib/query.js.map +1 -0
- package/lib/schema.d.ts +210 -0
- package/lib/schema.d.ts.map +1 -0
- package/lib/schema.js +218 -0
- package/lib/schema.js.map +1 -0
- package/lib/source.d.ts +348 -0
- package/lib/source.d.ts.map +1 -0
- package/lib/source.js +193 -0
- package/lib/source.js.map +1 -0
- package/package.json +31 -0
- package/src/index.ts +2 -0
- package/src/query.ts +195 -0
- package/src/schema.ts +263 -0
- package/src/source.ts +261 -0
package/src/schema.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {FieldSelection} from './query'
|
|
2
|
+
import {
|
|
3
|
+
array,
|
|
4
|
+
BYTES,
|
|
5
|
+
NAT,
|
|
6
|
+
object,
|
|
7
|
+
oneOf,
|
|
8
|
+
option,
|
|
9
|
+
QTY,
|
|
10
|
+
SMALL_QTY,
|
|
11
|
+
STRING,
|
|
12
|
+
STRING_FLOAT,
|
|
13
|
+
taggedUnion,
|
|
14
|
+
withDefault,
|
|
15
|
+
withSentinel,
|
|
16
|
+
} from '@subsquid/util-internal-validation'
|
|
17
|
+
|
|
18
|
+
export function getBlockHeaderProps(fields: FieldSelection['block'], forArchive: boolean) {
|
|
19
|
+
let natural = forArchive ? NAT : SMALL_QTY
|
|
20
|
+
return {
|
|
21
|
+
number: natural,
|
|
22
|
+
hash: BYTES,
|
|
23
|
+
parentHash: BYTES,
|
|
24
|
+
...project(fields, {
|
|
25
|
+
nonce: withSentinel('BlockHeader.nonce', '0x', BYTES),
|
|
26
|
+
sha3Uncles: withSentinel('BlockHeader.sha3Uncles', '0x', BYTES),
|
|
27
|
+
logsBloom: withSentinel('BlockHeader.logsBloom', '0x', BYTES),
|
|
28
|
+
transactionsRoot: withSentinel('BlockHeader.transactionsRoot', '0x', BYTES),
|
|
29
|
+
stateRoot: withSentinel('BlockHeader.stateRoot', '0x', BYTES),
|
|
30
|
+
receiptsRoot: withSentinel('BlockHeader.receiptsRoot', '0x', BYTES),
|
|
31
|
+
mixHash: withSentinel('BlockHeader.mixHash', '0x', BYTES),
|
|
32
|
+
miner: withSentinel('BlockHeader.miner', '0x', BYTES),
|
|
33
|
+
difficulty: withSentinel('BlockHeader.difficulty', -1n, QTY),
|
|
34
|
+
totalDifficulty: withSentinel('BlockHeader.totalDifficulty', -1n, QTY),
|
|
35
|
+
extraData: withSentinel('BlockHeader.extraData', '0x', BYTES),
|
|
36
|
+
size: withSentinel('BlockHeader.size', -1, natural),
|
|
37
|
+
gasLimit: withSentinel('BlockHeader.gasLimit', -1n, QTY),
|
|
38
|
+
gasUsed: withSentinel('BlockHeader.gasUsed', -1n, QTY),
|
|
39
|
+
baseFeePerGas: withSentinel('BlockHeader.baseFeePerGas', -1n, QTY),
|
|
40
|
+
timestamp: withSentinel('BlockHeader.timestamp', 0, natural),
|
|
41
|
+
l1BlockNumber: withDefault(0, natural),
|
|
42
|
+
}),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getTxProps(fields: FieldSelection['transaction'], forArchive: boolean) {
|
|
47
|
+
let natural = forArchive ? NAT : SMALL_QTY
|
|
48
|
+
|
|
49
|
+
let Authorization = object({
|
|
50
|
+
chainId: natural,
|
|
51
|
+
nonce: natural,
|
|
52
|
+
address: BYTES,
|
|
53
|
+
yParity: natural,
|
|
54
|
+
r: BYTES,
|
|
55
|
+
s: BYTES,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
transactionIndex: natural,
|
|
60
|
+
...project(fields, {
|
|
61
|
+
hash: BYTES,
|
|
62
|
+
from: BYTES,
|
|
63
|
+
to: option(BYTES),
|
|
64
|
+
gas: withSentinel('Transaction.gas', -1n, QTY),
|
|
65
|
+
gasPrice: withSentinel('Transaction.gasPrice', -1n, QTY),
|
|
66
|
+
maxFeePerGas: option(QTY),
|
|
67
|
+
maxPriorityFeePerGas: option(QTY),
|
|
68
|
+
input: BYTES,
|
|
69
|
+
nonce: withSentinel('Transaction.nonce', -1, natural),
|
|
70
|
+
value: withSentinel('Transaction.value', -1n, QTY),
|
|
71
|
+
v: withSentinel('Transaction.v', -1n, QTY),
|
|
72
|
+
r: withSentinel('Transaction.r', '0x', BYTES),
|
|
73
|
+
s: withSentinel('Transaction.s', '0x', BYTES),
|
|
74
|
+
yParity: option(natural),
|
|
75
|
+
chainId: option(natural),
|
|
76
|
+
authorizationList: option(array(Authorization)),
|
|
77
|
+
}),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function getTxReceiptProps(fields: FieldSelection['transaction'], forArchive: boolean) {
|
|
82
|
+
let natural = forArchive ? NAT : SMALL_QTY
|
|
83
|
+
return project(fields, {
|
|
84
|
+
gasUsed: withSentinel('Receipt.gasUsed', -1n, QTY),
|
|
85
|
+
cumulativeGasUsed: withSentinel('Receipt.cumulativeGasUsed', -1n, QTY),
|
|
86
|
+
effectiveGasPrice: withSentinel('Receipt.effectiveGasPrice', -1n, QTY),
|
|
87
|
+
contractAddress: option(BYTES),
|
|
88
|
+
type: withSentinel('Receipt.type', -1, natural),
|
|
89
|
+
status: withSentinel('Receipt.status', -1, natural),
|
|
90
|
+
l1Fee: option(QTY),
|
|
91
|
+
l1FeeScalar: option(STRING_FLOAT),
|
|
92
|
+
l1GasPrice: option(QTY),
|
|
93
|
+
l1GasUsed: option(QTY),
|
|
94
|
+
l1BlobBaseFee: option(QTY),
|
|
95
|
+
l1BlobBaseFeeScalar: option(natural),
|
|
96
|
+
l1BaseFeeScalar: option(natural),
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function getLogProps(fields: FieldSelection['log'], forArchive: boolean) {
|
|
101
|
+
let natural = forArchive ? NAT : SMALL_QTY
|
|
102
|
+
return {
|
|
103
|
+
logIndex: natural,
|
|
104
|
+
transactionIndex: natural,
|
|
105
|
+
...project(fields, {
|
|
106
|
+
transactionHash: BYTES,
|
|
107
|
+
address: BYTES,
|
|
108
|
+
data: BYTES,
|
|
109
|
+
topics: array(BYTES),
|
|
110
|
+
}),
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function getTraceFrameValidator(fields: FieldSelection['trace'], forArchive: boolean) {
|
|
115
|
+
let traceBase = {
|
|
116
|
+
transactionIndex: forArchive ? NAT : undefined,
|
|
117
|
+
traceAddress: array(NAT),
|
|
118
|
+
...project(fields, {
|
|
119
|
+
subtraces: NAT,
|
|
120
|
+
error: option(STRING),
|
|
121
|
+
revertReason: option(STRING),
|
|
122
|
+
}),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let traceCreateAction = project(
|
|
126
|
+
{
|
|
127
|
+
from: fields?.createFrom || !forArchive,
|
|
128
|
+
value: fields?.createValue,
|
|
129
|
+
gas: fields?.createGas,
|
|
130
|
+
init: fields?.createInit,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
from: BYTES,
|
|
134
|
+
value: QTY,
|
|
135
|
+
gas: QTY,
|
|
136
|
+
init: withDefault('0x', BYTES),
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
let traceCreateResult = project(
|
|
141
|
+
{
|
|
142
|
+
gasUsed: fields?.createResultGasUsed,
|
|
143
|
+
code: fields?.createResultCode,
|
|
144
|
+
address: fields?.createResultAddress,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
gasUsed: QTY,
|
|
148
|
+
code: withDefault('0x', BYTES),
|
|
149
|
+
address: withDefault('0x0000000000000000000000000000000000000000', BYTES),
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
let TraceCreate = object({
|
|
154
|
+
...traceBase,
|
|
155
|
+
action: isEmpty(traceCreateAction) ? undefined : object(traceCreateAction),
|
|
156
|
+
result: isEmpty(traceCreateResult) ? undefined : option(object(traceCreateResult)),
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
let traceCallAction = project(
|
|
160
|
+
{
|
|
161
|
+
callType: fields?.callCallType,
|
|
162
|
+
from: forArchive ? fields?.callFrom : true,
|
|
163
|
+
to: forArchive ? fields?.callTo : true,
|
|
164
|
+
value: fields?.callValue,
|
|
165
|
+
gas: fields?.callGas,
|
|
166
|
+
input: forArchive ? fields?.callInput : true,
|
|
167
|
+
sighash: forArchive ? fields?.callSighash : false,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
callType: STRING,
|
|
171
|
+
from: BYTES,
|
|
172
|
+
to: BYTES,
|
|
173
|
+
value: option(QTY),
|
|
174
|
+
gas: QTY,
|
|
175
|
+
input: BYTES,
|
|
176
|
+
sighash: withDefault('0x', BYTES),
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
let traceCallResult = project(
|
|
181
|
+
{
|
|
182
|
+
gasUsed: fields?.callResultGasUsed,
|
|
183
|
+
output: fields?.callResultOutput,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
gasUsed: QTY,
|
|
187
|
+
output: withDefault('0x', BYTES),
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
let TraceCall = object({
|
|
192
|
+
...traceBase,
|
|
193
|
+
action: isEmpty(traceCallAction) ? undefined : object(traceCallAction),
|
|
194
|
+
result: isEmpty(traceCallResult) ? undefined : option(object(traceCallResult)),
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
let traceSuicideAction = project(
|
|
198
|
+
{
|
|
199
|
+
address: fields?.suicideAddress,
|
|
200
|
+
refundAddress: forArchive ? fields?.suicideRefundAddress : true,
|
|
201
|
+
balance: fields?.suicideBalance,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
address: BYTES,
|
|
205
|
+
refundAddress: BYTES,
|
|
206
|
+
balance: QTY,
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
let TraceSuicide = object({
|
|
211
|
+
...traceBase,
|
|
212
|
+
action: isEmpty(traceSuicideAction) ? undefined : object(traceSuicideAction),
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
let traceRewardAction = project(
|
|
216
|
+
{
|
|
217
|
+
author: forArchive ? fields?.rewardAuthor : true,
|
|
218
|
+
value: fields?.rewardValue,
|
|
219
|
+
type: fields?.rewardType,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
author: BYTES,
|
|
223
|
+
value: QTY,
|
|
224
|
+
type: STRING,
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
let TraceReward = object({
|
|
229
|
+
...traceBase,
|
|
230
|
+
action: isEmpty(traceRewardAction) ? undefined : object(traceRewardAction),
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
return taggedUnion('type', {
|
|
234
|
+
create: TraceCreate,
|
|
235
|
+
call: TraceCall,
|
|
236
|
+
suicide: TraceSuicide,
|
|
237
|
+
reward: TraceReward,
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function project<T extends object, F extends {[K in keyof T]?: boolean}>(
|
|
242
|
+
fields: F | undefined,
|
|
243
|
+
obj: T
|
|
244
|
+
): Partial<T> {
|
|
245
|
+
if (fields == null) return {}
|
|
246
|
+
let result: Partial<T> = {}
|
|
247
|
+
let key: keyof T
|
|
248
|
+
for (key in obj) {
|
|
249
|
+
if (fields[key]) {
|
|
250
|
+
result[key] = obj[key]
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return result
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function isEmpty(obj: object): boolean {
|
|
257
|
+
for (let _ in obj) {
|
|
258
|
+
return false
|
|
259
|
+
}
|
|
260
|
+
return true
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function assertAssignable<A, B extends A>(): void {}
|
package/src/source.ts
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import {applyRangeBound, mergeRangeRequests, Range, RangeRequest} from '@subsquid/util-internal-range'
|
|
2
|
+
import {PortalClient, PortalStreamData} from '@subsquid/portal-client'
|
|
3
|
+
import {weakMemo} from '@subsquid/util-internal'
|
|
4
|
+
import {array, BYTES, cast, NAT, object, STRING, taggedUnion, withDefault} from '@subsquid/util-internal-validation'
|
|
5
|
+
import {
|
|
6
|
+
getBlockHeaderProps,
|
|
7
|
+
getTxProps,
|
|
8
|
+
getTxReceiptProps,
|
|
9
|
+
getLogProps,
|
|
10
|
+
getTraceFrameValidator,
|
|
11
|
+
project,
|
|
12
|
+
} from './schema'
|
|
13
|
+
import {
|
|
14
|
+
BlockData,
|
|
15
|
+
DataRequest,
|
|
16
|
+
EvmQueryOptions,
|
|
17
|
+
FieldSelection,
|
|
18
|
+
mergeDataRequests,
|
|
19
|
+
MergeFieldSelection,
|
|
20
|
+
mergeSelection,
|
|
21
|
+
Response,
|
|
22
|
+
} from './query'
|
|
23
|
+
import {DataSource, DataSourceStream, DataSourceStreamData} from '@subsquid/data-source'
|
|
24
|
+
|
|
25
|
+
export interface EvmPortalDataSourceOptions<Q extends EvmQueryOptions> {
|
|
26
|
+
portal: string | PortalClient
|
|
27
|
+
query: Q
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class EvmPortalDataSource<
|
|
31
|
+
Q extends EvmQueryOptions,
|
|
32
|
+
B extends BlockData<GetFields<Q['fields']>> = BlockData<GetFields<Q['fields']>>
|
|
33
|
+
> implements DataSource<B>
|
|
34
|
+
{
|
|
35
|
+
private portal: PortalClient
|
|
36
|
+
private fields: Q['fields']
|
|
37
|
+
private requests: RangeRequest<DataRequest>[]
|
|
38
|
+
|
|
39
|
+
constructor(options: EvmPortalDataSourceOptions<Q>) {
|
|
40
|
+
this.portal = typeof options.portal === 'string' ? new PortalClient({url: options.portal}) : options.portal
|
|
41
|
+
this.fields = options.query.fields
|
|
42
|
+
this.requests = mergeRangeRequests(options.query.requests, mergeDataRequests)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getHeight(): Promise<number> {
|
|
46
|
+
return this.portal.getFinalizedHeight()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getFinalizedHeight(): Promise<number> {
|
|
50
|
+
return this.portal.getFinalizedHeight()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getBlockStream(range?: Range, stopOnHead?: boolean): DataSourceStream<B> {
|
|
54
|
+
let fields = getFields(this.fields)
|
|
55
|
+
let requests = applyRangeBound(this.requests, range)
|
|
56
|
+
|
|
57
|
+
let {writable, readable} = new TransformStream<
|
|
58
|
+
PortalStreamData<BlockData<typeof fields>>,
|
|
59
|
+
DataSourceStreamData<B>
|
|
60
|
+
>({
|
|
61
|
+
transform: async (data, controller) => {
|
|
62
|
+
let blocks = data.map((b) => {
|
|
63
|
+
let block = mapBlock(b, fields)
|
|
64
|
+
Object.defineProperty(block, DataSource.blockRef, {
|
|
65
|
+
value: {hash: block.header.hash, number: block.header.number},
|
|
66
|
+
})
|
|
67
|
+
return block
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
Object.defineProperty(blocks, DataSource.finalizedHead, {
|
|
71
|
+
value: data[PortalClient.finalizedHead],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
controller.enqueue(blocks as DataSourceStreamData<B>)
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const ingest = async () => {
|
|
79
|
+
for (let request of requests) {
|
|
80
|
+
let query = {
|
|
81
|
+
type: 'evm',
|
|
82
|
+
fromBlock: request.range.from,
|
|
83
|
+
toBlock: request.range.to,
|
|
84
|
+
fields,
|
|
85
|
+
...request.request,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await this.portal.getFinalizedStream(query, {stopOnHead}).pipeTo(writable, {
|
|
89
|
+
preventClose: true,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
ingest()
|
|
95
|
+
.then(
|
|
96
|
+
() => writable.close(),
|
|
97
|
+
(reason) => writable.abort(reason)
|
|
98
|
+
)
|
|
99
|
+
.catch(() => {})
|
|
100
|
+
|
|
101
|
+
return readable
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const getBlockValidator = weakMemo(<F extends FieldSelection>(fields: F) => {
|
|
106
|
+
let BlockHeader = object(getBlockHeaderProps(fields.block, true))
|
|
107
|
+
|
|
108
|
+
let Transaction = object({
|
|
109
|
+
hash: fields.transaction?.hash ? BYTES : undefined,
|
|
110
|
+
...getTxProps(fields.transaction, true),
|
|
111
|
+
sighash: fields.transaction?.sighash ? withDefault('0x', BYTES) : undefined,
|
|
112
|
+
...getTxReceiptProps(fields.transaction, true),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
let Log = object(getLogProps(fields.log, true))
|
|
116
|
+
|
|
117
|
+
let Trace = getTraceFrameValidator(fields.trace, true)
|
|
118
|
+
|
|
119
|
+
let stateDiffBase = {
|
|
120
|
+
transactionIndex: NAT,
|
|
121
|
+
address: BYTES,
|
|
122
|
+
key: STRING,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let StateDiff = taggedUnion('kind', {
|
|
126
|
+
['=']: object({...stateDiffBase}),
|
|
127
|
+
['+']: object({...stateDiffBase, ...project(fields.stateDiff, {next: BYTES})}),
|
|
128
|
+
['*']: object({...stateDiffBase, ...project(fields.stateDiff, {prev: BYTES, next: BYTES})}),
|
|
129
|
+
['-']: object({...stateDiffBase, ...project(fields.stateDiff, {prev: BYTES})}),
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
return object({
|
|
133
|
+
header: BlockHeader,
|
|
134
|
+
transactions: withDefault([], array(Transaction)),
|
|
135
|
+
logs: withDefault([], array(Log)),
|
|
136
|
+
traces: withDefault([], array(Trace)),
|
|
137
|
+
stateDiffs: withDefault([], array(StateDiff)),
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
export function mapBlock<F extends FieldSelection, B extends BlockData<F> = BlockData<F>>(
|
|
142
|
+
rawBlock: unknown,
|
|
143
|
+
fields: F
|
|
144
|
+
): B {
|
|
145
|
+
let validator = getBlockValidator(fields)
|
|
146
|
+
let block = cast(validator, rawBlock)
|
|
147
|
+
|
|
148
|
+
// let {number, hash, parentHash, ...hdr} = src.header
|
|
149
|
+
// if (hdr.timestamp) {
|
|
150
|
+
// hdr.timestamp = hdr.timestamp * 1000 // convert to ms
|
|
151
|
+
// }
|
|
152
|
+
|
|
153
|
+
// let header = new BlockHeader(number, hash, parentHash)
|
|
154
|
+
// Object.assign(header, hdr)
|
|
155
|
+
|
|
156
|
+
// let block = new Block(header)
|
|
157
|
+
|
|
158
|
+
// if (src.transactions) {
|
|
159
|
+
// for (let {transactionIndex, ...props} of src.transactions) {
|
|
160
|
+
// let tx = new Transaction(header, transactionIndex)
|
|
161
|
+
// Object.assign(tx, props)
|
|
162
|
+
// block.transactions.push(tx)
|
|
163
|
+
// }
|
|
164
|
+
// }
|
|
165
|
+
|
|
166
|
+
// if (src.logs) {
|
|
167
|
+
// for (let {logIndex, transactionIndex, ...props} of src.logs) {
|
|
168
|
+
// let log = new Log(header, logIndex, transactionIndex)
|
|
169
|
+
// Object.assign(log, props)
|
|
170
|
+
// block.logs.push(log)
|
|
171
|
+
// }
|
|
172
|
+
// }
|
|
173
|
+
|
|
174
|
+
// if (src.traces) {
|
|
175
|
+
// for (let {transactionIndex, traceAddress, type, ...props} of src.traces) {
|
|
176
|
+
// transactionIndex = assertNotNull(transactionIndex)
|
|
177
|
+
// let trace: Trace
|
|
178
|
+
// switch (type) {
|
|
179
|
+
// case 'create':
|
|
180
|
+
// trace = new TraceCreate(header, transactionIndex, traceAddress)
|
|
181
|
+
// break
|
|
182
|
+
// case 'call':
|
|
183
|
+
// trace = new TraceCall(header, transactionIndex, traceAddress)
|
|
184
|
+
// break
|
|
185
|
+
// case 'suicide':
|
|
186
|
+
// trace = new TraceSuicide(header, transactionIndex, traceAddress)
|
|
187
|
+
// break
|
|
188
|
+
// case 'reward':
|
|
189
|
+
// trace = new TraceReward(header, transactionIndex, traceAddress)
|
|
190
|
+
// break
|
|
191
|
+
// default:
|
|
192
|
+
// throw unexpectedCase()
|
|
193
|
+
// }
|
|
194
|
+
// Object.assign(trace, props)
|
|
195
|
+
// block.traces.push(trace)
|
|
196
|
+
// }
|
|
197
|
+
// }
|
|
198
|
+
|
|
199
|
+
// if (src.stateDiffs) {
|
|
200
|
+
// for (let {transactionIndex, address, key, kind, ...props} of src.stateDiffs) {
|
|
201
|
+
// let diff: StateDiff
|
|
202
|
+
// switch (kind) {
|
|
203
|
+
// case '=':
|
|
204
|
+
// diff = new StateDiffNoChange(header, transactionIndex, address, key)
|
|
205
|
+
// break
|
|
206
|
+
// case '+':
|
|
207
|
+
// diff = new StateDiffAdd(header, transactionIndex, address, key)
|
|
208
|
+
// break
|
|
209
|
+
// case '*':
|
|
210
|
+
// diff = new StateDiffChange(header, transactionIndex, address, key)
|
|
211
|
+
// break
|
|
212
|
+
// case '-':
|
|
213
|
+
// diff = new StateDiffDelete(header, transactionIndex, address, key)
|
|
214
|
+
// break
|
|
215
|
+
// default:
|
|
216
|
+
// throw unexpectedCase()
|
|
217
|
+
// }
|
|
218
|
+
// Object.assign(diff, props)
|
|
219
|
+
// block.stateDiffs.push(diff)
|
|
220
|
+
// }
|
|
221
|
+
// }
|
|
222
|
+
|
|
223
|
+
// setUpRelations(block)
|
|
224
|
+
|
|
225
|
+
return block as unknown as B
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function getFields<T extends FieldSelection>(fields: T): GetFields<T> {
|
|
229
|
+
return mergeSelection(REQUIRED_FIELDS, fields)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
type GetFields<F extends FieldSelection> = MergeFieldSelection<ReqiredFieldSelection, F>
|
|
233
|
+
|
|
234
|
+
// type A = BlockData<GetFields<{}>>['header']
|
|
235
|
+
|
|
236
|
+
type ReqiredFieldSelection = typeof REQUIRED_FIELDS
|
|
237
|
+
|
|
238
|
+
const REQUIRED_FIELDS = {
|
|
239
|
+
block: {
|
|
240
|
+
number: true,
|
|
241
|
+
hash: true,
|
|
242
|
+
parentHash: true,
|
|
243
|
+
},
|
|
244
|
+
// transaction: {
|
|
245
|
+
// transactionIndex: true,
|
|
246
|
+
// },
|
|
247
|
+
// log: {
|
|
248
|
+
// logIndex: true,
|
|
249
|
+
// transactionIndex: true,
|
|
250
|
+
// },
|
|
251
|
+
// trace: {
|
|
252
|
+
// transactionIndex: true,
|
|
253
|
+
// traceAddress: true,
|
|
254
|
+
// type: true,
|
|
255
|
+
// },
|
|
256
|
+
// stateDiff: {
|
|
257
|
+
// transactionIndex: true,
|
|
258
|
+
// address: true,
|
|
259
|
+
// key: true,
|
|
260
|
+
// },
|
|
261
|
+
} as const satisfies FieldSelection
|