@subsquid/solana-stream 0.1.4 → 0.2.0-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.
Files changed (84) hide show
  1. package/lib/index.d.ts +2 -3
  2. package/lib/index.d.ts.map +1 -1
  3. package/lib/index.js +2 -3
  4. package/lib/index.js.map +1 -1
  5. package/lib/instruction.d.ts +2 -3
  6. package/lib/instruction.d.ts.map +1 -1
  7. package/lib/instruction.js +2 -2
  8. package/lib/instruction.js.map +1 -1
  9. package/lib/query.d.ts +46 -0
  10. package/lib/query.d.ts.map +1 -0
  11. package/lib/query.js +161 -0
  12. package/lib/query.js.map +1 -0
  13. package/lib/{archive/schema.d.ts → schema.d.ts} +30 -19
  14. package/lib/schema.d.ts.map +1 -0
  15. package/lib/{archive/schema.js → schema.js} +54 -38
  16. package/lib/schema.js.map +1 -0
  17. package/lib/source.d.ts +24 -101
  18. package/lib/source.d.ts.map +1 -1
  19. package/lib/source.js +67 -270
  20. package/lib/source.js.map +1 -1
  21. package/package.json +11 -16
  22. package/src/index.ts +2 -3
  23. package/src/instruction.ts +4 -9
  24. package/src/query.ts +192 -0
  25. package/src/{archive/schema.ts → schema.ts} +52 -34
  26. package/src/source.ts +94 -365
  27. package/README.md +0 -4
  28. package/lib/archive/schema.d.ts.map +0 -1
  29. package/lib/archive/schema.js.map +0 -1
  30. package/lib/archive/source.d.ts +0 -15
  31. package/lib/archive/source.d.ts.map +0 -1
  32. package/lib/archive/source.js +0 -98
  33. package/lib/archive/source.js.map +0 -1
  34. package/lib/data/fields.d.ts +0 -8
  35. package/lib/data/fields.d.ts.map +0 -1
  36. package/lib/data/fields.js +0 -46
  37. package/lib/data/fields.js.map +0 -1
  38. package/lib/data/model.d.ts +0 -79
  39. package/lib/data/model.d.ts.map +0 -1
  40. package/lib/data/model.js +0 -44
  41. package/lib/data/model.js.map +0 -1
  42. package/lib/data/partial.d.ts +0 -26
  43. package/lib/data/partial.d.ts.map +0 -1
  44. package/lib/data/partial.js +0 -3
  45. package/lib/data/partial.js.map +0 -1
  46. package/lib/data/request.d.ts +0 -106
  47. package/lib/data/request.d.ts.map +0 -1
  48. package/lib/data/request.js +0 -3
  49. package/lib/data/request.js.map +0 -1
  50. package/lib/data/type-util.d.ts +0 -20
  51. package/lib/data/type-util.d.ts.map +0 -1
  52. package/lib/data/type-util.js +0 -3
  53. package/lib/data/type-util.js.map +0 -1
  54. package/lib/rpc/client.d.ts +0 -17
  55. package/lib/rpc/client.d.ts.map +0 -1
  56. package/lib/rpc/client.js +0 -15
  57. package/lib/rpc/client.js.map +0 -1
  58. package/lib/rpc/filter.d.ts +0 -4
  59. package/lib/rpc/filter.d.ts.map +0 -1
  60. package/lib/rpc/filter.js +0 -351
  61. package/lib/rpc/filter.js.map +0 -1
  62. package/lib/rpc/mapping.d.ts +0 -5
  63. package/lib/rpc/mapping.d.ts.map +0 -1
  64. package/lib/rpc/mapping.js +0 -12
  65. package/lib/rpc/mapping.js.map +0 -1
  66. package/lib/rpc/project.d.ts +0 -5
  67. package/lib/rpc/project.d.ts.map +0 -1
  68. package/lib/rpc/project.js +0 -60
  69. package/lib/rpc/project.js.map +0 -1
  70. package/lib/rpc/source.d.ts +0 -15
  71. package/lib/rpc/source.d.ts.map +0 -1
  72. package/lib/rpc/source.js +0 -82
  73. package/lib/rpc/source.js.map +0 -1
  74. package/src/archive/source.ts +0 -105
  75. package/src/data/fields.ts +0 -50
  76. package/src/data/model.ts +0 -154
  77. package/src/data/partial.ts +0 -31
  78. package/src/data/request.ts +0 -140
  79. package/src/data/type-util.ts +0 -42
  80. package/src/rpc/client.ts +0 -26
  81. package/src/rpc/filter.ts +0 -362
  82. package/src/rpc/mapping.ts +0 -13
  83. package/src/rpc/project.ts +0 -61
  84. package/src/rpc/source.ts +0 -90
package/src/rpc/filter.ts DELETED
@@ -1,362 +0,0 @@
1
- import {
2
- Balance,
3
- Block,
4
- Instruction,
5
- LogMessage,
6
- Reward,
7
- TokenBalance,
8
- Transaction
9
- } from '@subsquid/solana-normalization'
10
- import {bisect, def, groupBy, weakMemo} from '@subsquid/util-internal'
11
- import {EntityFilter, FilterBuilder} from '@subsquid/util-internal-processor-tools'
12
- import assert from 'assert'
13
- import {
14
- BalanceRequestRelations,
15
- DataRequest,
16
- InstructionRequestRelations,
17
- LogRequestRelations,
18
- TokenBalanceRequestRelations,
19
- TransactionRequestRelations
20
- } from '../data/request'
21
- import {getInstructionDescriptor} from '../instruction'
22
-
23
-
24
- function buildTransactionFilter(dataRequest: DataRequest): EntityFilter<Transaction, TransactionRequestRelations> {
25
- let items = new EntityFilter()
26
- for (let req of dataRequest.transactions ?? []) {
27
- let filter = new FilterBuilder<Transaction>()
28
- let where = req.where || {}
29
- filter.getIn(tx => tx.accountKeys[0], where.feePayer)
30
- items.add(filter, req.include || {})
31
- }
32
- return items
33
- }
34
-
35
-
36
- function buildInstructionFilter(dataRequest: DataRequest): EntityFilter<Instruction, InstructionRequestRelations> {
37
- let items = new EntityFilter()
38
- for (let req of dataRequest.instructions ?? []) {
39
- let filter = new FilterBuilder<Instruction>()
40
- let where = req.where || {}
41
- filter.propIn('programId', where.programId)
42
- filter.matchAny((i, d) => getInstructionDescriptor(i).startsWith(d), where.d1)
43
- filter.matchAny((i, d) => getInstructionDescriptor(i).startsWith(d), where.d2)
44
- filter.matchAny((i, d) => getInstructionDescriptor(i).startsWith(d), where.d4)
45
- filter.getIn(getInstructionDescriptor, where.d8)
46
- filter.getIn(i => i.accounts[0], where.a0)
47
- filter.getIn(i => i.accounts[1], where.a1)
48
- filter.getIn(i => i.accounts[2], where.a2)
49
- filter.getIn(i => i.accounts[3], where.a3)
50
- filter.getIn(i => i.accounts[4], where.a4)
51
- filter.getIn(i => i.accounts[5], where.a5)
52
- filter.getIn(i => i.accounts[6], where.a6)
53
- filter.getIn(i => i.accounts[7], where.a7)
54
- filter.getIn(i => i.accounts[8], where.a8)
55
- filter.getIn(i => i.accounts[9], where.a9)
56
- if (where.isCommitted != null) {
57
- filter.propIn('isCommitted', [where.isCommitted])
58
- }
59
- items.add(filter, req.include ?? {})
60
- }
61
- return items
62
- }
63
-
64
-
65
- function buildLogFilter(dataRequest: DataRequest): EntityFilter<LogMessage, LogRequestRelations> {
66
- let items = new EntityFilter()
67
- for (let req of dataRequest.logs ?? []) {
68
- let filter = new FilterBuilder<LogMessage>()
69
- let where = req.where ?? {}
70
- filter.propIn('programId', where.programId)
71
- filter.propIn('kind', where.kind)
72
- items.add(filter, req.include ?? {})
73
- }
74
- return items
75
- }
76
-
77
-
78
- function buildBalanceFilter(dataRequest: DataRequest): EntityFilter<Balance, BalanceRequestRelations> {
79
- let items = new EntityFilter()
80
- for (let req of dataRequest.balances ?? []) {
81
- let filter = new FilterBuilder<Balance>()
82
- let where = req.where || {}
83
- filter.propIn('account', where.account)
84
- items.add(filter, req.include || {})
85
- }
86
- return items
87
- }
88
-
89
-
90
- function buildTokenBalanceFilter(dataRequest: DataRequest): EntityFilter<TokenBalance, TokenBalanceRequestRelations> {
91
- let items = new EntityFilter()
92
- for (let req of dataRequest.tokenBalances ?? []) {
93
- let filter = new FilterBuilder<TokenBalance>()
94
- let where = req.where || {}
95
- filter.propIn('account', where.account)
96
- filter.propIn('preProgramId', where.preProgramId)
97
- filter.propIn('postProgramId', where.postProgramId)
98
- filter.propIn('preMint', where.preMint)
99
- filter.propIn('postMint', where.postMint)
100
- filter.propIn('preOwner', where.preOwner)
101
- filter.propIn('postOwner', where.postOwner)
102
- items.add(filter, req.include || {})
103
- }
104
- return items
105
- }
106
-
107
-
108
- function buildRewardsFilter(dataRequest: DataRequest): EntityFilter<Reward, {}> {
109
- let items = new EntityFilter()
110
- for (let req of dataRequest.rewards ?? []) {
111
- let filter = new FilterBuilder<Reward>()
112
- let where = req.where || {}
113
- filter.propIn('pubkey', where.pubkey)
114
- items.add(filter, {})
115
- }
116
- return items
117
- }
118
-
119
-
120
- const getItemFilters = weakMemo((req: DataRequest) => {
121
- return {
122
- transactions: buildTransactionFilter(req),
123
- instructions: buildInstructionFilter(req),
124
- logs: buildLogFilter(req),
125
- balances: buildBalanceFilter(req),
126
- tokenBalances: buildTokenBalanceFilter(req),
127
- rewards: buildRewardsFilter(req)
128
- }
129
- })
130
-
131
-
132
- class IncludeSet {
133
- transactions = new Set<Transaction>
134
- instructions = new Set<Instruction>
135
- logs = new Set<LogMessage>
136
- balances = new Set<Balance>
137
- tokenBalances = new Set<TokenBalance>
138
- rewards = new Set<Reward>
139
- }
140
-
141
-
142
- export function filterBlockItems(block: Block, req: DataRequest): void {
143
- new BlockFilter(block, req).apply()
144
- }
145
-
146
-
147
- class BlockFilter {
148
- private include = new IncludeSet()
149
- private items: ReturnType<typeof getItemFilters>
150
-
151
- constructor(private block: Block, req: DataRequest) {
152
- this.items = getItemFilters(req)
153
- }
154
-
155
- @def
156
- private transactions(): Map<number, Transaction> {
157
- return new Map(this.block.transactions.map(tx => [tx.transactionIndex, tx]))
158
- }
159
-
160
- private getTransaction(idx: number): Transaction {
161
- let tx = this.transactions().get(idx)
162
- assert(tx)
163
- return tx
164
- }
165
-
166
- @def
167
- private logsByTx(): Map<number, LogMessage[]> {
168
- return groupBy(this.block.logs, log => log.transactionIndex)
169
- }
170
-
171
- @def
172
- private instructionsByTx(): Map<number, Instruction[]> {
173
- return groupBy(this.block.instructions, i => i.transactionIndex)
174
- }
175
-
176
- @def
177
- private balancesByTx(): Map<number, Balance[]> {
178
- return groupBy(this.block.balances, b => b.transactionIndex)
179
- }
180
-
181
- @def
182
- private tokenBalancesByTx(): Map<number, TokenBalance[]> {
183
- return groupBy(this.block.tokenBalances, b => b.transactionIndex)
184
- }
185
-
186
- private filterTransactions(): void {
187
- if (!this.items.transactions.present()) return
188
- for (let tx of this.block.transactions) {
189
- let rel = this.items.transactions.match(tx)
190
- if (rel == null) continue
191
- this.include.transactions.add(tx)
192
- if (rel.logs) {
193
- include(this.include.logs, this.logsByTx().get(tx.transactionIndex))
194
- }
195
- if (rel.instructions) {
196
- include(this.include.instructions, this.instructionsByTx().get(tx.transactionIndex))
197
- }
198
- }
199
- }
200
-
201
- private filterInstructions(): void {
202
- if (!this.items.instructions.present()) return
203
- for (let i = 0; i < this.block.instructions.length; i++) {
204
- let ins = this.block.instructions[i]
205
- let rel = this.items.instructions.match(ins)
206
- if (rel == null) continue
207
- this.include.instructions.add(ins)
208
- if (rel.innerInstructions) {
209
- for (let j = i + 1; j < this.block.instructions.length; j++) {
210
- let child = this.block.instructions[j]
211
- if (
212
- ins.transactionIndex == child.transactionIndex &&
213
- isChildAddress(ins.instructionAddress, child.instructionAddress)
214
- ) {
215
- this.include.instructions.add(child)
216
- } else {
217
- break
218
- }
219
- }
220
- }
221
- if (rel.logs) {
222
- let logs = this.logsByTx().get(ins.transactionIndex) ?? []
223
- include(this.include.logs, findInstructionChildren(logs, ins.instructionAddress))
224
- }
225
- if (rel.transaction) {
226
- this.include.transactions.add(this.getTransaction(ins.transactionIndex))
227
- }
228
- if (rel.transactionBalances) {
229
- include(this.include.balances, this.balancesByTx().get(ins.transactionIndex))
230
- }
231
- if (rel.transactionTokenBalances) {
232
- include(this.include.tokenBalances, this.tokenBalancesByTx().get(ins.transactionIndex))
233
- }
234
- if (rel.transactionInstructions) {
235
- include(this.include.instructions, this.instructionsByTx().get(ins.transactionIndex))
236
- }
237
- }
238
- }
239
-
240
- private filterLogs(): void {
241
- if (!this.items.logs.present()) return
242
- for (let log of this.block.logs) {
243
- let rel = this.items.logs.match(log)
244
- if (rel == null) continue
245
- this.include.logs.add(log)
246
- if (rel.transaction) {
247
- this.include.transactions.add(this.getTransaction(log.transactionIndex))
248
- }
249
- if (rel.instruction) {
250
- this.include.instructions.add(this.getInstruction(log.transactionIndex, log.instructionAddress))
251
- }
252
- }
253
- }
254
-
255
- private getInstruction(transactionIdx: number, address: number[]): Instruction {
256
- let pos = bisect(
257
- this.block.instructions,
258
- null,
259
- ins => ins.transactionIndex - transactionIdx || addressCompare(ins.instructionAddress, address)
260
- )
261
- let ins = this.block.instructions[pos]
262
- assert(
263
- ins &&
264
- ins.transactionIndex == transactionIdx &&
265
- addressCompare(ins.instructionAddress, address) == 0
266
- )
267
- return ins
268
- }
269
-
270
- private filterTokenBalances(): void {
271
- if (!this.items.tokenBalances.present()) return
272
- for (let balance of this.block.tokenBalances) {
273
- let rel = this.items.tokenBalances.match(balance)
274
- if (rel == null) continue
275
- this.include.tokenBalances.add(balance)
276
- if (rel.transaction) {
277
- this.include.transactions.add(this.getTransaction(balance.transactionIndex))
278
- }
279
- if (rel.transactionInstructions) {
280
- include(this.include.instructions, this.instructionsByTx().get(balance.transactionIndex))
281
- }
282
- }
283
- }
284
-
285
- private filterBalances(): void {
286
- if (!this.items.balances.present()) return
287
- for (let balance of this.block.balances) {
288
- let rel = this.items.balances.match(balance)
289
- if (rel == null) continue
290
- this.include.balances.add(balance)
291
- if (rel.transaction) {
292
- this.include.transactions.add(this.getTransaction(balance.transactionIndex))
293
- }
294
- if (rel.transactionInstructions) {
295
- include(this.include.instructions, this.instructionsByTx().get(balance.transactionIndex))
296
- }
297
- }
298
- }
299
-
300
- private filterRewards(): void {
301
- if (!this.items.rewards.present() || this.block.rewards == null) return
302
- for (let reward of this.block.rewards) {
303
- if (this.items.rewards.match(reward)) {
304
- this.include.rewards.add(reward)
305
- }
306
- }
307
- }
308
-
309
- apply(): void {
310
- this.filterTransactions()
311
- this.filterInstructions()
312
- this.filterLogs()
313
- this.filterBalances()
314
- this.filterTokenBalances()
315
- this.filterRewards()
316
- this.block.transactions = this.block.transactions.filter(i => this.include.transactions.has(i))
317
- this.block.instructions = this.block.instructions.filter(i => this.include.instructions.has(i))
318
- this.block.logs = this.block.logs.filter(i => this.include.logs.has(i))
319
- this.block.balances = this.block.balances.filter(i => this.include.balances.has(i))
320
- this.block.tokenBalances = this.block.tokenBalances.filter(i => this.include.tokenBalances.has(i))
321
- this.block.rewards = this.block.rewards.filter(i => this.include.rewards.has(i))
322
- }
323
- }
324
-
325
-
326
- function include<T>(set: Set<T>, items?: Iterable<T>): void {
327
- if (items == null) return
328
- for (let it of items) {
329
- set.add(it)
330
- }
331
- }
332
-
333
-
334
- function* findInstructionChildren<I extends {instructionAddress: number[]}>(
335
- items: I[],
336
- addr: number[],
337
- ): Iterable<I> {
338
- if (items.length == 0) return
339
- let beg = bisect(items, addr, (ins, addr) => addressCompare(ins.instructionAddress, addr))
340
- while (beg < items.length && isChildAddress(items[beg].instructionAddress, addr)) {
341
- yield items[beg]
342
- beg += 1
343
- }
344
- }
345
-
346
-
347
- function isChildAddress(parent: number[], addr: number[]): boolean {
348
- if (parent.length > addr.length) return false
349
- for (let i = 0; i < parent.length; i++) {
350
- if (parent[i] !== addr[i]) return false
351
- }
352
- return true
353
- }
354
-
355
-
356
- function addressCompare(a: number[], b: number[]): number {
357
- for (let i = 0; i < Math.min(a.length, b.length); i++) {
358
- let order = a[i] - b[i]
359
- if (order) return order
360
- }
361
- return a.length - b.length
362
- }
@@ -1,13 +0,0 @@
1
- import {mapRpcBlock} from '@subsquid/solana-normalization'
2
- import type * as rpc from '@subsquid/solana-rpc-data'
3
- import {PartialBlock} from '../data/partial'
4
- import {DataRequest} from '../data/request'
5
- import {filterBlockItems} from './filter'
6
- import {projectFields} from './project'
7
-
8
-
9
- export function mapBlock(src: rpc.Block, req: DataRequest): PartialBlock {
10
- let block = mapRpcBlock(src)
11
- filterBlockItems(block, req)
12
- return projectFields(block, req.fields || {})
13
- }
@@ -1,61 +0,0 @@
1
- import {Block} from '@subsquid/solana-normalization'
2
- import {project} from '../data/fields'
3
- import {FieldSelection} from '../data/model'
4
- import {PartialBlock} from '../data/partial'
5
- import {D8_SYM, DATA_SYM} from '../instruction'
6
-
7
-
8
- export function projectFields(block: Block, fields: FieldSelection): PartialBlock {
9
- return {
10
- header: {
11
- height: block.header.height,
12
- hash: block.header.hash,
13
- parentHash: block.header.parentHash,
14
- ...project(fields.block, block.header)
15
- },
16
- transactions: block.transactions.map(tx => {
17
- return {
18
- transactionIndex: tx.transactionIndex,
19
- ...project(fields.transaction, tx)
20
- }
21
- }),
22
- instructions: block.instructions.map(i => {
23
- let ins = {
24
- transactionIndex: i.transactionIndex,
25
- instructionAddress: i.instructionAddress,
26
- ...project(fields.instruction, i)
27
- }
28
- ;(ins as any)[D8_SYM] = (i as any)[D8_SYM]
29
- ;(ins as any)[DATA_SYM] = (i as any)[DATA_SYM]
30
- return ins
31
- }),
32
- logs: block.logs.map(log => {
33
- return {
34
- transactionIndex: log.transactionIndex,
35
- logIndex: log.logIndex,
36
- instructionAddress: log.instructionAddress,
37
- ...project(fields.log, log)
38
- }
39
- }),
40
- balances: block.balances.map(b => {
41
- return {
42
- transactionIndex: b.transactionIndex,
43
- account: b.account,
44
- ...project(fields.balance, b)
45
- }
46
- }),
47
- tokenBalances: block.tokenBalances.map(b => {
48
- return {
49
- transactionIndex: b.transactionIndex,
50
- account: b.account,
51
- ...project(fields.tokenBalance, b)
52
- }
53
- }),
54
- rewards: block.rewards.map(r => {
55
- return {
56
- pubkey: r.pubkey,
57
- ...project(fields.reward, r)
58
- }
59
- })
60
- }
61
- }
package/src/rpc/source.ts DELETED
@@ -1,90 +0,0 @@
1
- import {Base58Bytes, BlockInfo, findSlot, GetBlock, ingestFinalizedBlocks, Rpc} from '@subsquid/solana-rpc'
2
- import {addErrorContext, wait} from '@subsquid/util-internal'
3
- import {getRequestAt, mapRangeRequestList, RangeRequestList} from '@subsquid/util-internal-range'
4
- import {PartialBlock} from '../data/partial'
5
- import {DataRequest} from '../data/request'
6
- import type {RpcSettings} from '../source'
7
- import {mapBlock} from './mapping'
8
-
9
-
10
- export class RpcDataSource {
11
- private rpc: Rpc
12
-
13
- constructor(private options: RpcSettings) {
14
- this.rpc = new Rpc(options.client)
15
- }
16
-
17
- getFinalizedHeight(): Promise<number> {
18
- return this.rpc.getFinalizedHeight()
19
- }
20
-
21
- async getBlockInfo(slot: number): Promise<BlockInfo | undefined> {
22
- let attempts = 10
23
- while (attempts) {
24
- let block = await this.rpc.getBlockInfo('finalized', slot)
25
- if (block || block === undefined) return block
26
- await wait(100)
27
- attempts -= 1
28
- }
29
- throw new Error(`Failed to getBlock with finalized commitment at slot ${slot} 10 times in a row`)
30
- }
31
-
32
- async getBlockHash(height: number): Promise<Base58Bytes | undefined> {
33
- let headSlot = await this.rpc.getTopSlot('finalized')
34
- let top = {
35
- slot: headSlot,
36
- height: await this.rpc.getFinalizedBlockHeight(headSlot)
37
- }
38
- if (top.height < height) return
39
- let bottom = {slot: 0, height: 0}
40
- let slot = await findSlot(this.rpc, height, bottom, top)
41
- let block = await this.rpc.getFinalizedBlockInfo(slot)
42
- return block.blockhash
43
- }
44
-
45
- async *getBlockStream(
46
- requests: RangeRequestList<DataRequest>,
47
- stopOnHead?: boolean | undefined
48
- ): AsyncIterable<PartialBlock[]> {
49
- let blockStream = ingestFinalizedBlocks({
50
- requests: toRpcRequests(requests),
51
- stopOnHead,
52
- rpc: this.rpc,
53
- headPollInterval: 5_000,
54
- strideSize: this.options.strideSize ?? 5,
55
- strideConcurrency: this.options.strideConcurrency ?? 5,
56
- concurrentFetchThreshold: this.options.concurrentFetchThreshold ?? 50
57
- })
58
-
59
- for await (let batch of blockStream) {
60
- let req = getRequestAt(requests, batch[0].height) || {}
61
- yield batch.map(block => {
62
- try {
63
- return mapBlock(block, req)
64
- } catch(err: any) {
65
- throw addErrorContext(err, {
66
- blockHash: block.hash,
67
- blockHeight: block.height,
68
- blockSlot: block.slot
69
- })
70
- }
71
- })
72
- }
73
- }
74
- }
75
-
76
-
77
- function toRpcRequests(requests: RangeRequestList<DataRequest>) {
78
- return mapRangeRequestList(requests, req => {
79
- let rewards = req.rewards?.length
80
- let transactions = req.instructions?.length
81
- || req.transactions?.length
82
- || req.tokenBalances?.length
83
- || req.balances?.length
84
- || req.logs?.length
85
- return {
86
- rewards: !!rewards,
87
- transactions: !!transactions
88
- }
89
- })
90
- }