@xyo-network/xl1-cli-lib 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 (144) hide show
  1. package/dist/node/commands/index.d.ts +0 -1
  2. package/dist/node/commands/index.d.ts.map +1 -1
  3. package/dist/node/commands/validator/runValidator.d.ts +2 -2
  4. package/dist/node/commands/validator/runValidator.d.ts.map +1 -1
  5. package/dist/node/index.mjs +190 -1356
  6. package/dist/node/index.mjs.map +1 -1
  7. package/dist/node/orchestration/actor/implementation/BalanceActor.d.ts +2 -6
  8. package/dist/node/orchestration/actor/implementation/BalanceActor.d.ts.map +1 -1
  9. package/dist/node/orchestration/actor/implementation/ValidatorActor.d.ts +5 -10
  10. package/dist/node/orchestration/actor/implementation/ValidatorActor.d.ts.map +1 -1
  11. package/dist/node/orchestration/actor/implementation/index.d.ts +0 -1
  12. package/dist/node/orchestration/actor/implementation/index.d.ts.map +1 -1
  13. package/dist/node/orchestration/actor/index.d.ts +0 -1
  14. package/dist/node/orchestration/actor/index.d.ts.map +1 -1
  15. package/dist/node/orchestration/index.d.ts +0 -1
  16. package/dist/node/orchestration/index.d.ts.map +1 -1
  17. package/dist/node/orchestration/initServices.d.ts.map +1 -1
  18. package/dist/node/runCLI.d.ts.map +1 -1
  19. package/dist/node/xl1.mjs +24 -1386
  20. package/dist/node/xl1.mjs.map +1 -1
  21. package/package.json +30 -31
  22. package/src/commands/index.ts +0 -1
  23. package/src/commands/validator/runValidator.ts +6 -8
  24. package/src/orchestration/actor/implementation/BalanceActor.ts +4 -16
  25. package/src/orchestration/actor/implementation/ValidatorActor.ts +19 -27
  26. package/src/orchestration/actor/implementation/index.ts +0 -1
  27. package/src/orchestration/actor/index.ts +0 -1
  28. package/src/orchestration/index.ts +0 -1
  29. package/src/orchestration/initServices.ts +69 -112
  30. package/src/runCLI.ts +15 -14
  31. package/dist/node/commands/producer/index.d.ts +0 -2
  32. package/dist/node/commands/producer/index.d.ts.map +0 -1
  33. package/dist/node/commands/producer/runProducer.d.ts +0 -11
  34. package/dist/node/commands/producer/runProducer.d.ts.map +0 -1
  35. package/dist/node/orchestration/actor/implementation/ProducerActor.d.ts +0 -35
  36. package/dist/node/orchestration/actor/implementation/ProducerActor.d.ts.map +0 -1
  37. package/dist/node/orchestration/actor/model/Actor.d.ts +0 -41
  38. package/dist/node/orchestration/actor/model/Actor.d.ts.map +0 -1
  39. package/dist/node/orchestration/actor/model/Orchestrator.d.ts +0 -27
  40. package/dist/node/orchestration/actor/model/Orchestrator.d.ts.map +0 -1
  41. package/dist/node/orchestration/actor/model/index.d.ts +0 -3
  42. package/dist/node/orchestration/actor/model/index.d.ts.map +0 -1
  43. package/dist/node/orchestration/services/implementation/accountBalance.d.ts +0 -7
  44. package/dist/node/orchestration/services/implementation/accountBalance.d.ts.map +0 -1
  45. package/dist/node/orchestration/services/implementation/blockViewer.d.ts +0 -7
  46. package/dist/node/orchestration/services/implementation/blockViewer.d.ts.map +0 -1
  47. package/dist/node/orchestration/services/implementation/chain/evm.d.ts +0 -7
  48. package/dist/node/orchestration/services/implementation/chain/evm.d.ts.map +0 -1
  49. package/dist/node/orchestration/services/implementation/chain/index.d.ts +0 -7
  50. package/dist/node/orchestration/services/implementation/chain/index.d.ts.map +0 -1
  51. package/dist/node/orchestration/services/implementation/evm/index.d.ts +0 -2
  52. package/dist/node/orchestration/services/implementation/evm/index.d.ts.map +0 -1
  53. package/dist/node/orchestration/services/implementation/evm/initChainId.d.ts +0 -4
  54. package/dist/node/orchestration/services/implementation/evm/initChainId.d.ts.map +0 -1
  55. package/dist/node/orchestration/services/implementation/evm/initEvmProvider.d.ts +0 -11
  56. package/dist/node/orchestration/services/implementation/evm/initEvmProvider.d.ts.map +0 -1
  57. package/dist/node/orchestration/services/implementation/evm/initInfuraProvider.d.ts +0 -6
  58. package/dist/node/orchestration/services/implementation/evm/initInfuraProvider.d.ts.map +0 -1
  59. package/dist/node/orchestration/services/implementation/evm/initJsonRpcProvider.d.ts +0 -6
  60. package/dist/node/orchestration/services/implementation/evm/initJsonRpcProvider.d.ts.map +0 -1
  61. package/dist/node/orchestration/services/implementation/head/createBootstrapHead.d.ts +0 -5
  62. package/dist/node/orchestration/services/implementation/head/createBootstrapHead.d.ts.map +0 -1
  63. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getBridgeDestinationDetails.d.ts +0 -8
  64. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getBridgeDestinationDetails.d.ts.map +0 -1
  65. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getBridgeSourceDetails.d.ts +0 -9
  66. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getBridgeSourceDetails.d.ts.map +0 -1
  67. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getForkDetails.d.ts +0 -4
  68. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/getForkDetails.d.ts.map +0 -1
  69. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/index.d.ts +0 -4
  70. package/dist/node/orchestration/services/implementation/head/createForkedHead/config/index.d.ts.map +0 -1
  71. package/dist/node/orchestration/services/implementation/head/createForkedHead/createForkedHead.d.ts +0 -5
  72. package/dist/node/orchestration/services/implementation/head/createForkedHead/createForkedHead.d.ts.map +0 -1
  73. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeDestinationObservation.d.ts +0 -11
  74. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeDestinationObservation.d.ts.map +0 -1
  75. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeIntent.d.ts +0 -11
  76. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeIntent.d.ts.map +0 -1
  77. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeSourceObservation.d.ts +0 -11
  78. package/dist/node/orchestration/services/implementation/head/createForkedHead/getBridgeSourceObservation.d.ts.map +0 -1
  79. package/dist/node/orchestration/services/implementation/head/createForkedHead/getFirstBlockForNewChain.d.ts +0 -13
  80. package/dist/node/orchestration/services/implementation/head/createForkedHead/getFirstBlockForNewChain.d.ts.map +0 -1
  81. package/dist/node/orchestration/services/implementation/head/createForkedHead/index.d.ts +0 -2
  82. package/dist/node/orchestration/services/implementation/head/createForkedHead/index.d.ts.map +0 -1
  83. package/dist/node/orchestration/services/implementation/head/getForkFromBlock.d.ts +0 -12
  84. package/dist/node/orchestration/services/implementation/head/getForkFromBlock.d.ts.map +0 -1
  85. package/dist/node/orchestration/services/implementation/head/head.d.ts +0 -11
  86. package/dist/node/orchestration/services/implementation/head/head.d.ts.map +0 -1
  87. package/dist/node/orchestration/services/implementation/head/index.d.ts +0 -2
  88. package/dist/node/orchestration/services/implementation/head/index.d.ts.map +0 -1
  89. package/dist/node/orchestration/services/implementation/head/submitNewChain.d.ts +0 -10
  90. package/dist/node/orchestration/services/implementation/head/submitNewChain.d.ts.map +0 -1
  91. package/dist/node/orchestration/services/implementation/index.d.ts +0 -12
  92. package/dist/node/orchestration/services/implementation/index.d.ts.map +0 -1
  93. package/dist/node/orchestration/services/implementation/pendingTransactions.d.ts +0 -9
  94. package/dist/node/orchestration/services/implementation/pendingTransactions.d.ts.map +0 -1
  95. package/dist/node/orchestration/services/implementation/producer.d.ts +0 -5
  96. package/dist/node/orchestration/services/implementation/producer.d.ts.map +0 -1
  97. package/dist/node/orchestration/services/implementation/reward.d.ts +0 -5
  98. package/dist/node/orchestration/services/implementation/reward.d.ts.map +0 -1
  99. package/dist/node/orchestration/services/implementation/time.d.ts +0 -6
  100. package/dist/node/orchestration/services/implementation/time.d.ts.map +0 -1
  101. package/dist/node/orchestration/services/implementation/transfer.d.ts +0 -5
  102. package/dist/node/orchestration/services/implementation/transfer.d.ts.map +0 -1
  103. package/dist/node/orchestration/services/implementation/validator.d.ts +0 -5
  104. package/dist/node/orchestration/services/implementation/validator.d.ts.map +0 -1
  105. package/dist/node/orchestration/services/index.d.ts +0 -2
  106. package/dist/node/orchestration/services/index.d.ts.map +0 -1
  107. package/src/commands/producer/index.ts +0 -1
  108. package/src/commands/producer/runProducer.ts +0 -40
  109. package/src/orchestration/actor/implementation/ProducerActor.ts +0 -302
  110. package/src/orchestration/actor/model/Actor.ts +0 -167
  111. package/src/orchestration/actor/model/Orchestrator.ts +0 -71
  112. package/src/orchestration/actor/model/index.ts +0 -2
  113. package/src/orchestration/services/implementation/accountBalance.ts +0 -29
  114. package/src/orchestration/services/implementation/blockViewer.ts +0 -29
  115. package/src/orchestration/services/implementation/chain/evm.ts +0 -39
  116. package/src/orchestration/services/implementation/chain/index.ts +0 -45
  117. package/src/orchestration/services/implementation/evm/index.ts +0 -1
  118. package/src/orchestration/services/implementation/evm/initChainId.ts +0 -20
  119. package/src/orchestration/services/implementation/evm/initEvmProvider.ts +0 -24
  120. package/src/orchestration/services/implementation/evm/initInfuraProvider.ts +0 -26
  121. package/src/orchestration/services/implementation/evm/initJsonRpcProvider.ts +0 -20
  122. package/src/orchestration/services/implementation/head/createBootstrapHead.ts +0 -31
  123. package/src/orchestration/services/implementation/head/createForkedHead/config/getBridgeDestinationDetails.ts +0 -27
  124. package/src/orchestration/services/implementation/head/createForkedHead/config/getBridgeSourceDetails.ts +0 -19
  125. package/src/orchestration/services/implementation/head/createForkedHead/config/getForkDetails.ts +0 -10
  126. package/src/orchestration/services/implementation/head/createForkedHead/config/index.ts +0 -3
  127. package/src/orchestration/services/implementation/head/createForkedHead/createForkedHead.ts +0 -29
  128. package/src/orchestration/services/implementation/head/createForkedHead/getBridgeDestinationObservation.ts +0 -42
  129. package/src/orchestration/services/implementation/head/createForkedHead/getBridgeIntent.ts +0 -51
  130. package/src/orchestration/services/implementation/head/createForkedHead/getBridgeSourceObservation.ts +0 -46
  131. package/src/orchestration/services/implementation/head/createForkedHead/getFirstBlockForNewChain.ts +0 -41
  132. package/src/orchestration/services/implementation/head/createForkedHead/index.ts +0 -1
  133. package/src/orchestration/services/implementation/head/getForkFromBlock.ts +0 -43
  134. package/src/orchestration/services/implementation/head/head.ts +0 -49
  135. package/src/orchestration/services/implementation/head/index.ts +0 -1
  136. package/src/orchestration/services/implementation/head/submitNewChain.ts +0 -27
  137. package/src/orchestration/services/implementation/index.ts +0 -11
  138. package/src/orchestration/services/implementation/pendingTransactions.ts +0 -35
  139. package/src/orchestration/services/implementation/producer.ts +0 -15
  140. package/src/orchestration/services/implementation/reward.ts +0 -50
  141. package/src/orchestration/services/implementation/time.ts +0 -26
  142. package/src/orchestration/services/implementation/transfer.ts +0 -15
  143. package/src/orchestration/services/implementation/validator.ts +0 -15
  144. package/src/orchestration/services/index.ts +0 -1
@@ -1,302 +0,0 @@
1
- import type { Attributes, Counter } from '@opentelemetry/api'
2
- import type { Promisable } from '@xylabs/sdk-js'
3
- import {
4
- assertEx, isDefined, isUndefined, toHex,
5
- } from '@xylabs/sdk-js'
6
- import { createDeclarationIntent } from '@xyo-network/chain-protocol'
7
- import { BaseBlockProducerService } from '@xyo-network/chain-services'
8
- import { PayloadBuilder } from '@xyo-network/payload-builder'
9
- import type { PayloadBundle } from '@xyo-network/payload-model'
10
- import { PayloadBundleSchema } from '@xyo-network/payload-model'
11
- import type {
12
- ChainStakeIntent, HydratedBlockWithHashMeta,
13
- XL1BlockNumber,
14
- } from '@xyo-network/xl1-protocol'
15
- import { asXL1BlockNumber } from '@xyo-network/xl1-protocol'
16
- import type { ChainServiceCollectionV2 } from '@xyo-network/xl1-protocol-sdk'
17
- import {
18
- buildTransaction, flattenHydratedBlock, flattenHydratedTransaction,
19
- } from '@xyo-network/xl1-protocol-sdk'
20
- import { Mutex } from 'async-mutex'
21
-
22
- import type { ActorParams } from '../model/index.ts'
23
- import { Actor } from '../model/index.ts'
24
-
25
- export type ProducerActorParams = ActorParams<
26
- Pick<
27
- ChainServiceCollectionV2,
28
- 'account'
29
- | 'balance'
30
- | 'blockViewer'
31
- | 'chainStakeViewer'
32
- | 'chainSubmissionsArchivistWrite'
33
- | 'pendingBundledTransactionsArchivistWrite'
34
- | 'producer'
35
- | 'stakeIntent'
36
- >
37
- >
38
-
39
- const SHOULD_REGISTER_REDECLARATION_INTENT_TIMER = true
40
- const TEN_MINUTES = 10 * 60 * 1000 // 10 minutes in milliseconds
41
-
42
- export class ProducerActor extends Actor<ProducerActorParams> {
43
- protected _lastProducedBlock: HydratedBlockWithHashMeta | undefined
44
- protected _lastRedeclarationIntent: ChainStakeIntent | undefined
45
- protected readonly _metricAttributes: Attributes
46
- protected readonly _producerActorBlockProductionAttempts: Counter<Attributes> | undefined
47
- protected readonly _producerActorBlockProductionChecks: Counter<Attributes> | undefined
48
- protected readonly _producerActorBlocksProduced: Counter<Attributes> | undefined
49
- protected readonly _producerActorBlocksPublished: Counter<Attributes> | undefined
50
-
51
- private _produceBlockMutex = new Mutex()
52
-
53
- protected constructor(params: ProducerActorParams) {
54
- super(params.producer.address, 'Producer', params)
55
- // Create the consistent meter attributes that will
56
- // be included with all metrics from this actor
57
- this._metricAttributes = { address: this.account.address.toString() }
58
- // Create the metrics
59
- this._producerActorBlockProductionChecks = this.meter?.createCounter(
60
- 'producer_actor_block_production_checks',
61
- { description: 'Number of block production checks' },
62
- )
63
- this._producerActorBlockProductionAttempts = this.meter?.createCounter(
64
- 'producer_actor_block_production_attempts',
65
- { description: 'Number of block production attempts' },
66
- )
67
- this._producerActorBlocksProduced = this.meter?.createCounter(
68
- 'producer_actor_blocks_produced',
69
- { description: 'Number of blocks produced' },
70
- )
71
- this._producerActorBlocksPublished = this.meter?.createCounter(
72
- 'producer_actor_blocks_published',
73
- { description: 'Number of blocks published' },
74
- )
75
- }
76
-
77
- protected get account() {
78
- return assertEx(this.params.account, () => 'account not set')
79
- }
80
-
81
- protected get balanceService() {
82
- return assertEx(this.params.balance, () => 'balanceService not set')
83
- }
84
-
85
- protected get blockViewer() {
86
- return assertEx(this.params.blockViewer, () => 'blockViewer not set')
87
- }
88
-
89
- protected get chainStakeViewer() {
90
- return assertEx(this.params.chainStakeViewer, () => 'chainStakeViewer not set')
91
- }
92
-
93
- protected get chainSubmissionsArchivistWrite() {
94
- return assertEx(this.params.chainSubmissionsArchivistWrite, () => 'chainSubmissionsArchivistWrite not set')
95
- }
96
-
97
- protected get pendingBundledTransactionsArchivistWrite() {
98
- return assertEx(this.params.pendingBundledTransactionsArchivistWrite, () => 'pendingBundledTransactionsArchivistWrite not set')
99
- }
100
-
101
- protected get producer() {
102
- return assertEx(this.params.producer, () => 'producer not set')
103
- }
104
-
105
- protected get stakeIntentService() {
106
- return assertEx(this.params.stakeIntent, () => 'stakeIntentService not set')
107
- }
108
-
109
- static create(params: ProducerActorParams): Promisable<ProducerActor> {
110
- return new ProducerActor(params)
111
- }
112
-
113
- override async start(): Promise<void> {
114
- await super.start()
115
- // Register a timer to check if we should produce a block
116
- this.registerTimer('BlockProductionTimer', async () => {
117
- await this.produceBlock()
118
- }, 2000, 1500/* 500 */)
119
-
120
- if (SHOULD_REGISTER_REDECLARATION_INTENT_TIMER) {
121
- // Register a timer to check if we should redeclare the producer
122
- this.registerTimer('ProducerRedeclarationTimer', async () => {
123
- await this.redeclareIntent()
124
- }, TEN_MINUTES, TEN_MINUTES)
125
- }
126
- }
127
-
128
- protected async calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): Promise<number> {
129
- // Decide if we need to redeclare intent
130
- const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.account.address, 'producer')
131
- // TODO: This doesn't handle the case where the producer had declared a range for the future
132
- // but we're in a range that's not the future
133
- // Sort in ascending order based on ending range to get range with highest ending block
134
- const lastRange = ranges.toSorted((a, b) => a[1] > b[1] ? 1 : -1).at(-1)
135
-
136
- // Use the most recent range's end block as the current declaration end OR
137
- const [, currentDeclarationEnd] = lastRange
138
- // If we have no ranges, we need to declare intent, so use the current block
139
- ?? [undefined, currentBlock]
140
-
141
- // Calculate the time until the producer's declaration expires
142
- const timeToProducerExpiration = currentDeclarationEnd - currentBlock
143
- return timeToProducerExpiration
144
- }
145
-
146
- protected async produceBlock(): Promise<void> {
147
- this._producerActorBlockProductionChecks?.add(1, this._metricAttributes)
148
- await this.spanAsync('produceBlock', async () => {
149
- if (this._produceBlockMutex.isLocked()) {
150
- this.logger?.log('Skipping block production, previous production still in progress')
151
- return
152
- }
153
-
154
- await this._produceBlockMutex.runExclusive(async () => {
155
- // Get the updated head
156
- const headStart = Date.now()
157
- const head = (await this.blockViewer.currentBlock())[0]
158
- const headDuration = Date.now() - headStart
159
- if (headDuration > 500) this.logger?.warn(`[Slow] Fetched head in ${headDuration}ms: 0x${toHex(head._hash)}`)
160
- // Check if we've already produced the next block for this head
161
- const headHash = head._hash
162
- // If our last produced block was the next block for the current head, we do not
163
- // need to produce another. This prevents duplicate blocks from being produced
164
- if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {
165
- this.logger?.log('Block already produced:', `0x${toHex(this._lastProducedBlock[0].block)}`, this._lastProducedBlock[0].block)
166
- } else {
167
- this._producerActorBlockProductionAttempts?.add(1, this._metricAttributes)
168
- // Produce the next block
169
- const nextStart = Date.now()
170
- const nextBlock = await this.producer.next(head)
171
- const nextDuration = Date.now() - nextStart
172
- if (nextDuration > 1000) this.logger?.warn(`[Slow] Generated next block in ${nextDuration}ms, block: ${nextBlock?.[0]._hash}`)
173
- // If it was produced
174
- if (nextBlock) {
175
- const displayBlockNumber = `0x${toHex(nextBlock[0].block)}`
176
- this.logger?.log('Produced block:', displayBlockNumber)
177
- this._producerActorBlocksProduced?.add(1, this._metricAttributes)
178
- // Insert the block into the chain
179
- await this.chainSubmissionsArchivistWrite.insert(flattenHydratedBlock(nextBlock))
180
- this.logger?.log('Published block:', displayBlockNumber, nextBlock[0].block)
181
- this._producerActorBlocksPublished?.add(1, this._metricAttributes)
182
- // Record that we have produced a block so we do not produce it again
183
- this._lastProducedBlock = nextBlock
184
- }
185
- }
186
- })
187
- })
188
- }
189
-
190
- protected async redeclareIntent(): Promise<void> {
191
- await this.spanAsync('redeclareIntent', async () => {
192
- // Decide if we should redeclare intent
193
- if (this.params.config.producer.disableIntentRedeclaration) return
194
-
195
- // Get the current block
196
- const head = (await this.blockViewer.currentBlock())[0]
197
- if (isUndefined(head)) return
198
- const currentBlock = head.block
199
-
200
- // Calculate the time until the producer's declaration expires
201
- const blocksUntilExpiration = await this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock)
202
-
203
- // Allow the producer time to redeclare itself via block production
204
- // (for free) before submitting a redeclaration intent transaction.
205
- if (blocksUntilExpiration > BaseBlockProducerService.RedeclarationWindow * 0.1) {
206
- // Clear any previous redeclaration intent
207
- this._lastRedeclarationIntent = undefined
208
- // No need to redeclare yet
209
- return
210
- }
211
-
212
- // If we already have a valid redeclaration intent, do not create another
213
- // unless it has expired.
214
- if (this._lastRedeclarationIntent) {
215
- // Check if the last redeclaration intent is still valid
216
- if (this._lastRedeclarationIntent.exp > currentBlock) return
217
- // If it has expired, clear the last redeclaration intent
218
- this._lastRedeclarationIntent = undefined
219
- }
220
-
221
- // Check if we have a valid balance before declaring intent
222
- if (!await this.validateCurrentBalance()) {
223
- this.logger?.error(
224
- `Add balance to address ${this.account.address} for the producer to declare it's intent.`,
225
- )
226
- return
227
- }
228
-
229
- // Check if we have a valid stake before declaring intent
230
- if (!(await this.validateCurrentStake())) {
231
- this.logger?.error(
232
- `Add stake to contract address ${this.params.config.chain.id}`
233
- + ' for the producer to declare it\'s intent.',
234
- )
235
- return
236
- }
237
-
238
- // Create a redeclaration intent
239
- this.logger?.log('Creating redeclaration intent for producer:', this.account.address)
240
- const redeclarationIntent = createDeclarationIntent(
241
- this.account.address,
242
- 'producer',
243
- currentBlock,
244
- currentBlock + BaseBlockProducerService.RedeclarationDuration,
245
- )
246
-
247
- // Submit the redeclaration intent
248
- await this.submitRedeclarationIntent(currentBlock, redeclarationIntent)
249
-
250
- // On successful submission, save the redeclaration intent
251
- this._lastRedeclarationIntent = redeclarationIntent
252
- })
253
- }
254
-
255
- protected async submitRedeclarationIntent(currentBlock: XL1BlockNumber, redeclarationIntent: ChainStakeIntent): Promise<void> {
256
- this.logger?.log('Submitting redeclaration intent for producer:', this.account.address)
257
- // Create a transaction to submit the redeclaration intent
258
- const tx = await buildTransaction(
259
- await this.chainStakeViewer.chainId(),
260
- [redeclarationIntent],
261
- [],
262
- this.account,
263
- currentBlock,
264
- asXL1BlockNumber(currentBlock + 1000, true),
265
- )
266
- const payloads = flattenHydratedTransaction(tx)
267
- const root = tx[0]._hash
268
- const payloadBundle = new PayloadBuilder<PayloadBundle>({ schema: PayloadBundleSchema }).fields({ payloads, root }).build()
269
-
270
- // Submit the redeclaration intent
271
- await this.pendingBundledTransactionsArchivistWrite.insert([payloadBundle])
272
-
273
- this.logger?.log('Submitted redeclaration intent for producer:', this.account.address)
274
- }
275
-
276
- protected async validateCurrentBalance(): Promise<boolean> {
277
- // Check if we have a valid balance before declaring intent
278
- const head = this._lastProducedBlock?.[0]._hash
279
- if (isDefined(head)) {
280
- const balances = await this.balanceService.accountsBalances([this.account.address], head)
281
- const currentBalance = balances[this.account.address] ?? 0n
282
- if (currentBalance <= 0n) {
283
- this.logger?.error(`Producer ${this.account.address} has no balance.`)
284
- return false
285
- }
286
- return true
287
- }
288
- return true
289
- }
290
-
291
- protected async validateCurrentStake(): Promise<boolean> {
292
- // Use StakeIntentService to get the required minimum stake
293
- const requiredMinimumStake = this.stakeIntentService.getRequiredMinimumStakeForIntent('producer')
294
- // Check if we have a valid stake before declaring intent
295
- const currentStake = await this.chainStakeViewer.activeByStaked(this.account.address)
296
- if (currentStake < requiredMinimumStake) {
297
- this.logger?.error(`Producer ${this.account.address} has insufficient stake.`)
298
- return false
299
- }
300
- return true
301
- }
302
- }
@@ -1,167 +0,0 @@
1
- import type { BaseParams, EmptyObject } from '@xylabs/sdk-js'
2
- import {
3
- Base, delay, IdLogger,
4
- } from '@xylabs/sdk-js'
5
- import { span, spanRootAsync } from '@xylabs/telemetry'
6
- import type { Config } from '@xyo-network/xl1-protocol-sdk'
7
- import { Semaphore } from 'async-mutex'
8
-
9
- export interface IActor {
10
- start(): Promise<void>
11
- stop(): Promise<void>
12
- }
13
-
14
- export type ActorParams<T extends EmptyObject | void = void> = BaseParams<{
15
- config: Config
16
- name: string
17
- } & (T extends void ? EmptyObject : T)>
18
-
19
- export class Actor<TParams extends ActorParams = ActorParams> extends Base<TParams> implements IActor {
20
- protected readonly _intervals: Map<string, ReturnType<typeof setInterval>> = new Map()
21
- protected readonly _semaphores: Map<string, Semaphore> = new Map()
22
- protected readonly _timeouts: Map<string, ReturnType<typeof setTimeout>> = new Map()
23
- private _active = false
24
- private readonly _displayName: string
25
- private readonly _id: string
26
-
27
- constructor(id: string, displayName: string = 'Actor', params: TParams) {
28
- const logger = params.logger ?? new IdLogger(Base.defaultLogger ?? console, () => `[${displayName} (${id})] `)
29
- super({ ...params, logger })
30
- this._displayName = displayName
31
- this._id = id
32
- }
33
-
34
- get displayName() {
35
- return this._displayName
36
- }
37
-
38
- get id() {
39
- return this._id
40
- }
41
-
42
- get name() {
43
- return this.params.name
44
- }
45
-
46
- protected get logPrefix() {
47
- return `[${this.displayName} (${this.id})] `
48
- }
49
-
50
- /**
51
- * The timer runs until the actor is deactivated (or you manually stop it).
52
- */
53
- registerTimer(timerName: string, callback: () => Promise<void>, dueTimeMs: number, periodMs: number) {
54
- if (!this._active) {
55
- this.logger?.warn(
56
- `Cannot register timer '${timerName}' because actor is not active.`,
57
- )
58
- return
59
- }
60
-
61
- let running = false
62
-
63
- this._semaphores.set(timerName, new Semaphore(1))
64
-
65
- const timeoutId = setTimeout(() => {
66
- const intervalId = setInterval(() => {
67
- const semaphore = this._semaphores.get(timerName)
68
- if (!this._active || !this._intervals.has(timerName) || !semaphore || running) return
69
- if (semaphore.isLocked()) {
70
- this.logger?.warn(
71
- `Skipping timer '${this.name}:${timerName}' execution because previous execution is still running.`,
72
- )
73
- return
74
- }
75
- semaphore.acquire().then(([, release]) => {
76
- const startTime = Date.now()
77
- running = true
78
- callback()
79
- .then(() => {
80
- const duration = Date.now() - startTime
81
- if (duration > periodMs) {
82
- this.logger?.warn(
83
- `Timer '${this.name}:${timerName}' execution took longer (${duration}ms) than the period (${periodMs}ms).`,
84
- )
85
- } else if (duration > 5000) {
86
- this.logger?.warn(
87
- `Timer '${this.name}:${timerName}' execution took longer (${duration}ms) than 5000ms.`,
88
- )
89
- }
90
- })
91
- .catch((error) => {
92
- this.logger?.error(`Error in timer '${this.name}:${timerName}': ${error}`)
93
- })
94
- .finally(() => {
95
- release()
96
- running = false
97
- })
98
- }).catch((error) => {
99
- this.logger?.error(`Error acquiring semaphore for timer '${this.name}:${timerName}': ${error}`)
100
- })
101
- }, periodMs)
102
-
103
- // store interval so we can clear it on stop()
104
- this._intervals.set(timerName, intervalId)
105
- }, dueTimeMs)
106
-
107
- // store timeout so we can clear it on stop() if interval hasn't started yet
108
- this._timeouts.set(timerName, timeoutId)
109
-
110
- this.logger?.log(
111
- `Timer '${this.name}:${timerName}' registered: first call after ${dueTimeMs}ms, recurring every ${periodMs}ms.`,
112
- )
113
- }
114
-
115
- span<T>(name: string, fn: () => T): T {
116
- return span(`${this.name}:${name}`, fn, this.tracer)
117
- }
118
-
119
- async spanAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
120
- return await spanRootAsync(`${this.name}:${name}`, fn, this.tracer)
121
- }
122
-
123
- /**
124
- * Called by the Orchestrator when the actor is activated.
125
- */
126
- async start() {
127
- await Promise.resolve()
128
- this._active = true
129
- this.logger?.log('Started.')
130
- }
131
-
132
- /**
133
- * Called by the Orchestrator when the actor is deactivated.
134
- * Stop all running timers.
135
- */
136
- async stop() {
137
- await Promise.resolve()
138
- this._active = false
139
- this.logger?.log('Stopping all timers...')
140
-
141
- // wait for all semaphores to be free and acquire them to prevent new tasks from starting
142
- await Promise.all(
143
- [...this._semaphores.values()].map(async (semaphore) => {
144
- // Wait for any running tasks to complete
145
- while (semaphore.isLocked()) {
146
- this.logger?.log('Waiting for running timer task to complete...')
147
- await delay(500)
148
- }
149
- await semaphore.acquire()
150
- }),
151
- )
152
-
153
- this._semaphores.clear()
154
-
155
- for (const [, timeoutRef] of this._timeouts.entries()) {
156
- clearTimeout(timeoutRef)
157
- }
158
- this._timeouts.clear()
159
-
160
- for (const [, intervalRef] of this._intervals.entries()) {
161
- clearInterval(intervalRef)
162
- }
163
- this._intervals.clear()
164
-
165
- this.logger?.log('Stopped.')
166
- }
167
- }
@@ -1,71 +0,0 @@
1
- import type { Logger } from '@xylabs/sdk-js'
2
-
3
- import type { IActor } from './Actor.ts'
4
-
5
- export interface IOrchestrator {
6
- start(): Promise<void>
7
- stop(): Promise<void>
8
- }
9
-
10
- export class Orchestrator implements IOrchestrator {
11
- protected actors: IActor[] = []
12
- protected keepAliveHandle: NodeJS.Timeout | null = null
13
- protected readonly logger?: Logger
14
- protected running = false
15
-
16
- constructor(logger?: Logger) {
17
- this.logger = logger
18
- }
19
-
20
- /**
21
- * Registers an actor.
22
- * (We won't activate the actor until `start()` is called.)
23
- */
24
- async registerActor(actor: IActor) {
25
- if (this.running) {
26
- // If the orchestrator is already running, activate the actor immediately
27
- await actor.start()
28
- }
29
- this.actors.push(actor)
30
- }
31
-
32
- /**
33
- * Starts the orchestrator: activates all actors.
34
- */
35
- async start() {
36
- await Promise.resolve()
37
- if (this.running) {
38
- this.logger?.warn('[Orchestrator] Already started.')
39
- return
40
- }
41
-
42
- this.logger?.log('[Orchestrator] Starting...')
43
- this.running = true
44
- for (const actor of this.actors) {
45
- await actor.start()
46
- }
47
- // This interval will fire every 24.8 days (2^31 - 1 ms), effectively never finishing
48
- this.keepAliveHandle = setInterval(() => {
49
- // No-op
50
- }, 2_147_483_647)
51
- }
52
-
53
- /**
54
- * Stops the orchestrator: deactivates all actors.
55
- */
56
- async stop() {
57
- await Promise.resolve()
58
- if (!this.running) {
59
- this.logger?.log('[Orchestrator] Already stopped.')
60
- return
61
- }
62
-
63
- this.logger?.log('[Orchestrator] Stopping...')
64
- for (const actor of this.actors) {
65
- await actor.stop()
66
- }
67
- this.running = false
68
- if (this.keepAliveHandle) clearInterval(this.keepAliveHandle)
69
- this.logger?.log('[Orchestrator] Stopped...')
70
- }
71
- }
@@ -1,2 +0,0 @@
1
- export * from './Actor.ts'
2
- export * from './Orchestrator.ts'
@@ -1,29 +0,0 @@
1
- import { isDefined, type Promisable } from '@xylabs/sdk-js'
2
- import type { Initializable, InitializableParams } from '@xyo-network/xl1-protocol'
3
- import type { AccountBalanceViewer, Config } from '@xyo-network/xl1-protocol-sdk'
4
- import {
5
- AccountBalanceViewerRpcSchemas,
6
- HttpRpcTransport,
7
- JsonRpcAccountBalanceViewer,
8
- } from '@xyo-network/xl1-rpc'
9
-
10
- let balanceServiceSingleton: Promisable<AccountBalanceViewer> | undefined
11
-
12
- export type InitAccountBalanceServiceParams = InitializableParams<{
13
- config: Config
14
- }>
15
-
16
- export const initAccountBalanceService: Initializable<InitAccountBalanceServiceParams, AccountBalanceViewer>
17
- = (params): Promisable<AccountBalanceViewer> => {
18
- const { config, logger } = params
19
- if (balanceServiceSingleton) return balanceServiceSingleton
20
- const endpoint = config.services?.accountBalanceViewerEndpoint ?? config.services?.apiEndpoint
21
- if (isDefined(endpoint)) {
22
- const transport = new HttpRpcTransport(endpoint, { ...AccountBalanceViewerRpcSchemas })
23
- const viewer = new JsonRpcAccountBalanceViewer(transport)
24
- logger?.log('Using AccountBalanceViewer RPC service at', endpoint)
25
- return viewer
26
- } else {
27
- throw new Error('No AccountBalanceViewer endpoint configured')
28
- }
29
- }
@@ -1,29 +0,0 @@
1
- import { isDefined, type Promisable } from '@xylabs/sdk-js'
2
- import type { Initializable, InitializableParams } from '@xyo-network/xl1-protocol'
3
- import type { BlockViewer, Config } from '@xyo-network/xl1-protocol-sdk'
4
- import {
5
- BlockViewerRpcSchemas,
6
- HttpRpcTransport,
7
- JsonRpcBlockViewer,
8
- } from '@xyo-network/xl1-rpc'
9
-
10
- let blockViewerSingleton: Promisable<BlockViewer> | undefined
11
-
12
- export type InitBlockViewerParams = InitializableParams<{
13
- config: Config
14
- }>
15
-
16
- export const initBlockViewer: Initializable<InitBlockViewerParams, BlockViewer>
17
- = (params): Promisable<BlockViewer> => {
18
- const { config, logger } = params
19
- if (blockViewerSingleton) return blockViewerSingleton
20
- const endpoint = config.services?.apiEndpoint
21
- if (isDefined(endpoint)) {
22
- const transport = new HttpRpcTransport(endpoint, { ...BlockViewerRpcSchemas })
23
- const viewer = new JsonRpcBlockViewer(transport)
24
- logger?.log('Using BlockViewer RPC service at', endpoint)
25
- return viewer
26
- } else {
27
- throw new Error('No BlockViewer endpoint configured')
28
- }
29
- }
@@ -1,39 +0,0 @@
1
- import type { Address, Promisable } from '@xylabs/sdk-js'
2
- import {
3
- asAddress, assertEx, isDefined, ZERO_ADDRESS,
4
- } from '@xylabs/sdk-js'
5
- import type { BaseAccountableServiceParams } from '@xyo-network/chain-services'
6
- import { EvmChainService } from '@xyo-network/chain-services'
7
- import type { Initializable } from '@xyo-network/xl1-protocol'
8
- import type { Config } from '@xyo-network/xl1-protocol-sdk'
9
- import type { ContractRunner } from 'ethers'
10
- import { Wallet } from 'ethers/wallet'
11
-
12
- import { canUseEvmProvider, initEvmProvider } from '../evm/index.ts'
13
-
14
- let chainStakeServiceSingleton: Promisable<EvmChainService> | undefined
15
-
16
- export const canUseEvmContractChainService = (config: Pick<Config, 'chain' | 'evm'>) => {
17
- const { id } = config.chain
18
- return isDefined(id) && id !== ZERO_ADDRESS && canUseEvmProvider({ config })
19
- }
20
-
21
- export const initEvmContractChainService: Initializable<BaseAccountableServiceParams<Pick<Config, 'chain' | 'evm'>>, EvmChainService> = async ({
22
- account, config, traceProvider, meterProvider, logger,
23
- }) => {
24
- if (chainStakeServiceSingleton) return chainStakeServiceSingleton
25
- // Parse config
26
- const emvStakingContractAddress = assertEx(config.chain.id, () => 'config.chain.id is required')
27
- // Configure ContractRunner
28
- const id: Address = assertEx(asAddress(emvStakingContractAddress), () => 'config.chain.id is not a valid address')
29
- const provider = assertEx(await initEvmProvider({ config }))
30
- const privateKey = assertEx(account.private?.hex, () => 'Account does not have a private key')
31
- const runner: ContractRunner = new Wallet(privateKey, provider)
32
- // Create service
33
- chainStakeServiceSingleton = EvmChainService.create({
34
- id, runner, traceProvider, meterProvider, logger,
35
- })
36
- const result = await chainStakeServiceSingleton
37
- await result.start()
38
- return result
39
- }
@@ -1,45 +0,0 @@
1
- import {
2
- assertEx, type CreatableName, type Promisable,
3
- } from '@xylabs/sdk-js'
4
- import { type BaseAccountableServiceParams, MemoryChainService } from '@xyo-network/chain-services'
5
- import type { Initializable } from '@xyo-network/xl1-protocol'
6
- import type { ChainService } from '@xyo-network/xl1-protocol-sdk'
7
- import type { Config } from 'cosmiconfig'
8
-
9
- import { canUseEvmContractChainService, initEvmContractChainService } from './evm.ts'
10
-
11
- let chainStakeServiceSingleton: Promisable<ChainService> | undefined
12
-
13
- export const initChainService: Initializable<BaseAccountableServiceParams<
14
- Pick<Config, 'chain' | 'evm' | 'producer'>>,
15
- ChainService> = ({
16
- account, config, logger,
17
- }) => {
18
- logger?.log('ChainService: Initializing...')
19
- const result = init({
20
- config, name: 'ChainService' as CreatableName, account,
21
- })
22
- logger?.log('ChainService: Initialized')
23
- return result
24
- }
25
-
26
- export const initMemoryChainService: Initializable<BaseAccountableServiceParams<
27
- Pick<Config, 'producer'>>, ChainService> = async ({ config }) => {
28
- const result = await MemoryChainService.create({
29
- config,
30
- name: 'MemoryChainService' as CreatableName,
31
- })
32
- assertEx(await result.start(), () => 'Failed to start MemoryChainService')
33
- return result
34
- }
35
-
36
- const init: Initializable<BaseAccountableServiceParams<Pick<Config, 'chain' | 'evm' | 'producer'>>,
37
- ChainService> = async (params): Promise<ChainService> => {
38
- if (chainStakeServiceSingleton) return chainStakeServiceSingleton
39
- const { config } = params
40
- chainStakeServiceSingleton = canUseEvmContractChainService(config)
41
- ? await initEvmContractChainService({ ...params, name: 'ChainStakeService' as CreatableName })
42
- : await initMemoryChainService(params)
43
- // Create service
44
- return chainStakeServiceSingleton
45
- }