@xyo-network/xl1-protocol-sdk 1.17.0 → 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/dist/neutral/ChainServiceCollectionV2.d.ts +6 -29
  2. package/dist/neutral/ChainServiceCollectionV2.d.ts.map +1 -1
  3. package/dist/neutral/block/hydrate/flattenHydratedBlocks.d.ts +2 -3
  4. package/dist/neutral/block/hydrate/flattenHydratedBlocks.d.ts.map +1 -1
  5. package/dist/neutral/index.d.ts +2 -0
  6. package/dist/neutral/index.d.ts.map +1 -1
  7. package/dist/neutral/index.mjs +1455 -1124
  8. package/dist/neutral/index.mjs.map +1 -1
  9. package/dist/neutral/model/PayloadBundle/bundledPayloadToHydratedBlock.d.ts +4 -0
  10. package/dist/neutral/model/PayloadBundle/bundledPayloadToHydratedBlock.d.ts.map +1 -0
  11. package/dist/neutral/model/PayloadBundle/hydratedBlockToPayloadBundle.d.ts +4 -0
  12. package/dist/neutral/model/PayloadBundle/hydratedBlockToPayloadBundle.d.ts.map +1 -0
  13. package/dist/neutral/model/PayloadBundle/index.d.ts +2 -0
  14. package/dist/neutral/model/PayloadBundle/index.d.ts.map +1 -1
  15. package/dist/neutral/model/Qualified.d.ts +6 -0
  16. package/dist/neutral/model/Qualified.d.ts.map +1 -0
  17. package/dist/neutral/model/index.d.ts +1 -1
  18. package/dist/neutral/model/index.d.ts.map +1 -1
  19. package/dist/neutral/payloads/index.d.ts +0 -1
  20. package/dist/neutral/payloads/index.d.ts.map +1 -1
  21. package/dist/neutral/primitives/index.d.ts +1 -1
  22. package/dist/neutral/primitives/index.d.ts.map +1 -1
  23. package/dist/neutral/primitives/rewardFromBlockNumber.d.ts +3 -0
  24. package/dist/neutral/primitives/rewardFromBlockNumber.d.ts.map +1 -0
  25. package/dist/neutral/provider/XyoRunner.d.ts +5 -1
  26. package/dist/neutral/provider/XyoRunner.d.ts.map +1 -1
  27. package/dist/neutral/provider/viewer/XyoViewer.d.ts +7 -2
  28. package/dist/neutral/provider/viewer/XyoViewer.d.ts.map +1 -1
  29. package/dist/neutral/runners/Block.d.ts +8 -0
  30. package/dist/neutral/runners/Block.d.ts.map +1 -0
  31. package/dist/neutral/runners/Mempool.d.ts +9 -0
  32. package/dist/neutral/runners/Mempool.d.ts.map +1 -0
  33. package/dist/neutral/runners/index.d.ts +3 -0
  34. package/dist/neutral/runners/index.d.ts.map +1 -0
  35. package/dist/neutral/services/BlockProducerService.d.ts +2 -2
  36. package/dist/neutral/services/BlockProducerService.d.ts.map +1 -1
  37. package/dist/neutral/services/Chain/ChainService.d.ts +2 -3
  38. package/dist/neutral/services/Chain/ChainService.d.ts.map +1 -1
  39. package/dist/neutral/services/Chain/index.d.ts +0 -1
  40. package/dist/neutral/services/Chain/index.d.ts.map +1 -1
  41. package/dist/neutral/services/index.d.ts +0 -2
  42. package/dist/neutral/services/index.d.ts.map +1 -1
  43. package/dist/neutral/simple/accountBalance/SimpleAccountBalanceViewer.d.ts +7 -3
  44. package/dist/neutral/simple/accountBalance/SimpleAccountBalanceViewer.d.ts.map +1 -1
  45. package/dist/neutral/simple/block/SimpleBlockViewer.d.ts +9 -4
  46. package/dist/neutral/simple/block/SimpleBlockViewer.d.ts.map +1 -1
  47. package/dist/neutral/simple/blockReward/SimpleBlockRewardViewer.d.ts +16 -0
  48. package/dist/neutral/simple/blockReward/SimpleBlockRewardViewer.d.ts.map +1 -0
  49. package/dist/neutral/simple/blockReward/index.d.ts +2 -0
  50. package/dist/neutral/simple/blockReward/index.d.ts.map +1 -0
  51. package/dist/neutral/simple/chain/SimpleChainViewer.d.ts +12 -0
  52. package/dist/neutral/simple/chain/SimpleChainViewer.d.ts.map +1 -0
  53. package/dist/neutral/simple/chain/index.d.ts +2 -0
  54. package/dist/neutral/simple/chain/index.d.ts.map +1 -0
  55. package/dist/neutral/simple/index.d.ts +2 -0
  56. package/dist/neutral/simple/index.d.ts.map +1 -1
  57. package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts +15 -0
  58. package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts.map +1 -0
  59. package/dist/neutral/simple/mempool/SimpleMempoolViewer.d.ts +10 -4
  60. package/dist/neutral/simple/mempool/SimpleMempoolViewer.d.ts.map +1 -1
  61. package/dist/neutral/simple/mempool/index.d.ts +1 -0
  62. package/dist/neutral/simple/mempool/index.d.ts.map +1 -1
  63. package/dist/neutral/summary/index.d.ts +3 -0
  64. package/dist/neutral/summary/index.d.ts.map +1 -0
  65. package/dist/neutral/summary/model/BalancesStepSummary.d.ts.map +1 -0
  66. package/dist/neutral/summary/model/SchemasStepSummary.d.ts.map +1 -0
  67. package/dist/neutral/summary/model/StepSummary.d.ts.map +1 -0
  68. package/dist/neutral/summary/model/TransfersSummary.d.ts.map +1 -0
  69. package/dist/neutral/{payloads/summary → summary/model}/index.d.ts +1 -0
  70. package/dist/neutral/summary/model/index.d.ts.map +1 -0
  71. package/dist/neutral/{model → summary/model}/summary.d.ts +3 -4
  72. package/dist/neutral/summary/model/summary.d.ts.map +1 -0
  73. package/dist/neutral/{primitives/summary → summary/primitives}/balances/balancesStepSummaryFromRange.d.ts +1 -2
  74. package/dist/neutral/summary/primitives/balances/balancesStepSummaryFromRange.d.ts.map +1 -0
  75. package/dist/neutral/summary/primitives/balances/balancesSummary.d.ts +5 -0
  76. package/dist/neutral/summary/primitives/balances/balancesSummary.d.ts.map +1 -0
  77. package/dist/neutral/summary/primitives/balances/index.d.ts.map +1 -0
  78. package/dist/neutral/{primitives/summary → summary/primitives}/index.d.ts.map +1 -1
  79. package/dist/neutral/summary/primitives/schemas/index.d.ts.map +1 -0
  80. package/dist/neutral/{primitives/summary → summary/primitives}/schemas/schemasStepSummaryFromRange.d.ts +1 -2
  81. package/dist/neutral/summary/primitives/schemas/schemasStepSummaryFromRange.d.ts.map +1 -0
  82. package/dist/neutral/summary/primitives/schemas/schemasSummary.d.ts +5 -0
  83. package/dist/neutral/summary/primitives/schemas/schemasSummary.d.ts.map +1 -0
  84. package/dist/neutral/summary/primitives/transfers/index.d.ts.map +1 -0
  85. package/dist/neutral/{primitives/summary → summary/primitives}/transfers/transfersStepSummaryFromRange.d.ts +1 -2
  86. package/dist/neutral/summary/primitives/transfers/transfersStepSummaryFromRange.d.ts.map +1 -0
  87. package/dist/neutral/summary/primitives/transfers/transfersSummary.d.ts +6 -0
  88. package/dist/neutral/summary/primitives/transfers/transfersSummary.d.ts.map +1 -0
  89. package/dist/neutral/viewers/AccountBalance.d.ts +5 -2
  90. package/dist/neutral/viewers/AccountBalance.d.ts.map +1 -1
  91. package/dist/neutral/viewers/Block.d.ts +3 -0
  92. package/dist/neutral/viewers/Block.d.ts.map +1 -1
  93. package/dist/neutral/viewers/BlockReward.d.ts +8 -0
  94. package/dist/neutral/viewers/BlockReward.d.ts.map +1 -0
  95. package/dist/neutral/viewers/ChainStakeViewer.d.ts +6 -0
  96. package/dist/neutral/viewers/ChainStakeViewer.d.ts.map +1 -0
  97. package/dist/neutral/viewers/Mempool.d.ts +8 -1
  98. package/dist/neutral/viewers/Mempool.d.ts.map +1 -1
  99. package/dist/neutral/viewers/StakeIntent.d.ts +10 -0
  100. package/dist/neutral/viewers/StakeIntent.d.ts.map +1 -0
  101. package/dist/neutral/viewers/index.d.ts +2 -0
  102. package/dist/neutral/viewers/index.d.ts.map +1 -1
  103. package/package.json +20 -19
  104. package/src/ChainServiceCollectionV2.ts +9 -33
  105. package/src/block/hydrate/flattenHydratedBlocks.ts +2 -3
  106. package/src/index.ts +2 -1
  107. package/src/model/PayloadBundle/bundledPayloadToHydratedBlock.ts +14 -0
  108. package/src/model/PayloadBundle/hydratedBlockToPayloadBundle.ts +18 -0
  109. package/src/model/PayloadBundle/index.ts +2 -0
  110. package/src/model/Qualified.ts +9 -0
  111. package/src/model/index.ts +1 -1
  112. package/src/payloads/index.ts +0 -1
  113. package/src/primitives/index.ts +1 -1
  114. package/src/primitives/rewardFromBlockNumber.ts +25 -0
  115. package/src/provider/XyoRunner.ts +7 -1
  116. package/src/provider/viewer/XyoViewer.ts +13 -4
  117. package/src/runners/Block.ts +10 -0
  118. package/src/runners/Mempool.ts +9 -0
  119. package/src/runners/index.ts +2 -0
  120. package/src/services/BlockProducerService.ts +3 -2
  121. package/src/services/Chain/ChainService.ts +4 -3
  122. package/src/services/Chain/index.ts +0 -1
  123. package/src/services/index.ts +0 -2
  124. package/src/simple/accountBalance/SimpleAccountBalanceViewer.ts +99 -13
  125. package/src/simple/block/SimpleBlockViewer.ts +60 -21
  126. package/src/simple/blockReward/SimpleBlockRewardViewer.ts +34 -0
  127. package/src/simple/blockReward/index.ts +1 -0
  128. package/src/simple/chain/SimpleChainViewer.ts +25 -0
  129. package/src/simple/chain/index.ts +1 -0
  130. package/src/simple/gateway/SimpleXyoGatewayRunner.ts +1 -1
  131. package/src/simple/index.ts +2 -0
  132. package/src/simple/mempool/SimpleMempoolRunner.ts +47 -0
  133. package/src/simple/mempool/SimpleMempoolViewer.ts +34 -8
  134. package/src/simple/mempool/index.ts +1 -0
  135. package/src/simple/timesync/SimpleTimeSyncViewer.ts +1 -1
  136. package/src/summary/index.ts +2 -0
  137. package/src/{payloads/summary → summary/model}/index.ts +1 -0
  138. package/src/{model → summary/model}/summary.ts +5 -4
  139. package/src/{primitives/summary → summary/primitives}/balances/balancesStepSummaryFromRange.ts +4 -3
  140. package/src/{primitives/summary → summary/primitives}/balances/balancesSummary.ts +6 -5
  141. package/src/{primitives/summary → summary/primitives}/schemas/schemasStepSummaryFromRange.ts +3 -3
  142. package/src/{primitives/summary → summary/primitives}/schemas/schemasSummary.ts +7 -6
  143. package/src/{primitives/summary → summary/primitives}/transfers/transfersStepSummaryFromRange.ts +4 -3
  144. package/src/{primitives/summary → summary/primitives}/transfers/transfersSummary.ts +6 -5
  145. package/src/viewers/AccountBalance.ts +9 -2
  146. package/src/viewers/Block.ts +3 -0
  147. package/src/viewers/BlockReward.ts +9 -0
  148. package/src/viewers/ChainStakeViewer.ts +7 -0
  149. package/src/viewers/Mempool.ts +10 -1
  150. package/src/viewers/StakeIntent.ts +14 -0
  151. package/src/viewers/index.ts +2 -0
  152. package/dist/neutral/model/summary.d.ts.map +0 -1
  153. package/dist/neutral/payloads/summary/BalancesStepSummary.d.ts.map +0 -1
  154. package/dist/neutral/payloads/summary/SchemasStepSummary.d.ts.map +0 -1
  155. package/dist/neutral/payloads/summary/StepSummary.d.ts.map +0 -1
  156. package/dist/neutral/payloads/summary/TransfersSummary.d.ts.map +0 -1
  157. package/dist/neutral/payloads/summary/index.d.ts.map +0 -1
  158. package/dist/neutral/primitives/summary/balances/balancesStepSummaryFromRange.d.ts.map +0 -1
  159. package/dist/neutral/primitives/summary/balances/balancesSummary.d.ts +0 -4
  160. package/dist/neutral/primitives/summary/balances/balancesSummary.d.ts.map +0 -1
  161. package/dist/neutral/primitives/summary/balances/index.d.ts.map +0 -1
  162. package/dist/neutral/primitives/summary/schemas/index.d.ts.map +0 -1
  163. package/dist/neutral/primitives/summary/schemas/schemasStepSummaryFromRange.d.ts.map +0 -1
  164. package/dist/neutral/primitives/summary/schemas/schemasSummary.d.ts +0 -4
  165. package/dist/neutral/primitives/summary/schemas/schemasSummary.d.ts.map +0 -1
  166. package/dist/neutral/primitives/summary/transfers/index.d.ts.map +0 -1
  167. package/dist/neutral/primitives/summary/transfers/transfersStepSummaryFromRange.d.ts.map +0 -1
  168. package/dist/neutral/primitives/summary/transfers/transfersSummary.d.ts +0 -5
  169. package/dist/neutral/primitives/summary/transfers/transfersSummary.d.ts.map +0 -1
  170. package/dist/neutral/services/BlockRewardService.d.ts +0 -5
  171. package/dist/neutral/services/BlockRewardService.d.ts.map +0 -1
  172. package/dist/neutral/services/BlockRewardServiceV2.d.ts +0 -6
  173. package/dist/neutral/services/BlockRewardServiceV2.d.ts.map +0 -1
  174. package/dist/neutral/services/Chain/interfaces/ChainStakeViewer.d.ts +0 -4
  175. package/dist/neutral/services/Chain/interfaces/ChainStakeViewer.d.ts.map +0 -1
  176. package/dist/neutral/services/Chain/interfaces/ChainStaker.d.ts +0 -6
  177. package/dist/neutral/services/Chain/interfaces/ChainStaker.d.ts.map +0 -1
  178. package/dist/neutral/services/Chain/interfaces/index.d.ts +0 -3
  179. package/dist/neutral/services/Chain/interfaces/index.d.ts.map +0 -1
  180. package/src/services/BlockRewardService.ts +0 -6
  181. package/src/services/BlockRewardServiceV2.ts +0 -8
  182. package/src/services/Chain/interfaces/ChainStakeViewer.ts +0 -7
  183. package/src/services/Chain/interfaces/ChainStaker.ts +0 -5
  184. package/src/services/Chain/interfaces/index.ts +0 -2
  185. /package/dist/neutral/{payloads/summary → summary/model}/BalancesStepSummary.d.ts +0 -0
  186. /package/dist/neutral/{payloads/summary → summary/model}/SchemasStepSummary.d.ts +0 -0
  187. /package/dist/neutral/{payloads/summary → summary/model}/StepSummary.d.ts +0 -0
  188. /package/dist/neutral/{payloads/summary → summary/model}/TransfersSummary.d.ts +0 -0
  189. /package/dist/neutral/{primitives/summary → summary/primitives}/balances/index.d.ts +0 -0
  190. /package/dist/neutral/{primitives/summary → summary/primitives}/index.d.ts +0 -0
  191. /package/dist/neutral/{primitives/summary → summary/primitives}/schemas/index.d.ts +0 -0
  192. /package/dist/neutral/{primitives/summary → summary/primitives}/transfers/index.d.ts +0 -0
  193. /package/src/{payloads/summary → summary/model}/BalancesStepSummary.ts +0 -0
  194. /package/src/{payloads/summary → summary/model}/SchemasStepSummary.ts +0 -0
  195. /package/src/{payloads/summary → summary/model}/StepSummary.ts +0 -0
  196. /package/src/{payloads/summary → summary/model}/TransfersSummary.ts +0 -0
  197. /package/src/{primitives/summary → summary/primitives}/balances/index.ts +0 -0
  198. /package/src/{primitives/summary → summary/primitives}/index.ts +0 -0
  199. /package/src/{primitives/summary → summary/primitives}/schemas/index.ts +0 -0
  200. /package/src/{primitives/summary → summary/primitives}/transfers/index.ts +0 -0
@@ -3,6 +3,7 @@ import type {
3
3
  } from '@xylabs/sdk-js'
4
4
  import {
5
5
  AbstractCreatable,
6
+ asHash,
6
7
  assertEx, exists, isDefined,
7
8
  } from '@xylabs/sdk-js'
8
9
  import { spanRootAsync } from '@xylabs/telemetry'
@@ -17,9 +18,15 @@ import {
17
18
  } from '@xyo-network/xl1-protocol'
18
19
 
19
20
  import { deepCalculateFramesFromRange } from '../../block/index.ts'
20
- import type { BalanceStepSummaryContext, TransfersStepSummaryContext } from '../../model/index.ts'
21
- import type { TransfersStepSummary } from '../../payloads/index.ts'
22
- import { balancesSummary, transfersStepSummaryFromRange } from '../../primitives/index.ts'
21
+ import type { Qualified } from '../../model/index.ts'
22
+ import type {
23
+ BalanceStepSummaryContext, TransfersStepSummary,
24
+ TransfersStepSummaryContext,
25
+ } from '../../summary/index.ts'
26
+ import {
27
+ balancesSummary,
28
+ transfersStepSummaryFromRange,
29
+ } from '../../summary/index.ts'
23
30
  import type {
24
31
  AccountBalanceHistoryItem, AccountBalanceViewer, BlockViewer,
25
32
  } from '../../viewers/index.ts'
@@ -52,10 +59,14 @@ export class SimpleAccountBalanceViewer extends AbstractCreatable<SimpleAccountB
52
59
  }
53
60
 
54
61
  async accountBalance(address: Address, headOrRange?: XL1BlockRange | Hash): Promise<AttoXL1> {
55
- const balances = await this.accountsBalances([address], headOrRange)
62
+ const balances = await this.accountBalances([address], headOrRange)
56
63
  return balances[address] ?? AttoXL1(0n)
57
64
  }
58
65
 
66
+ accountBalanceHistories(_addresses: Address[], _rangeOrHash?: XL1BlockRange | Hash): Promise<Record<Address, AccountBalanceHistoryItem[]>> {
67
+ throw new Error('Method [accountBalanceHistories] not implemented.')
68
+ }
69
+
59
70
  async accountBalanceHistory(address: Address, headOrRange?: XL1BlockRange | Hash): Promise<AccountBalanceHistoryItem[]> {
60
71
  const range = asRange(headOrRange)
61
72
  const startingRange = asXL1BlockRange(range ?? [0, await this.blockViewer.currentBlockNumber()], true)
@@ -84,24 +95,64 @@ export class SimpleAccountBalanceViewer extends AbstractCreatable<SimpleAccountB
84
95
  return result
85
96
  }
86
97
 
87
- async accountsBalances(address: Address[], _headOrRange?: XL1BlockRange | Hash): Promise<Partial<Record<Address, AttoXL1>>> {
88
- return await spanRootAsync('balances', async () => {
89
- const summary = await balancesSummary(
98
+ async accountBalances(address: Address[], _headOrRange?: XL1BlockRange | Hash): Promise<Record<Address, AttoXL1>> {
99
+ const [result] = (await this.qualifiedAccountBalances(address, _headOrRange))
100
+ return result
101
+ }
102
+
103
+ async qualifiedAccountBalanceHistories(
104
+ addresses: Address[],
105
+ headOrRange?: Hash | XL1BlockRange,
106
+ ): Promise<Qualified<Record<Address, AccountBalanceHistoryItem[]>>> {
107
+ const head = asHash(headOrRange) ?? await this.blockViewer.currentBlockHash()
108
+ const range = asXL1BlockRange(headOrRange) ?? asXL1BlockRange([0,
109
+ assertEx(
110
+ await this.blockViewer.blockByHash(head),
111
+ () => `Error: Could not find block with hash ${head}`,
112
+ )[0].block])
113
+ const qualifiedEntries: [Address, Qualified<AccountBalanceHistoryItem[]>][] = await Promise.all(addresses.map(async address => ([
114
+ address,
115
+ await this.qualifiedAccountBalanceHistory(address, range),
116
+ ])))
117
+
118
+ const entries = qualifiedEntries.map(([address, [history]]) => {
119
+ return [address, history]
120
+ })
121
+ const qualifiedRange = qualifiedEntries[0][1][1]
122
+ const qualifiedHeadHash = qualifiedEntries[0][1][2]
123
+
124
+ // check for drift
125
+ for (const [_, [__, range, headHash]] of qualifiedEntries) {
126
+ assertEx(
127
+ range[0] === qualifiedRange[0] && range[1] === qualifiedRange[1],
128
+ () => 'Inconsistent ranges in qualifiedAccountBalanceHistories',
129
+ )
130
+ assertEx(
131
+ headHash === qualifiedHeadHash,
132
+ () => 'Inconsistent head hashes in qualifiedAccountBalanceHistories',
133
+ )
134
+ }
135
+
136
+ return [Object.fromEntries(entries), qualifiedRange, qualifiedHeadHash]
137
+ }
138
+
139
+ async qualifiedAccountBalances(
140
+ address: Address[],
141
+ _headOrRange?: Hash | XL1BlockRange,
142
+ ): Promise<Qualified<Record<Address, AttoXL1>>> {
143
+ return await spanRootAsync('qualifiedAccountsBalances', async () => {
144
+ const qualifiedSummary = await balancesSummary(
90
145
  this.context,
91
146
  )
92
147
  const result: Record<Address, AttoXL1> = {}
93
148
  for (const addr of address) {
94
- const summaryBalance = summary[addr] ?? 0n
149
+ const summaryBalance = qualifiedSummary[0][addr] ?? 0n
95
150
  result[addr] = AttoXL1(summaryBalance < 0n ? 0n : summaryBalance)
96
151
  }
97
- return result
152
+ return [result, qualifiedSummary[1], qualifiedSummary[2]]
98
153
  })
99
154
  }
100
155
 
101
- accountsBalancesHistory(_addresses: Address[], _rangeOrHash?: XL1BlockRange | Hash): Promise<Partial<Record<Address, AccountBalanceHistoryItem[]>>> {
102
- throw new Error('Method not implemented.')
103
- }
104
-
105
156
  private async distillTransferHistory(address: Address, range: XL1BlockRange, max: number = 50): Promise<XL1BlockNumber[]> {
106
157
  if ((range[1] - range[0]) <= StepSizes[0] || max <= 1) {
107
158
  return Array.from({ length: range[1] - range[0] + 1 }, (_, i) => range[1] - i).slice(0, max).map(n => asXL1BlockNumber(n, true))
@@ -139,4 +190,39 @@ export class SimpleAccountBalanceViewer extends AbstractCreatable<SimpleAccountB
139
190
  }
140
191
  return [...resultBlockNumbers].toSorted((a, b) => b - a).slice(0, max)
141
192
  }
193
+
194
+ private async qualifiedAccountBalanceHistory(
195
+ address: Address,
196
+ headOrRange?: Hash | XL1BlockRange,
197
+ ): Promise<Qualified<AccountBalanceHistoryItem[]>> {
198
+ const range = asRange(headOrRange)
199
+ const headHash = asHash(headOrRange)
200
+ const [head] = assertEx(isDefined(headHash)
201
+ ? (await this.blockViewer.blockByHash(headHash))
202
+ : (await this.blockViewer.currentBlock()), () => 'Could not resolve head block')
203
+ const startingRange = asXL1BlockRange(range ?? [0, head.block], true)
204
+ const blockNumbers = await this.distillTransferHistory(address, startingRange)
205
+ const blocks = (await Promise.all(blockNumbers.map(async bn => await this.blockViewer.blockByNumber(bn)))).filter(exists)
206
+ const result: AccountBalanceHistoryItem[] = []
207
+ for (const block of blocks) {
208
+ const transferIndexes = block[0].payload_schemas.map((schema, index) => schema === TransferSchema ? index : undefined).filter(exists)
209
+ const transfers = transferIndexes.map((index) => {
210
+ const hash = block[0].payload_hashes[index]
211
+ return assertEx(
212
+ block[1].find(p => p._hash === hash) as WithStorageMeta<Transfer>,
213
+ () => `Error: Could not find Transfer with hash ${hash} in block ${block[0]._hash}`,
214
+ )
215
+ }).filter(exists).filter(t => ((t.from === address) || (isDefined(t.transfers[address]))))
216
+ if (transfers.length === 0) {
217
+ continue
218
+ }
219
+ const pairs: [SignedBlockBoundWitnessWithHashMeta, WithHashMeta<Transfer>][] = (transfers.map((transfer) => {
220
+ return [block[0], transfer]
221
+ }))
222
+ result.push(...pairs.map(([block, transfer]) => [block,
223
+ null,
224
+ transfer] satisfies AccountBalanceHistoryItem))
225
+ }
226
+ return [result, startingRange, head._hash]
227
+ }
142
228
  }
@@ -2,30 +2,39 @@ import type { CreatableParams, Hash } from '@xylabs/sdk-js'
2
2
  import {
3
3
  AbstractCreatable,
4
4
  assertEx,
5
+ exists,
6
+ isDefined,
5
7
  spanRootAsync,
6
8
  } from '@xylabs/sdk-js'
7
9
  import type { ReadArchivist } from '@xyo-network/archivist-model'
10
+ import type { Payload, WithHashMeta } from '@xyo-network/payload-model'
8
11
  import {
9
12
  asSignedHydratedBlockWithHashMeta,
10
13
  asXL1BlockNumber,
11
- type SignedHydratedBlockWithHashMeta, type XL1BlockNumber,
14
+ type SignedHydratedBlockWithHashMeta,
15
+ type XL1BlockNumber,
12
16
  } from '@xyo-network/xl1-protocol'
13
17
 
14
18
  import { hydrateBlock } from '../../block/index.ts'
15
- import type { ChainStoreRead, StakedChainContextRead } from '../../model/index.ts'
19
+ import { LruCacheMap } from '../../driver/index.ts'
20
+ import type {
21
+ ChainContextRead,
22
+ ChainStoreRead, PayloadMap,
23
+ } from '../../model/index.ts'
16
24
  import { findMostRecentBlock, hydratedBlockByNumber } from '../../primitives/index.ts'
17
25
  import { HydratedCache } from '../../utils/index.ts'
18
26
  import type { BlockViewer } from '../../viewers/index.ts'
19
27
 
20
28
  export interface SimpleBlockViewerParams extends CreatableParams {
21
- context: StakedChainContextRead
29
+ context: ChainContextRead
22
30
  finalizedArchivist?: ReadArchivist
23
31
  }
24
32
 
25
33
  export class SimpleBlockViewer extends AbstractCreatable<SimpleBlockViewerParams> implements BlockViewer {
34
+ private _payloadCache: PayloadMap<WithHashMeta<Payload>> | undefined
26
35
  private _signedHydratedBlockCache: HydratedCache<SignedHydratedBlockWithHashMeta> | undefined
27
36
 
28
- get context(): StakedChainContextRead {
37
+ get context(): ChainContextRead {
29
38
  return this.params.context!
30
39
  }
31
40
 
@@ -33,6 +42,27 @@ export class SimpleBlockViewer extends AbstractCreatable<SimpleBlockViewerParams
33
42
  return this.params.finalizedArchivist!
34
43
  }
35
44
 
45
+ protected get hydratedBlockCache(): HydratedCache<SignedHydratedBlockWithHashMeta> {
46
+ if (this._signedHydratedBlockCache) return this._signedHydratedBlockCache
47
+ const chainMap = this.context.store.chainMap
48
+ this._signedHydratedBlockCache = new HydratedCache<SignedHydratedBlockWithHashMeta>(chainMap, async (
49
+ { chainMap }: ChainStoreRead,
50
+ hash: Hash,
51
+ maxDepth?: number,
52
+ minDepth?: number,
53
+ ) => {
54
+ const result = await hydrateBlock({ chainMap }, hash, maxDepth, minDepth)
55
+ return asSignedHydratedBlockWithHashMeta(result, true)
56
+ }, 200)
57
+ return this._signedHydratedBlockCache
58
+ }
59
+
60
+ protected get payloadCache(): PayloadMap<WithHashMeta<Payload>> {
61
+ if (this._payloadCache) return this._payloadCache
62
+ this._payloadCache = new LruCacheMap<Hash, WithHashMeta<Payload>>({ max: 10_000 })
63
+ return this._payloadCache
64
+ }
65
+
36
66
  static override async paramsHandler(params: Partial<SimpleBlockViewerParams>) {
37
67
  assertEx(params.context, () => 'context is required')
38
68
  assertEx(params.finalizedArchivist, () => 'finalizedArchivist is required')
@@ -42,7 +72,7 @@ export class SimpleBlockViewer extends AbstractCreatable<SimpleBlockViewerParams
42
72
 
43
73
  async blockByHash(hash: Hash): Promise<SignedHydratedBlockWithHashMeta | null> {
44
74
  return await spanRootAsync('blockByHash', async () => {
45
- const cache = this.getHydratedBlockCache()
75
+ const cache = this.hydratedBlockCache
46
76
  return await cache.get(hash)
47
77
  }, this.tracer)
48
78
  }
@@ -88,7 +118,7 @@ export class SimpleBlockViewer extends AbstractCreatable<SimpleBlockViewerParams
88
118
  async currentBlock(): Promise<SignedHydratedBlockWithHashMeta> {
89
119
  return await spanRootAsync('currentBlock', async () => {
90
120
  const currentHead = assertEx(await this.getCurrentHead(), () => 'Could not find most recent block')
91
- const cache = this.getHydratedBlockCache()
121
+ const cache = this.hydratedBlockCache
92
122
  const block = await cache.get(currentHead._hash)
93
123
  if (!block) {
94
124
  console.log(`Could not find current block with hash ${currentHead!._hash}`)
@@ -111,23 +141,32 @@ export class SimpleBlockViewer extends AbstractCreatable<SimpleBlockViewerParams
111
141
  }, this.tracer)
112
142
  }
113
143
 
144
+ async payloadByHash(hash: Hash): Promise<WithHashMeta<Payload> | null> {
145
+ const cachedPayload = await this.payloadCache.get(hash)
146
+ if (cachedPayload) {
147
+ return cachedPayload
148
+ } else {
149
+ const [result] = await this.finalizedArchivist.get([hash])
150
+ if (isDefined(result)) {
151
+ await this.payloadCache.set(hash, result)
152
+ }
153
+ return result ?? null
154
+ }
155
+ }
156
+
157
+ async payloadsByHash(hashes: Hash[]): Promise<WithHashMeta<Payload>[]> {
158
+ let remainingHashes = [...hashes]
159
+ const cachedPayloads = await this.payloadCache.getMany(remainingHashes)
160
+ const cachedHashes = new Set(cachedPayloads.map(p => p._hash))
161
+ remainingHashes = remainingHashes.filter(h => !cachedHashes.has(h))
162
+ const remainingPayloads = remainingHashes.length > 0
163
+ ? await this.finalizedArchivist.get(remainingHashes)
164
+ : []
165
+ return [...cachedPayloads, ...remainingPayloads.filter(exists)]
166
+ }
167
+
114
168
  protected async getCurrentHead() {
115
169
  const chainArchivist = this.finalizedArchivist
116
170
  return await findMostRecentBlock(chainArchivist)
117
171
  }
118
-
119
- protected getHydratedBlockCache(): HydratedCache<SignedHydratedBlockWithHashMeta> {
120
- if (this._signedHydratedBlockCache) return this._signedHydratedBlockCache
121
- const chainMap = this.context.store.chainMap
122
- this._signedHydratedBlockCache = new HydratedCache<SignedHydratedBlockWithHashMeta>(chainMap, async (
123
- { chainMap }: ChainStoreRead,
124
- hash: Hash,
125
- maxDepth?: number,
126
- minDepth?: number,
127
- ) => {
128
- const result = await hydrateBlock({ chainMap }, hash, maxDepth, minDepth)
129
- return asSignedHydratedBlockWithHashMeta(result, true)
130
- }, 200)
131
- return this._signedHydratedBlockCache
132
- }
133
172
  }
@@ -0,0 +1,34 @@
1
+ import {
2
+ AbstractCreatable,
3
+ creatable, CreatableParams, Promisable,
4
+ } from '@xylabs/sdk-js'
5
+ import { AttoXL1, XL1BlockNumber } from '@xyo-network/xl1-protocol'
6
+
7
+ import { rewardFromBlockNumber } from '../../primitives/index.ts'
8
+ import { BlockRewardViewer } from '../../viewers/index.ts'
9
+
10
+ export interface SimpleBlockRewardViewerParams extends CreatableParams {
11
+ creatorReward: AttoXL1
12
+ initialReward: AttoXL1
13
+ minRewardPerBlock: AttoXL1
14
+ stepFactorDenominator: bigint
15
+ stepFactorNumerator: bigint
16
+ stepSize: XL1BlockNumber
17
+ }
18
+
19
+ @creatable()
20
+ export class SimpleBlockRewardViewer extends AbstractCreatable<SimpleBlockRewardViewerParams> implements BlockRewardViewer {
21
+ protected rewardFromBlockNumber = rewardFromBlockNumber(18)
22
+
23
+ allowedRewardForBlock(block: XL1BlockNumber): Promisable<AttoXL1> {
24
+ return this.rewardFromBlockNumber(
25
+ block,
26
+ this.params.initialReward,
27
+ this.params.stepSize,
28
+ this.params.stepFactorNumerator,
29
+ this.params.stepFactorDenominator,
30
+ this.params.minRewardPerBlock,
31
+ this.params.creatorReward,
32
+ )
33
+ }
34
+ }
@@ -0,0 +1 @@
1
+ export * from './SimpleBlockRewardViewer.ts'
@@ -0,0 +1,25 @@
1
+ import {
2
+ type Address, asHex, Promisable,
3
+ } from '@xylabs/sdk-js'
4
+ import {
5
+ AbstractCreatable,
6
+ creatable, CreatableParams,
7
+ } from '@xylabs/sdk-js'
8
+ import { ChainId } from '@xyo-network/xl1-protocol'
9
+
10
+ import { ChainViewer } from '../../viewers/index.ts'
11
+
12
+ export interface SimpleChainParams extends CreatableParams {
13
+ chainId: Address
14
+ }
15
+
16
+ @creatable()
17
+ export class SimpleChainViewer extends AbstractCreatable<SimpleChainParams> implements ChainViewer {
18
+ static override async paramsHandler(params?: Partial<SimpleChainParams>) {
19
+ return ({ ...await super.paramsHandler(params), chainId: asHex(params?.chainId, () => 'chainId not set') }) as SimpleChainParams
20
+ }
21
+
22
+ chainId(): Promisable<ChainId> {
23
+ return this.params.chainId
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ export * from './SimpleChainViewer.ts'
@@ -43,7 +43,7 @@ export class SimpleXyoGatewayRunner implements XyoGatewayRunner {
43
43
  }
44
44
 
45
45
  get dataLakes(): DataLakeRunner[] {
46
- throw new Error('Method not implemented.')
46
+ throw new Error('Method [dataLakes] not implemented.')
47
47
  }
48
48
 
49
49
  get signerInstance(): XyoSigner {
@@ -1,9 +1,11 @@
1
1
  export * from './accountBalance/index.ts'
2
2
  export * from './block/index.ts'
3
+ export * from './blockReward/index.ts'
3
4
  export * from './chainStake/index.ts'
4
5
  export * from './client/index.ts'
5
6
  export * from './datalake/index.ts'
6
7
  export * from './gateway/index.ts'
8
+ export * from './mempool/index.ts'
7
9
  export * from './network/index.ts'
8
10
  export * from './permissions/index.ts'
9
11
  export * from './runner/index.ts'
@@ -0,0 +1,47 @@
1
+ import {
2
+ AbstractCreatable, creatable, CreatableParams, type Hash,
3
+ } from '@xylabs/sdk-js'
4
+ import type { ArchivistInstance } from '@xyo-network/archivist-model'
5
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
6
+ import { type SignedHydratedBlock, type SignedHydratedTransaction } from '@xyo-network/xl1-protocol'
7
+
8
+ import { hydratedBlockToPayloadBundle, hydratedTransactionToPayloadBundle } from '../../model/index.ts'
9
+ import type { MempoolRunner } from '../../runners/index.ts'
10
+
11
+ export interface SimpleMempoolRunnerParams extends CreatableParams {
12
+ pendingBlocksArchivist: ArchivistInstance
13
+ pendingTransactionsArchivist: ArchivistInstance
14
+ }
15
+
16
+ @creatable()
17
+ export class SimpleMempoolRunner extends AbstractCreatable<SimpleMempoolRunnerParams> implements MempoolRunner {
18
+ protected get pendingBlocksArchivist() {
19
+ return this.params.pendingBlocksArchivist
20
+ }
21
+
22
+ protected get pendingTransactionsArchivist() {
23
+ return this.params.pendingTransactionsArchivist
24
+ }
25
+
26
+ async submitBlocks(blocks: SignedHydratedBlock[]): Promise<Hash[]> {
27
+ const bundles = await Promise.all(blocks.map(async ([bw, payloads]) => {
28
+ return hydratedBlockToPayloadBundle([
29
+ await PayloadBuilder.addHashMeta(bw),
30
+ await PayloadBuilder.addHashMeta(payloads),
31
+ ])
32
+ }))
33
+ const inserted = await this.pendingBlocksArchivist.insert(bundles)
34
+ return inserted.map(p => p._hash)
35
+ }
36
+
37
+ async submitTransactions(transactions: SignedHydratedTransaction[]): Promise<Hash[]> {
38
+ const bundles = await Promise.all(transactions.map(async ([tx, payloads]) => {
39
+ return hydratedTransactionToPayloadBundle([
40
+ await PayloadBuilder.addHashMeta(tx),
41
+ await PayloadBuilder.addHashMeta(payloads),
42
+ ])
43
+ }))
44
+ const inserted = await this.pendingBlocksArchivist.insert(bundles)
45
+ return inserted.map(p => p._hash)
46
+ }
47
+ }
@@ -1,34 +1,60 @@
1
1
  import {
2
+ AbstractCreatable,
3
+ creatable,
4
+ CreatableParams,
2
5
  exists, isDefined, isHash,
3
6
  } from '@xylabs/sdk-js'
4
7
  import type { ArchivistInstance } from '@xyo-network/archivist-model'
5
8
  import {
6
9
  isHashMeta, isPayloadBundle, type Sequence,
7
10
  } from '@xyo-network/payload-model'
8
- import type { SignedHydratedTransactionWithHashMeta } from '@xyo-network/xl1-protocol'
11
+ import type { SignedHydratedBlockWithHashMeta, SignedHydratedTransactionWithHashMeta } from '@xyo-network/xl1-protocol'
9
12
 
10
- import { bundledPayloadToHydratedTransaction } from '../../model/index.ts'
13
+ import { bundledPayloadToHydratedBlock, bundledPayloadToHydratedTransaction } from '../../model/index.ts'
11
14
  import type {
12
15
  MempoolViewer,
13
16
  PendingTransactionsOptions,
14
17
  } from '../../viewers/index.ts'
15
18
 
16
- export class SimpleMempoolViewer implements MempoolViewer {
17
- protected readonly archivist: ArchivistInstance
19
+ export interface SimpleMempoolViewerParams extends CreatableParams {
20
+ pendingBlocksArchivist: ArchivistInstance
21
+ pendingTransactionsArchivist: ArchivistInstance
22
+ }
23
+
24
+ @creatable()
25
+ export class SimpleMempoolViewer extends AbstractCreatable<SimpleMempoolViewerParams> implements MempoolViewer {
26
+ protected get pendingBlocksArchivist() {
27
+ return this.params.pendingBlocksArchivist
28
+ }
18
29
 
19
- constructor(archivist: ArchivistInstance) {
20
- this.archivist = archivist
30
+ protected get pendingTransactionsArchivist() {
31
+ return this.params.pendingTransactionsArchivist
32
+ }
33
+
34
+ async pendingBlocks({ cursor: providedCursor }: PendingTransactionsOptions = {}): Promise<SignedHydratedBlockWithHashMeta[]> {
35
+ let cursor: Sequence | undefined = undefined
36
+ if (isHash(providedCursor)) {
37
+ const [p] = await this.pendingBlocksArchivist.get([providedCursor])
38
+ if (isDefined(p)) {
39
+ cursor = p._sequence
40
+ }
41
+ }
42
+ const bundles = await this.pendingBlocksArchivist.next({
43
+ order: 'asc', limit: 100, cursor,
44
+ })
45
+ const filteredBundles = bundles.filter(isPayloadBundle).filter(isHashMeta)
46
+ return (await Promise.all(filteredBundles.map(async bundle => await bundledPayloadToHydratedBlock(bundle)))).filter(exists)
21
47
  }
22
48
 
23
49
  async pendingTransactions({ cursor: providedCursor }: PendingTransactionsOptions = {}): Promise<SignedHydratedTransactionWithHashMeta[]> {
24
50
  let cursor: Sequence | undefined = undefined
25
51
  if (isHash(providedCursor)) {
26
- const [p] = await this.archivist.get([providedCursor])
52
+ const [p] = await this.pendingTransactionsArchivist.get([providedCursor])
27
53
  if (isDefined(p)) {
28
54
  cursor = p._sequence
29
55
  }
30
56
  }
31
- const bundles = await this.archivist.next({
57
+ const bundles = await this.pendingTransactionsArchivist.next({
32
58
  order: 'asc', limit: 100, cursor,
33
59
  })
34
60
  const filteredBundles = bundles.filter(isPayloadBundle).filter(isHashMeta)
@@ -1 +1,2 @@
1
+ export * from './SimpleMempoolRunner.ts'
1
2
  export * from './SimpleMempoolViewer.ts'
@@ -88,6 +88,6 @@ export class SimpleTimeSyncViewer implements TimeSyncViewer {
88
88
  }
89
89
 
90
90
  currentTimePayload(): Promisable<TimePayload> {
91
- throw new Error('Method not implemented.')
91
+ throw new Error('Method [currentTimePayload] not implemented.')
92
92
  }
93
93
  }
@@ -0,0 +1,2 @@
1
+ export * from './model/index.ts'
2
+ export * from './primitives/index.ts'
@@ -1,4 +1,5 @@
1
1
  export * from './BalancesStepSummary.ts'
2
2
  export * from './SchemasStepSummary.ts'
3
3
  export * from './StepSummary.ts'
4
+ export * from './summary.ts'
4
5
  export * from './TransfersSummary.ts'
@@ -1,10 +1,11 @@
1
1
  import type { Payload } from '@xyo-network/payload-model'
2
2
  import type { Semaphore } from 'async-mutex'
3
3
 
4
- import type { MapTypeRead, MapTypeWrite } from '../map/index.ts'
5
- import type { SchemasStepSummary } from '../payloads/index.ts'
6
- import type { BalancesStepSummary, TransfersStepSummary } from '../payloads/summary/index.ts'
7
- import type { BaseContext, ChainContextRead } from './index.ts'
4
+ import type { MapTypeRead, MapTypeWrite } from '../../map/index.ts'
5
+ import type { BaseContext, ChainContextRead } from '../../model/index.ts'
6
+ import type {
7
+ BalancesStepSummary, SchemasStepSummary, TransfersStepSummary,
8
+ } from './index.ts'
8
9
 
9
10
  export interface ChainSummaryContextBase<TPayload extends Payload,
10
11
  T extends (MapTypeRead<string, TPayload> | MapTypeWrite<string, TPayload>)> extends BaseContext {
@@ -11,12 +11,13 @@ import {
11
11
  deepCalculateFramesFromRange, hashFromBlockNumber,
12
12
  hydrateBlock,
13
13
  } from '../../../block/index.ts'
14
- import type { BalanceStepSummaryContext } from '../../../model/index.ts'
15
- import type { BalancesStepSummary } from '../../../payloads/index.ts'
16
- import { BalancesStepSummarySchema, netBalancesForPayloads } from '../../../payloads/index.ts'
14
+ import { netBalancesForPayloads } from '../../../payloads/index.ts'
17
15
  import {
18
16
  parseSignedBigInt, type SignedBigInt, toSignedBigInt,
19
17
  } from '../../../SignedBigInt.ts'
18
+ import {
19
+ type BalancesStepSummary, BalancesStepSummarySchema, type BalanceStepSummaryContext,
20
+ } from '../../model/index.ts'
20
21
 
21
22
  export async function balancesStepSummaryFromRange(
22
23
  context: BalanceStepSummaryContext,
@@ -6,30 +6,31 @@ import {
6
6
  } from '@xyo-network/xl1-protocol'
7
7
 
8
8
  import { deepCalculateFramesFromRange } from '../../../block/index.ts'
9
- import type { BalanceStepSummaryContext } from '../../../model/index.ts'
9
+ import type { Qualified } from '../../../model/index.ts'
10
10
  import { parseSignedBigInt } from '../../../SignedBigInt.ts'
11
+ import type { BalanceStepSummaryContext } from '../../model/index.ts'
11
12
  import { balancesStepSummaryFromRange } from './balancesStepSummaryFromRange.ts'
12
13
 
13
14
  export async function balancesSummary(
14
15
  context: BalanceStepSummaryContext,
15
- ): Promise<Partial<Record<Address, bigint>>> {
16
+ ): Promise<Qualified<Record<Address, bigint>>> {
16
17
  return await spanRootAsync('balancesSummary', async () => {
17
18
  const [headHash] = await context.head()
18
19
  const headResult = await context.store.chainMap.get(headHash)
19
20
  const headBoundWitness = asBlockBoundWitnessWithStorageMeta(headResult, () => `Head block not found for hash: ${headHash}`)
20
- const rangeStart = asXL1BlockNumber(isDefined(context.windowSize) ? Math.max(headBoundWitness.block - context.windowSize + 1, 0) : 0)
21
+ const rangeStart = asXL1BlockNumber(isDefined(context.windowSize) ? Math.max(headBoundWitness.block - context.windowSize + 1, 0) : 0, true)
21
22
  const ranges = deepCalculateFramesFromRange(asXL1BlockRange(
22
23
  [rangeStart, headBoundWitness.block],
23
24
  { name: 'balancesSummary' },
24
25
  ))
25
26
  const summaries = await Promise.all(ranges.map(range => balancesStepSummaryFromRange(context, range)))
26
- const balances: Partial<Record<Address, bigint>> = {}
27
+ const balances: Record<Address, bigint> = {}
27
28
  for (let summary of summaries) {
28
29
  for (const [address, balance] of Object.entries(summary.balances)) {
29
30
  const validAddress = asAddress(address, () => `Invalid address: ${address}`)
30
31
  balances[validAddress] = (balances[validAddress] ?? 0n) + parseSignedBigInt(balance)
31
32
  }
32
33
  }
33
- return balances
34
+ return [balances, [rangeStart, headBoundWitness.block], headHash]
34
35
  })
35
36
  }
@@ -12,9 +12,9 @@ import {
12
12
  deepCalculateFramesFromRange, hashFromBlockNumber,
13
13
  hydrateBlock,
14
14
  } from '../../../block/index.ts'
15
- import type { SchemasStepSummaryContext } from '../../../model/index.ts'
16
- import type { SchemasStepSummary } from '../../../payloads/index.ts'
17
- import { SchemasStepSummarySchema } from '../../../payloads/index.ts'
15
+ import {
16
+ type SchemasStepSummary, type SchemasStepSummaryContext, SchemasStepSummarySchema,
17
+ } from '../../model/index.ts'
18
18
 
19
19
  export async function schemasStepSummaryFromRange(
20
20
  context: SchemasStepSummaryContext,
@@ -6,28 +6,29 @@ import {
6
6
  } from '@xyo-network/xl1-protocol'
7
7
 
8
8
  import { deepCalculateFramesFromRange } from '../../../block/index.ts'
9
- import type { SchemasStepSummaryContext } from '../../../model/index.ts'
9
+ import type { Qualified } from '../../../model/index.ts'
10
+ import type { SchemasStepSummaryContext } from '../../model/index.ts'
10
11
  import { schemasStepSummaryFromRange } from './schemasStepSummaryFromRange.ts'
11
12
 
12
13
  export async function schemasSummary(
13
14
  context: SchemasStepSummaryContext,
14
- ): Promise<Partial<Record<Schema, number>>> {
15
+ ): Promise<Qualified<Record<Schema, number>>> {
15
16
  return await spanRootAsync('schemasSummary', async () => {
16
17
  const [headHash] = await context.head()
17
18
  const headResult = await context.store.chainMap.get(headHash)
18
19
  const headBoundWitness = asBlockBoundWitnessWithStorageMeta(headResult, () => `Head block not found for hash: ${headHash}`)
19
- const rangeStart = asXL1BlockNumber(isDefined(context.windowSize) ? Math.max(headBoundWitness.block - context.windowSize + 1, 0) : 0)
20
+ const rangeStart = asXL1BlockNumber(isDefined(context.windowSize) ? Math.max(headBoundWitness.block - context.windowSize + 1, 0) : 0, true)
20
21
  const ranges = deepCalculateFramesFromRange(asXL1BlockRange(
21
22
  [rangeStart, headBoundWitness.block],
22
23
  { name: 'schemasSummary' },
23
24
  ))
24
25
  const summaries = await Promise.all(ranges.map(range => schemasStepSummaryFromRange(context, range)))
25
- const schemas: Partial<Record<Schema, number>> = {}
26
+ const results: Record<Schema, number> = {}
26
27
  for (let summary of summaries) {
27
28
  for (const [schema, count] of Object.entries(summary.schemas)) {
28
- schemas[schema] = (schemas[schema] ?? 0) + count
29
+ results[schema] = (results[schema] ?? 0) + count
29
30
  }
30
31
  }
31
- return schemas
32
+ return [results, [rangeStart, headBoundWitness.block], headHash]
32
33
  })
33
34
  }