@xyo-network/chain-services 1.19.13 → 1.19.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/neutral/PendingTransactions/bundledPayloadToHydratedTransaction.d.ts.map +1 -1
- package/dist/neutral/PendingTransactions/hydratedTransactionToPayloadBundle.d.ts.map +1 -1
- package/dist/neutral/index.d.ts +0 -1
- package/dist/neutral/index.d.ts.map +1 -1
- package/dist/neutral/index.mjs +14 -262
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/neutral/simple/block/runner/SimpleBlockRunner.d.ts +4 -1
- package/dist/neutral/simple/block/runner/SimpleBlockRunner.d.ts.map +1 -1
- package/package.json +27 -22
- package/src/PendingTransactions/bundledPayloadToHydratedTransaction.ts +1 -1
- package/src/PendingTransactions/hydratedTransactionToPayloadBundle.ts +1 -1
- package/src/index.ts +0 -1
- package/src/simple/block/runner/SimpleBlockRunner.ts +10 -11
- package/src/simple/block/runner/generateTransactionFeeTransfers.ts +1 -1
- package/dist/neutral/StakeIntent/XyoStakeIntentService.d.ts +0 -47
- package/dist/neutral/StakeIntent/XyoStakeIntentService.d.ts.map +0 -1
- package/dist/neutral/StakeIntent/index.d.ts +0 -3
- package/dist/neutral/StakeIntent/index.d.ts.map +0 -1
- package/dist/neutral/StakeIntent/lib/getBlockSignedStakeDeclarations.d.ts +0 -4
- package/dist/neutral/StakeIntent/lib/getBlockSignedStakeDeclarations.d.ts.map +0 -1
- package/dist/neutral/StakeIntent/lib/index.d.ts +0 -2
- package/dist/neutral/StakeIntent/lib/index.d.ts.map +0 -1
- package/src/StakeIntent/XyoStakeIntentService.ts +0 -259
- package/src/StakeIntent/index.ts +0 -2
- package/src/StakeIntent/lib/getBlockSignedStakeDeclarations.ts +0 -47
- package/src/StakeIntent/lib/index.ts +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Hash } from '@xylabs/sdk-js'
|
|
2
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
3
2
|
import type { PayloadBundle } from '@xyo-network/payload-model'
|
|
4
3
|
import { PayloadBundleSchema } from '@xyo-network/payload-model'
|
|
4
|
+
import { PayloadBuilder } from '@xyo-network/sdk-js'
|
|
5
5
|
import type { SignedHydratedTransactionWithHashMeta } from '@xyo-network/xl1-sdk'
|
|
6
6
|
import { flattenHydratedTransaction } from '@xyo-network/xl1-sdk'
|
|
7
7
|
|
package/src/index.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
BlockRewardDiviner, FixedPercentageBlockRewardDiviner, FixedPercentageBlockRewardDivinerConfigSchema,
|
|
9
9
|
} from '@xyo-network/chain-modules'
|
|
10
10
|
import { buildNextBlock } from '@xyo-network/chain-protocol'
|
|
11
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
12
11
|
import { WithHashMeta } from '@xyo-network/payload-model'
|
|
12
|
+
import { PayloadBuilder } from '@xyo-network/sdk-js'
|
|
13
13
|
import {
|
|
14
14
|
AbstractCreatableProvider, AccountBalanceViewer, AccountBalanceViewerMoniker, AllowedBlockPayload, asBlockBoundWitness, AttoXL1, BlockBoundWitness,
|
|
15
15
|
BlockNumberPayload, BlockNumberSchema, BlockRewardViewer, BlockRewardViewerMoniker, BlockRunner, BlockRunnerMoniker, BlockValidationViewer,
|
|
@@ -39,6 +39,8 @@ export const XYO_PRODUCER_REDECLARATION_WINDOW = 500
|
|
|
39
39
|
|
|
40
40
|
export interface SimpleBlockRunnerParams extends CreatableProviderParams {
|
|
41
41
|
account: AccountInstance
|
|
42
|
+
disableIntentRedeclaration?: boolean
|
|
43
|
+
heartbeatInterval?: number
|
|
42
44
|
rejectedTransactionsArchivist?: ArchivistInstance
|
|
43
45
|
rewardAddress: Address
|
|
44
46
|
validateHydratedBlockState?: HydratedBlockStateValidationFunction
|
|
@@ -121,9 +123,9 @@ export class SimpleBlockRunner extends AbstractCreatableProvider<SimpleBlockRunn
|
|
|
121
123
|
return this._chainId
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
protected get heartbeatInterval() {
|
|
127
|
+
return this.params.heartbeatInterval ?? 3_600_000
|
|
128
|
+
}
|
|
127
129
|
|
|
128
130
|
protected get mempoolRunner() {
|
|
129
131
|
return this._mempoolRunner!
|
|
@@ -167,7 +169,7 @@ export class SimpleBlockRunner extends AbstractCreatableProvider<SimpleBlockRunn
|
|
|
167
169
|
this._chainId = this.context.config.chain.id
|
|
168
170
|
this._mempoolRunner = await this.locateAndCreate<MempoolRunner>(MempoolRunnerMoniker)
|
|
169
171
|
this._mempoolViewer = await this.locateAndCreate<MempoolViewer>(MempoolViewerMoniker)
|
|
170
|
-
this._rewardAddress = this.params.rewardAddress
|
|
172
|
+
this._rewardAddress = this.params.rewardAddress
|
|
171
173
|
this._timeSyncViewer = await this.locateAndCreate<TimeSyncViewer>(TimeSyncViewerMoniker)
|
|
172
174
|
}
|
|
173
175
|
|
|
@@ -222,7 +224,7 @@ export class SimpleBlockRunner extends AbstractCreatableProvider<SimpleBlockRunn
|
|
|
222
224
|
protected getProducerRedeclaration(head: WithHashMeta<BlockBoundWitness>): Promisable<ChainStakeIntent | undefined> {
|
|
223
225
|
// TODO: Do not redeclare on every block
|
|
224
226
|
// Decide if we should redeclare intent
|
|
225
|
-
if (this.params.
|
|
227
|
+
if (this.params.disableIntentRedeclaration) return
|
|
226
228
|
// Decide if we need to redeclare intent
|
|
227
229
|
// const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.address, 'producer')
|
|
228
230
|
// TODO: This doesn't handle the case where the producer had declared a range for the future
|
|
@@ -350,11 +352,8 @@ export class SimpleBlockRunner extends AbstractCreatableProvider<SimpleBlockRunn
|
|
|
350
352
|
*/
|
|
351
353
|
private heartbeatRequired(head: WithHashMeta<BlockBoundWitness>): boolean {
|
|
352
354
|
const epoch = head.$epoch
|
|
353
|
-
if (isDefined(epoch)) {
|
|
354
|
-
|
|
355
|
-
if (Date.now() - epoch > heartbeatInterval) {
|
|
356
|
-
return true
|
|
357
|
-
}
|
|
355
|
+
if (isDefined(epoch) && Date.now() - epoch > this.heartbeatInterval) {
|
|
356
|
+
return true
|
|
358
357
|
}
|
|
359
358
|
return false
|
|
360
359
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Address, hexFromBigInt } from '@xylabs/sdk-js'
|
|
2
2
|
import { assertEx } from '@xylabs/sdk-js'
|
|
3
|
-
import { PayloadBuilder } from '@xyo-network/
|
|
3
|
+
import { PayloadBuilder } from '@xyo-network/sdk-js'
|
|
4
4
|
import type {
|
|
5
5
|
SignedHydratedTransaction,
|
|
6
6
|
Transfer,
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Address, Hash } from '@xylabs/sdk-js';
|
|
2
|
-
import { ArchivistInstance } from '@xyo-network/archivist-model';
|
|
3
|
-
import { IntervalMap } from '@xyo-network/chain-utils';
|
|
4
|
-
import { Payload } from '@xyo-network/payload-model';
|
|
5
|
-
import { AbstractCreatableProvider, BlockViewer, ChainStakeViewer, StakeIntentService } from '@xyo-network/xl1-sdk';
|
|
6
|
-
import { type Intent } from '@xyo-network/xl1-sdk';
|
|
7
|
-
import { Mutex } from 'async-mutex';
|
|
8
|
-
import { LRUCache } from 'lru-cache';
|
|
9
|
-
import { BaseServiceParams } from '../model/index.ts';
|
|
10
|
-
export interface XyoStakeIntentServiceParams extends BaseServiceParams {
|
|
11
|
-
blockViewer: BlockViewer;
|
|
12
|
-
chainArchivist: ArchivistInstance;
|
|
13
|
-
chainStakeViewer: ChainStakeViewer;
|
|
14
|
-
stakeIntentStateArchivist: ArchivistInstance;
|
|
15
|
-
}
|
|
16
|
-
export declare class XyoStakeIntentService extends AbstractCreatableProvider<XyoStakeIntentServiceParams> implements StakeIntentService {
|
|
17
|
-
static readonly defaultMoniker = "StakeIntent";
|
|
18
|
-
static readonly dependencies: never[];
|
|
19
|
-
static readonly monikers: string[];
|
|
20
|
-
moniker: string;
|
|
21
|
-
protected _lastIndexedBlockHash: Hash | undefined;
|
|
22
|
-
protected _producers: IntervalMap<Address>;
|
|
23
|
-
protected _stakeCache: LRUCache<Lowercase<string> & {
|
|
24
|
-
readonly __hex: true;
|
|
25
|
-
} & {
|
|
26
|
-
readonly __address: true;
|
|
27
|
-
}, bigint, unknown>;
|
|
28
|
-
protected _updateMutex: Mutex;
|
|
29
|
-
private _blockViewer?;
|
|
30
|
-
private _chainStakeViewer?;
|
|
31
|
-
protected get blockViewer(): BlockViewer<"BlockViewer">;
|
|
32
|
-
protected get chainArchivist(): ArchivistInstance<import("@xyo-network/archivist-model").ArchivistParams<import("@xyo-network/module-model").AnyConfigSchema<import("@xyo-network/archivist-model").ArchivistConfig>>, import("@xyo-network/archivist-model").ArchivistModuleEventData, Payload>;
|
|
33
|
-
protected get chainStakeViewer(): ChainStakeViewer;
|
|
34
|
-
protected get stakeIntentStateArchivist(): ArchivistInstance<import("@xyo-network/archivist-model").ArchivistParams<import("@xyo-network/module-model").AnyConfigSchema<import("@xyo-network/archivist-model").ArchivistConfig>>, import("@xyo-network/archivist-model").ArchivistModuleEventData, Payload>;
|
|
35
|
-
static paramsHandler(params: Partial<XyoStakeIntentServiceParams>): Promise<XyoStakeIntentServiceParams>;
|
|
36
|
-
createHandler(): Promise<void>;
|
|
37
|
-
getDeclaredCandidateRanges(address: Address, intent: Intent): Promise<Readonly<Readonly<[number, number]>[]>>;
|
|
38
|
-
getDeclaredCandidatesForBlock(block: number, intent: Intent): Promise<Address[]>;
|
|
39
|
-
getRequiredMinimumStakeForIntent(intent: Intent): bigint;
|
|
40
|
-
isStakedForBlock(block: number, intent: Intent, address: Address): Promise<boolean>;
|
|
41
|
-
startHandler(): Promise<void>;
|
|
42
|
-
private filterToValidStake;
|
|
43
|
-
private persistState;
|
|
44
|
-
private recoverState;
|
|
45
|
-
private updateIndex;
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=XyoStakeIntentService.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"XyoStakeIntentService.d.ts","sourceRoot":"","sources":["../../../src/StakeIntent/XyoStakeIntentService.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAAiC,IAAI,EAE7C,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAwB,MAAM,8BAA8B,CAAA;AAKtF,OAAO,EAEc,WAAW,EAE/B,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,OAAO,EAAmB,MAAM,4BAA4B,CAAA;AACrE,OAAO,EACL,yBAAyB,EAEzB,WAAW,EAEiD,gBAAgB,EAK5E,kBAAkB,EAEnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACwE,KAAK,MAAM,EACzF,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,MAAM,WAAW,2BAA4B,SAAQ,iBAAiB;IACpE,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,iBAAiB,CAAA;IACjC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,yBAAyB,EAAE,iBAAiB,CAAA;CAC7C;AAWD,qBACa,qBAAsB,SAAQ,yBAAyB,CAAC,2BAA2B,CAAE,YAAW,kBAAkB;IAC7H,MAAM,CAAC,QAAQ,CAAC,cAAc,iBAAgB;IAC9C,MAAM,CAAC,QAAQ,CAAC,YAAY,UAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,WAAyC;IACjE,OAAO,SAAgB;IAEvB,SAAS,CAAC,qBAAqB,EAAE,IAAI,GAAG,SAAS,CAAY;IAS7D,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,CAAoB;IAC9D,SAAS,CAAC,WAAW;;;;wBAAkE;IACvF,SAAS,CAAC,YAAY,QAAc;IAEpC,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,iBAAiB,CAAC,CAAkB;IAE5C,SAAS,KAAK,WAAW,+BAExB;IAED,SAAS,KAAK,cAAc,qQAE3B;IAED,SAAS,KAAK,gBAAgB,qBAE7B;IAED,SAAS,KAAK,yBAAyB,qQAEtC;WAEqB,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAQxG,aAAa;IAQtB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAO7G,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAWtF,gCAAgC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IASlD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1E,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAI9B,kBAAkB;YAkClB,YAAY;YAQZ,YAAY;YAiCZ,WAAW;CAuC1B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/StakeIntent/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,4BAA4B,CAAA"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model';
|
|
2
|
-
import type { BlockBoundWitness, ChainStakeIntent, Intent } from '@xyo-network/xl1-sdk';
|
|
3
|
-
export declare const getBlockSignedStakeDeclarations: (block: BlockBoundWitness, archivist: ArchivistInstance, intent: Intent) => Promise<ChainStakeIntent[]>;
|
|
4
|
-
//# sourceMappingURL=getBlockSignedStakeDeclarations.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getBlockSignedStakeDeclarations.d.ts","sourceRoot":"","sources":["../../../../src/StakeIntent/lib/getBlockSignedStakeDeclarations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAKrE,OAAO,KAAK,EACV,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,EAC5C,MAAM,sBAAsB,CAAA;AAG7B,eAAO,MAAM,+BAA+B,GAAU,OAAO,iBAAiB,EAAE,WAAW,iBAAiB,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,gBAAgB,EAAE,CAyBxJ,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/StakeIntent/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAA"}
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Address, asAddress, assertEx, filterAs, Hash,
|
|
3
|
-
isUndefined,
|
|
4
|
-
} from '@xylabs/sdk-js'
|
|
5
|
-
import { ArchivistInstance, ArchivistNextOptions } from '@xyo-network/archivist-model'
|
|
6
|
-
import {
|
|
7
|
-
analyzeChain, ChainStakeIntentAnalyzer,
|
|
8
|
-
isChainSummaryStakeIntent,
|
|
9
|
-
} from '@xyo-network/chain-analyze'
|
|
10
|
-
import {
|
|
11
|
-
DEFAULT_FIND_FIRST_MATCHING_NEXT_OPTIONS,
|
|
12
|
-
findFirstMatching, IntervalMap,
|
|
13
|
-
SerializedIntervalMap,
|
|
14
|
-
} from '@xyo-network/chain-utils'
|
|
15
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
16
|
-
import { Payload, WithStorageMeta } from '@xyo-network/payload-model'
|
|
17
|
-
import {
|
|
18
|
-
AbstractCreatableProvider,
|
|
19
|
-
asChainIndexingServiceStateWithStorageMeta,
|
|
20
|
-
BlockViewer,
|
|
21
|
-
BlockViewerMoniker,
|
|
22
|
-
ChainIndexingServiceState, ChainIndexingServiceStateSchema, ChainStakeViewer,
|
|
23
|
-
ChainStakeViewerMoniker,
|
|
24
|
-
creatableProvider,
|
|
25
|
-
isChainIndexingServiceState,
|
|
26
|
-
readPayloadMapFromStore,
|
|
27
|
-
StakeIntentService,
|
|
28
|
-
timeBudget,
|
|
29
|
-
} from '@xyo-network/xl1-sdk'
|
|
30
|
-
import {
|
|
31
|
-
asBlockBoundWitness, asBlockBoundWitnessWithStorageMeta, asChainStakeIntent, type Intent,
|
|
32
|
-
} from '@xyo-network/xl1-sdk'
|
|
33
|
-
import { Mutex } from 'async-mutex'
|
|
34
|
-
import { LRUCache } from 'lru-cache'
|
|
35
|
-
|
|
36
|
-
import { BaseServiceParams } from '../model/index.ts'
|
|
37
|
-
|
|
38
|
-
export interface XyoStakeIntentServiceParams extends BaseServiceParams {
|
|
39
|
-
blockViewer: BlockViewer
|
|
40
|
-
chainArchivist: ArchivistInstance
|
|
41
|
-
chainStakeViewer: ChainStakeViewer
|
|
42
|
-
stakeIntentStateArchivist: ArchivistInstance
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The number of blocks to periodically persist state
|
|
47
|
-
*/
|
|
48
|
-
// const STATE_PERSISTENCE_INTERVAL = 60n
|
|
49
|
-
|
|
50
|
-
const ACTIVE_STAKE_TTL = 1000 * 60 * 60 * 2 // 2 hours in milliseconds
|
|
51
|
-
const NO_ACTIVE_STAKE_TTL = 1000 * 2 // 2 seconds in milliseconds
|
|
52
|
-
const STAKE_CACHE_MAX_ENTRIES = 10_000
|
|
53
|
-
|
|
54
|
-
@creatableProvider()
|
|
55
|
-
export class XyoStakeIntentService extends AbstractCreatableProvider<XyoStakeIntentServiceParams> implements StakeIntentService {
|
|
56
|
-
static readonly defaultMoniker = 'StakeIntent'
|
|
57
|
-
static readonly dependencies = []
|
|
58
|
-
static readonly monikers = [XyoStakeIntentService.defaultMoniker]
|
|
59
|
-
moniker = 'StakeIntent'
|
|
60
|
-
// TODO: Use hash instead of block number to handle chain reorgs
|
|
61
|
-
protected _lastIndexedBlockHash: Hash | undefined = undefined
|
|
62
|
-
// TODO: Interval tree per declaration (bank, validator, etc.)
|
|
63
|
-
|
|
64
|
-
// Ideally move to DataIntervalTree to handle declared
|
|
65
|
-
// ranges as it enables range queries in O(min(n, k * log n)) time,
|
|
66
|
-
// where k is the number of intervals in the output list time
|
|
67
|
-
// Currently using set based because it's simpler, equivalent
|
|
68
|
-
// in performance for small sets, and (most importantly) easily
|
|
69
|
-
// persisted so we can recover state on restart.
|
|
70
|
-
protected _producers: IntervalMap<Address> = new IntervalMap()
|
|
71
|
-
protected _stakeCache = new LRUCache<Address, bigint>({ max: STAKE_CACHE_MAX_ENTRIES })
|
|
72
|
-
protected _updateMutex = new Mutex()
|
|
73
|
-
|
|
74
|
-
private _blockViewer?: BlockViewer
|
|
75
|
-
private _chainStakeViewer?: ChainStakeViewer
|
|
76
|
-
|
|
77
|
-
protected get blockViewer() {
|
|
78
|
-
return this._blockViewer!
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
protected get chainArchivist() {
|
|
82
|
-
return assertEx(this.params.chainArchivist!, () => 'chainArchivist not set')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
protected get chainStakeViewer() {
|
|
86
|
-
return this._chainStakeViewer!
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
protected get stakeIntentStateArchivist() {
|
|
90
|
-
return assertEx(this.params.stakeIntentStateArchivist!, () => 'stakeIntentStateArchivist not set')
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
static override async paramsHandler(params: Partial<XyoStakeIntentServiceParams>): Promise<XyoStakeIntentServiceParams> {
|
|
94
|
-
return {
|
|
95
|
-
...await super.paramsHandler(params),
|
|
96
|
-
chainArchivist: assertEx(params?.chainArchivist, () => 'chainArchivist is required'),
|
|
97
|
-
stakeIntentStateArchivist: assertEx(params?.stakeIntentStateArchivist, () => 'stakeIntentStateArchivist is required'),
|
|
98
|
-
} as XyoStakeIntentServiceParams
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
override async createHandler() {
|
|
102
|
-
this._blockViewer = await this.locator.getInstance(BlockViewerMoniker)
|
|
103
|
-
this._chainStakeViewer = await this.locator.getInstance(ChainStakeViewerMoniker)
|
|
104
|
-
const head = await this.blockViewer.currentBlock()
|
|
105
|
-
if (isUndefined(head)) return
|
|
106
|
-
await this.recoverState(head[0]._hash)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async getDeclaredCandidateRanges(address: Address, intent: Intent): Promise<Readonly<Readonly<[number, number]>[]>> {
|
|
110
|
-
await Promise.resolve()
|
|
111
|
-
assertEx(intent === 'producer', () => `Support not yet added for intent ${intent}`)
|
|
112
|
-
const results = this._producers.get(address)
|
|
113
|
-
return results ?? []
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async getDeclaredCandidatesForBlock(block: number, intent: Intent): Promise<Address[]> {
|
|
117
|
-
return await this.spanAsync('getDeclaredCandidatesForBlock', async () => {
|
|
118
|
-
assertEx(intent === 'producer', () => `Support not yet added for intent ${intent}`)
|
|
119
|
-
const results = this._producers.findAllContaining(block)
|
|
120
|
-
const candidates = [...results]
|
|
121
|
-
const requiredMinimumStake = this.getRequiredMinimumStakeForIntent(intent)
|
|
122
|
-
const validCandidates = await this.filterToValidStake(candidates, this.chainStakeViewer, requiredMinimumStake)
|
|
123
|
-
return validCandidates
|
|
124
|
-
}, this.context)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
getRequiredMinimumStakeForIntent(intent: Intent): bigint {
|
|
128
|
-
switch (intent) {
|
|
129
|
-
case 'producer': {
|
|
130
|
-
const { minStake } = this.params.context.config.actors.producer
|
|
131
|
-
return BigInt(minStake)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async isStakedForBlock(block: number, intent: Intent, address: Address): Promise<boolean> {
|
|
137
|
-
const candidates = await this.getDeclaredCandidatesForBlock(block, intent)
|
|
138
|
-
return candidates.includes(address)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
override async startHandler(): Promise<void> {
|
|
142
|
-
await this.updateIndex(true)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private async filterToValidStake(
|
|
146
|
-
candidates: Address[],
|
|
147
|
-
chainStakeViewer: ChainStakeViewer,
|
|
148
|
-
requiredMinimumStake: bigint,
|
|
149
|
-
): Promise<Address[]> {
|
|
150
|
-
type CandidateStake = { candidate: Address; stake: bigint }
|
|
151
|
-
|
|
152
|
-
// Find the stake for each candidate
|
|
153
|
-
const candidatesWithStake: CandidateStake[] = await Promise.all(
|
|
154
|
-
candidates.map(async (candidate) => {
|
|
155
|
-
// Check if the stake is already cached
|
|
156
|
-
const stake = this._stakeCache.get(candidate)
|
|
157
|
-
if (stake === undefined) {
|
|
158
|
-
// Fetch from chainStakeViewer if not cached
|
|
159
|
-
const activeStake = await chainStakeViewer.activeByStaked(candidate)
|
|
160
|
-
if (activeStake > 0n) {
|
|
161
|
-
// Store result in cache
|
|
162
|
-
this._stakeCache.set(candidate, activeStake, { ttl: ACTIVE_STAKE_TTL })
|
|
163
|
-
} else {
|
|
164
|
-
this._stakeCache.set(candidate, activeStake, { ttl: NO_ACTIVE_STAKE_TTL })
|
|
165
|
-
}
|
|
166
|
-
return { candidate, stake: activeStake }
|
|
167
|
-
} else {
|
|
168
|
-
return { candidate, stake }
|
|
169
|
-
}
|
|
170
|
-
}),
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
// Filter out candidates whose stake is greater than or equal to the required minimum
|
|
174
|
-
return candidatesWithStake
|
|
175
|
-
.filter(({ stake }) => stake >= requiredMinimumStake)
|
|
176
|
-
.map(({ candidate }) => candidate)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
private async persistState(current: Hash): Promise<void> {
|
|
180
|
-
const state = this._producers.serialize()
|
|
181
|
-
const payload = new PayloadBuilder<ChainIndexingServiceState<SerializedIntervalMap>>({ schema: ChainIndexingServiceStateSchema })
|
|
182
|
-
.fields({ endBlockHash: current, state })
|
|
183
|
-
.build()
|
|
184
|
-
await this.stakeIntentStateArchivist.insert([payload])
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private async recoverState(current: Hash): Promise<void> {
|
|
188
|
-
return await timeBudget('XyoStakeIntentService.recoverState', console, async () => {
|
|
189
|
-
const currentBlock = assertEx(asBlockBoundWitness((await this.chainArchivist.get([current]))?.[0]), () => `Block ${current} not found`)
|
|
190
|
-
const currentBlockNum = currentBlock.block
|
|
191
|
-
// Find last state before current head (in case of rollback, we indexed past it on an uncle chain, etc.)
|
|
192
|
-
const opts: ArchivistNextOptions = { ...DEFAULT_FIND_FIRST_MATCHING_NEXT_OPTIONS }
|
|
193
|
-
while (true) {
|
|
194
|
-
const predicate = (p: WithStorageMeta<Payload>) => {
|
|
195
|
-
const state = asChainIndexingServiceStateWithStorageMeta(p)
|
|
196
|
-
return state ? true : false
|
|
197
|
-
}
|
|
198
|
-
const state = await findFirstMatching(this.stakeIntentStateArchivist, predicate, opts)
|
|
199
|
-
if (isChainIndexingServiceState<SerializedIntervalMap>(state)) {
|
|
200
|
-
const indexed = (await this.chainArchivist.get([state.endBlockHash]))?.[0]
|
|
201
|
-
const indexedBlock = asBlockBoundWitnessWithStorageMeta(indexed)
|
|
202
|
-
if (indexedBlock) {
|
|
203
|
-
const indexedBlockNum = indexedBlock.block
|
|
204
|
-
if (indexedBlockNum <= currentBlockNum) {
|
|
205
|
-
const data = state.state as SerializedIntervalMap
|
|
206
|
-
this._producers = new IntervalMap(data)
|
|
207
|
-
this._lastIndexedBlockHash = indexedBlock._hash
|
|
208
|
-
break
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
// No state found, start from genesis
|
|
213
|
-
break
|
|
214
|
-
}
|
|
215
|
-
opts.open = true
|
|
216
|
-
}
|
|
217
|
-
}, 2000, true)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
private async updateIndex(displayProgress = false): Promise<void> {
|
|
221
|
-
if (this._updateMutex.isLocked()) {
|
|
222
|
-
return
|
|
223
|
-
}
|
|
224
|
-
await this._updateMutex.runExclusive(async () => {
|
|
225
|
-
return await this.spanAsync('updateIndex', async () => {
|
|
226
|
-
const currentHead = (await this.blockViewer.currentBlock())[0]
|
|
227
|
-
if (isUndefined(currentHead)) return
|
|
228
|
-
const currentHeadHash = currentHead._hash
|
|
229
|
-
const chainMap = readPayloadMapFromStore<WithStorageMeta<Payload>>(this.chainArchivist)
|
|
230
|
-
const result = await analyzeChain(
|
|
231
|
-
{ ...this.context, chainMap },
|
|
232
|
-
[new ChainStakeIntentAnalyzer('producer')],
|
|
233
|
-
currentHeadHash,
|
|
234
|
-
this._lastIndexedBlockHash,
|
|
235
|
-
)
|
|
236
|
-
const signedDeclarations = filterAs(result.find(isChainSummaryStakeIntent)?.intents ?? [], asChainStakeIntent)
|
|
237
|
-
if (currentHead.block === undefined) return
|
|
238
|
-
const currentHeadBlockNum = currentHead.block
|
|
239
|
-
if (displayProgress) this.logger?.log(`Updating index through 0x${currentHeadBlockNum}`)
|
|
240
|
-
for (const signedDeclaration of signedDeclarations) {
|
|
241
|
-
const { exp, nbf } = signedDeclaration
|
|
242
|
-
const start = nbf
|
|
243
|
-
const stop = exp
|
|
244
|
-
const address = asAddress(signedDeclaration?.from)
|
|
245
|
-
if (start !== undefined && stop !== undefined && address !== undefined) {
|
|
246
|
-
this._producers.insert(address, start, stop)
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
/*
|
|
250
|
-
if (index % STATE_PERSISTENCE_INTERVAL === 0n) {
|
|
251
|
-
if (displayProgress) this.logger?.info(`Persisting state at block ${index}`)
|
|
252
|
-
await this.persistState(await PayloadBuilder.hash(block))
|
|
253
|
-
}
|
|
254
|
-
*/
|
|
255
|
-
this._lastIndexedBlockHash = currentHeadHash
|
|
256
|
-
}, this.context)
|
|
257
|
-
})
|
|
258
|
-
}
|
|
259
|
-
}
|
package/src/StakeIntent/index.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { Hash } from '@xylabs/sdk-js'
|
|
2
|
-
import { exists, filterAs } from '@xylabs/sdk-js'
|
|
3
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
4
|
-
import type { BoundWitness } from '@xyo-network/boundwitness-model'
|
|
5
|
-
import { isBoundWitness } from '@xyo-network/boundwitness-model'
|
|
6
|
-
import { payloadSchemasContains } from '@xyo-network/boundwitness-validator'
|
|
7
|
-
import { BoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
8
|
-
import type {
|
|
9
|
-
BlockBoundWitness, ChainStakeIntent, Intent,
|
|
10
|
-
} from '@xyo-network/xl1-sdk'
|
|
11
|
-
import { asChainStakeIntent, ChainStakeIntentSchema } from '@xyo-network/xl1-sdk'
|
|
12
|
-
|
|
13
|
-
export const getBlockSignedStakeDeclarations = async (block: BlockBoundWitness, archivist: ArchivistInstance, intent: Intent): Promise<ChainStakeIntent[]> => {
|
|
14
|
-
// Get payloads in block
|
|
15
|
-
const blockData = await archivist.get(block.payload_hashes)
|
|
16
|
-
// Filter Payloads in block to BoundWitnesses
|
|
17
|
-
const bwsFromBlock = blockData.filter(x => isBoundWitness(x))
|
|
18
|
-
// Filter to BoundWitnesses with StakeIntent payloads
|
|
19
|
-
const bwsFromBlockWithDeclarations = bwsFromBlock.filter(bw => payloadSchemasContains(bw, ChainStakeIntentSchema))
|
|
20
|
-
// Filter to only valid signed BWs
|
|
21
|
-
const validBlockBwsWithDeclarations = await filterToValidSignedBoundWitnesses(bwsFromBlockWithDeclarations)
|
|
22
|
-
return (await Promise.all(validBlockBwsWithDeclarations.map(async (bw) => {
|
|
23
|
-
// Get staked intent hashes from signed declarations
|
|
24
|
-
const stakeIntentHashes = validBlockBwsWithDeclarations
|
|
25
|
-
.flatMap(mapBoundWitnessToStakeIntentHashes)
|
|
26
|
-
.filter(exists)
|
|
27
|
-
// Get staked intent payloads
|
|
28
|
-
const payloads = await archivist.get(stakeIntentHashes)
|
|
29
|
-
// Filter payloads to staked intents
|
|
30
|
-
const stakeIntents = filterAs(payloads, asChainStakeIntent)
|
|
31
|
-
// that are producers
|
|
32
|
-
.filter(p => p.intent === intent)
|
|
33
|
-
// where the issuer of the intent is also the signer of this BW
|
|
34
|
-
.filter(p => bw.addresses.includes(p.from))
|
|
35
|
-
|
|
36
|
-
return stakeIntents
|
|
37
|
-
}))).flat()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const filterToValidSignedBoundWitnesses = async (bws: BoundWitness[]): Promise<BoundWitness[]> => {
|
|
41
|
-
const validBwIndexes = await Promise.all(bws.map(bw => BoundWitnessWrapper.parse(bw).getValid()))
|
|
42
|
-
return bws.filter((_, index) => validBwIndexes[index])
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const mapBoundWitnessToStakeIntentHashes = (bw: BoundWitness): (Hash | undefined)[] => {
|
|
46
|
-
return bw.payload_schemas.map((schema, index) => schema === ChainStakeIntentSchema ? bw.payload_hashes[index] : undefined)
|
|
47
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './getBlockSignedStakeDeclarations.ts'
|