@xyo-network/chain-producer 1.17.7 → 1.18.0

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.
@@ -1,136 +1,133 @@
1
1
  import type { Attributes, Counter } from '@opentelemetry/api';
2
2
  import type { CreatableName } from '@xylabs/sdk-js';
3
- import { AccountInstance } from '@xyo-network/account-model';
4
3
  import { Actor, type ActorParams } from '@xyo-network/chain-orchestration';
5
- import type { ChainId, ChainStakeIntent, HydratedBlockWithHashMeta, XL1BlockNumber } from '@xyo-network/xl1-protocol';
6
- import { AccountBalanceViewer, BlockProducerService, BlockRewardViewer, BlockViewer, Config, MempoolRunner, MempoolViewer, StakeTotalsViewer, TimeSyncViewer } from '@xyo-network/xl1-protocol-sdk';
7
- export type ProducerActorParams = ActorParams<{
8
- account: AccountInstance;
9
- blockRewardViewer: BlockRewardViewer;
10
- chainId: ChainId;
11
- config: Config;
12
- runners: {
13
- mempoolRunner: MempoolRunner;
14
- };
15
- viewers: {
16
- accountBalanceViewer: AccountBalanceViewer;
17
- blockViewer: BlockViewer;
18
- mempoolViewer: MempoolViewer;
19
- stakeTotalsViewer: StakeTotalsViewer;
20
- time: TimeSyncViewer;
21
- };
22
- }>;
4
+ import type { ChainStakeIntent, HydratedBlockWithHashMeta, XL1BlockNumber } from '@xyo-network/xl1-protocol';
5
+ import { AccountBalanceViewer, BlockRunner, BlockViewer, MempoolRunner, MempoolViewer, StakeTotalsViewer } from '@xyo-network/xl1-protocol-sdk';
6
+ export type ProducerActorParams = ActorParams;
23
7
  export declare class ProducerActor extends Actor<ProducerActorParams> {
24
- protected _lastProducedBlock: HydratedBlockWithHashMeta | undefined;
25
- protected _lastRedeclarationIntent: ChainStakeIntent | undefined;
26
- protected _metricAttributes: Attributes | undefined;
27
- protected _producerActorBlockProductionAttempts: Counter<Attributes> | undefined;
28
- protected _producerActorBlockProductionChecks: Counter<Attributes> | undefined;
29
- protected _producerActorBlocksProduced: Counter<Attributes> | undefined;
30
- protected _producerActorBlocksPublished: Counter<Attributes> | undefined;
8
+ static readonly RedeclarationWindow = 10000;
9
+ protected _lastProducedBlock?: HydratedBlockWithHashMeta;
10
+ protected _lastRedeclarationIntent?: ChainStakeIntent;
11
+ protected _metricAttributes?: Attributes;
12
+ protected _producerActorBlockProductionAttempts?: Counter<Attributes>;
13
+ protected _producerActorBlockProductionChecks?: Counter<Attributes>;
14
+ protected _producerActorBlocksProduced?: Counter<Attributes>;
15
+ protected _producerActorBlocksPublished?: Counter<Attributes>;
16
+ private _accountBalanceViewer?;
17
+ private _blockRunner?;
18
+ private _blockViewer?;
19
+ private _chainId?;
20
+ private _mempoolRunner?;
21
+ private _mempoolViewer?;
31
22
  private _produceBlockMutex;
32
- private _producer;
33
- protected get account(): AccountInstance;
23
+ private _stakeTotalsViewer?;
34
24
  protected get accountBalanceViewer(): AccountBalanceViewer;
25
+ protected get blockRunner(): BlockRunner;
35
26
  protected get blockViewer(): BlockViewer;
36
27
  protected get chainId(): import("@xylabs/sdk-js").Hex;
37
- protected get config(): {
38
- api: {
39
- host: string;
40
- initRewardsCache: boolean;
41
- port: number;
42
- mnemonic?: string | undefined;
43
- };
44
- bridge: {
45
- chainRpcApiUrl: string;
46
- feeFixed: import("@xylabs/sdk-js").Hex;
47
- feeRateBasisPoints: number;
48
- host: string;
49
- maxBridgeAmount: import("@xylabs/sdk-js").Hex;
50
- minBridgeAmount: import("@xylabs/sdk-js").Hex;
51
- port: number;
52
- remoteBridgeContractAddress: import("@xylabs/sdk-js").Address;
53
- remoteChainId: import("@xylabs/sdk-js").Hex;
54
- remoteTokenAddress: import("@xylabs/sdk-js").Hex;
55
- escrowAddress?: import("@xylabs/sdk-js").Address | undefined;
56
- feesAddress?: import("@xylabs/sdk-js").Address | undefined;
57
- mnemonic?: string | undefined;
58
- xl1ChainId?: import("@xylabs/sdk-js").Hex | undefined;
59
- xl1TokenAddress?: import("@xylabs/sdk-js").Hex | undefined;
60
- };
61
- chain: {
62
- id?: string | undefined;
63
- genesisRewardAddress?: import("@xylabs/sdk-js").Address | undefined;
64
- };
65
- evm: {
66
- chainId?: string | undefined;
67
- infura?: {
68
- projectId?: string | undefined;
69
- projectSecret?: string | undefined;
70
- } | undefined;
71
- jsonRpc?: {
72
- url?: string | undefined;
73
- } | undefined;
74
- };
75
- mempool: {
76
- enabled: boolean;
77
- host: string;
78
- port: number;
79
- mnemonic?: string | undefined;
80
- };
81
- producer: {
82
- heartbeatInterval: number;
83
- minStake: number;
84
- port: number;
85
- allowlist?: import("@xylabs/sdk-js").Address[] | undefined;
86
- disableIntentRedeclaration?: boolean | undefined;
87
- healthCheckPort?: number | undefined;
88
- mnemonic?: string | undefined;
89
- rewardAddress?: string | undefined;
90
- };
91
- rewardRedemptionApi: {
92
- chainRpcApiUrl: string;
93
- host: string;
94
- port: number;
95
- mnemonic?: string | undefined;
96
- };
97
- services: {
98
- accountBalanceViewerEndpoint?: string | undefined;
99
- apiEndpoint?: string | undefined;
100
- };
101
- storage: {
102
- mongo?: {
103
- connectionString?: string | undefined;
104
- database?: string | undefined;
105
- domain?: string | undefined;
106
- password?: string | undefined;
107
- username?: string | undefined;
108
- } | undefined;
109
- root?: string | undefined;
110
- };
111
- telemetry: {
112
- metrics?: {
113
- scrape: {
114
- path: string;
115
- port: number;
116
- };
117
- } | undefined;
118
- otel?: {
119
- otlpEndpoint?: string | undefined;
120
- } | undefined;
121
- };
122
- validation: {
123
- allowedRewardRedeemers?: import("@xylabs/sdk-js").Address[] | undefined;
124
- allowedRewardEscrowAccountSigners?: import("@xylabs/sdk-js").Address[] | undefined;
125
- };
126
- logLevel: "info" | "warn" | "error" | "log" | "debug" | "trace";
127
- silent: boolean;
128
- };
129
28
  protected get mempoolRunner(): MempoolRunner;
130
29
  protected get mempoolViewer(): MempoolViewer;
131
- protected get producer(): BlockProducerService;
132
30
  protected get stakeTotalsViewer(): StakeTotalsViewer;
133
31
  static paramsHandler<T extends ActorParams>(params?: Partial<T>): Promise<{
32
+ account: T["account"] | import("@xyo-network/wallet-model").WalletInstance;
33
+ context: T["context"] | {
34
+ config: {
35
+ api: {
36
+ host: string;
37
+ initRewardsCache: boolean;
38
+ port: number;
39
+ mnemonic?: string | undefined;
40
+ };
41
+ bridge: {
42
+ chainRpcApiUrl: string;
43
+ feeFixed: import("@xylabs/sdk-js").Hex;
44
+ feeRateBasisPoints: number;
45
+ host: string;
46
+ maxBridgeAmount: import("@xylabs/sdk-js").Hex;
47
+ minBridgeAmount: import("@xylabs/sdk-js").Hex;
48
+ port: number;
49
+ redisHost: string;
50
+ redisPort: number;
51
+ remoteBridgeContractAddress: import("@xylabs/sdk-js").Address;
52
+ remoteChainId: import("@xylabs/sdk-js").Hex;
53
+ remoteTokenAddress: import("@xylabs/sdk-js").Hex;
54
+ remoteChainWalletPrivateKey: import("@xylabs/sdk-js").Hex;
55
+ escrowAddress?: import("@xylabs/sdk-js").Address | undefined;
56
+ feesAddress?: import("@xylabs/sdk-js").Address | undefined;
57
+ mnemonic?: string | undefined;
58
+ xl1ChainId?: import("@xylabs/sdk-js").Hex | undefined;
59
+ xl1TokenAddress?: import("@xylabs/sdk-js").Hex | undefined;
60
+ };
61
+ chain: {
62
+ id?: import("@xylabs/sdk-js").Hex | undefined;
63
+ genesisRewardAddress?: import("@xylabs/sdk-js").Address | undefined;
64
+ };
65
+ evm: {
66
+ chainId?: string | undefined;
67
+ infura?: {
68
+ projectId?: string | undefined;
69
+ projectSecret?: string | undefined;
70
+ } | undefined;
71
+ jsonRpc?: {
72
+ url?: string | undefined;
73
+ } | undefined;
74
+ };
75
+ mempool: {
76
+ enabled: boolean;
77
+ host: string;
78
+ port: number;
79
+ mnemonic?: string | undefined;
80
+ };
81
+ producer: {
82
+ heartbeatInterval: number;
83
+ minStake: number;
84
+ port: number;
85
+ allowlist?: import("@xylabs/sdk-js").Address[] | undefined;
86
+ disableIntentRedeclaration?: boolean | undefined;
87
+ healthCheckPort?: number | undefined;
88
+ mnemonic?: string | undefined;
89
+ rewardAddress?: string | undefined;
90
+ };
91
+ rewardRedemptionApi: {
92
+ chainRpcApiUrl: string;
93
+ host: string;
94
+ port: number;
95
+ mnemonic?: string | undefined;
96
+ };
97
+ services: {
98
+ accountBalanceViewerEndpoint: string;
99
+ apiEndpoint: string;
100
+ };
101
+ storage: {
102
+ mongo?: {
103
+ connectionString?: string | undefined;
104
+ database?: string | undefined;
105
+ domain?: string | undefined;
106
+ password?: string | undefined;
107
+ username?: string | undefined;
108
+ } | undefined;
109
+ root?: string | undefined;
110
+ };
111
+ telemetry: {
112
+ metrics?: {
113
+ scrape: {
114
+ path: string;
115
+ port: number;
116
+ };
117
+ } | undefined;
118
+ otel?: {
119
+ otlpEndpoint?: string | undefined;
120
+ } | undefined;
121
+ };
122
+ validation: {
123
+ allowedRewardRedeemers?: import("@xylabs/sdk-js").Address[] | undefined;
124
+ allowedRewardEscrowAccountSigners?: import("@xylabs/sdk-js").Address[] | undefined;
125
+ };
126
+ logLevel: "info" | "error" | "warn" | "log" | "debug" | "trace";
127
+ silent: boolean;
128
+ };
129
+ locator: import("@xyo-network/xl1-protocol-sdk").ProviderFactoryLocator;
130
+ };
134
131
  displayName: CreatableName | NonNullable<T["displayName"]> | undefined;
135
132
  id: CreatableName | T["id"] | undefined;
136
133
  logger: import("@xylabs/sdk-js").Logger;
@@ -141,6 +138,7 @@ export declare class ProducerActor extends Actor<ProducerActorParams> {
141
138
  }>;
142
139
  createHandler(): Promise<void>;
143
140
  startHandler(): Promise<void>;
141
+ protected calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): number;
144
142
  protected produceBlock(): Promise<void>;
145
143
  protected redeclareIntent(): Promise<void>;
146
144
  protected submitRedeclarationIntent(currentBlock: XL1BlockNumber, redeclarationIntent: ChainStakeIntent): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"ProducerActor.d.ts","sourceRoot":"","sources":["../../src/ProducerActor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAMnD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAG1E,OAAO,KAAK,EACV,OAAO,EACP,gBAAgB,EAAE,yBAAyB,EAC3C,cAAc,EACf,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EAAE,iBAAiB,EAAE,WAAW,EACpD,MAAM,EACN,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,cAAc,EACf,MAAM,+BAA+B,CAAA;AAGtC,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC;IAC5C,OAAO,EAAE,eAAe,CAAA;IACxB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QACP,aAAa,EAAE,aAAa,CAAA;KAC7B,CAAA;IACD,OAAO,EAAE;QACP,oBAAoB,EAAE,oBAAoB,CAAA;QAC1C,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,aAAa,CAAA;QAC5B,iBAAiB,EAAE,iBAAiB,CAAA;QACpC,IAAI,EAAE,cAAc,CAAA;KACrB,CAAA;CACF,CAAC,CAAA;AAKF,qBACa,aAAc,SAAQ,KAAK,CAAC,mBAAmB,CAAC;IAC3D,SAAS,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,SAAS,CAAA;IACnE,SAAS,CAAC,wBAAwB,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAChE,SAAS,CAAC,iBAAiB,EAAE,UAAU,GAAG,SAAS,CAAA;IACnD,SAAS,CAAC,qCAAqC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;IAChF,SAAS,CAAC,mCAAmC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;IAC9E,SAAS,CAAC,4BAA4B,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;IACvE,SAAS,CAAC,6BAA6B,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;IAExE,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,SAAS,CAAkC;IAEnD,SAAS,KAAK,OAAO,oBAEpB;IAED,SAAS,KAAK,oBAAoB,yBAEjC;IAED,SAAS,KAAK,WAAW,gBAExB;IAED,SAAS,KAAK,OAAO,iCAEpB;IAED,SAAS,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAEnB;IAED,SAAS,KAAK,aAAa,kBAE1B;IAED,SAAS,KAAK,aAAa,kBAE1B;IAED,SAAS,KAAK,QAAQ,yBAErB;IAED,SAAS,KAAK,iBAAiB,sBAE9B;WAEqB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;;;;;;;;;IAI/D,aAAa;IAuCb,YAAY;cAiCX,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cA8C7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;cAiEhC,yBAAyB,CAAC,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;cAkB7G,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC;cAe1C,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;CAWzD"}
1
+ {"version":3,"file":"ProducerActor.d.ts","sourceRoot":"","sources":["../../src/ProducerActor.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,11 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
4
  // src/ProducerActor.ts
5
- import { asAddress, creatable, isDefined, isUndefined, toHex, ZERO_ADDRESS } from "@xylabs/sdk-js";
6
- import { Actor } from "@xyo-network/chain-orchestration";
7
- import { createDeclarationIntent } from "@xyo-network/chain-protocol";
5
+ import { creatable, isDefined, isUndefined, toHex } from "@xylabs/sdk-js";
6
+ import { Actor, initProducerAccount } from "@xyo-network/chain-orchestration";
8
7
  import { SimpleBlockRunner } from "@xyo-network/chain-services";
9
8
  import { asXL1BlockNumber } from "@xyo-network/xl1-protocol";
10
- import { buildTransaction } from "@xyo-network/xl1-protocol-sdk";
9
+ import { AccountBalanceViewerMoniker, BlockRunnerMoniker, BlockViewerMoniker, buildTransaction, createDeclarationIntent, getDefaultConfig, MempoolRunnerMoniker, MempoolViewerMoniker, StakeTotalsViewerMoniker } from "@xyo-network/xl1-protocol-sdk";
11
10
  import { Mutex } from "async-mutex";
12
11
  function _ts_decorate(decorators, target, key, desc) {
13
12
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -18,10 +17,11 @@ function _ts_decorate(decorators, target, key, desc) {
18
17
  __name(_ts_decorate, "_ts_decorate");
19
18
  var SHOULD_REGISTER_REDECLARATION_INTENT_TIMER = true;
20
19
  var TEN_MINUTES = 10 * 60 * 1e3;
21
- var ProducerActor = class extends Actor {
20
+ var ProducerActor = class _ProducerActor extends Actor {
22
21
  static {
23
22
  __name(this, "ProducerActor");
24
23
  }
24
+ static RedeclarationWindow = 1e4;
25
25
  _lastProducedBlock;
26
26
  _lastRedeclarationIntent;
27
27
  _metricAttributes;
@@ -29,39 +29,44 @@ var ProducerActor = class extends Actor {
29
29
  _producerActorBlockProductionChecks;
30
30
  _producerActorBlocksProduced;
31
31
  _producerActorBlocksPublished;
32
+ _accountBalanceViewer;
33
+ _blockRunner;
34
+ _blockViewer;
35
+ _chainId;
36
+ _mempoolRunner;
37
+ _mempoolViewer;
32
38
  _produceBlockMutex = new Mutex();
33
- _producer;
34
- get account() {
35
- return this.params.account;
36
- }
39
+ _stakeTotalsViewer;
37
40
  get accountBalanceViewer() {
38
- return this.params.viewers.accountBalanceViewer;
41
+ return this._accountBalanceViewer;
42
+ }
43
+ get blockRunner() {
44
+ return this._blockRunner;
39
45
  }
40
46
  get blockViewer() {
41
- return this.params.viewers.blockViewer;
47
+ return this._blockViewer;
42
48
  }
43
49
  get chainId() {
44
- return this.params.chainId;
45
- }
46
- get config() {
47
- return this.params.config;
50
+ return this._chainId;
48
51
  }
49
52
  get mempoolRunner() {
50
- return this.params.runners.mempoolRunner;
53
+ return this._mempoolRunner;
51
54
  }
52
55
  get mempoolViewer() {
53
- return this.params.viewers.mempoolViewer;
54
- }
55
- get producer() {
56
- return this._producer;
56
+ return this._mempoolViewer;
57
57
  }
58
58
  get stakeTotalsViewer() {
59
- return this.params.viewers.stakeTotalsViewer;
59
+ return this._stakeTotalsViewer;
60
60
  }
61
61
  static async paramsHandler(params) {
62
+ const config = params?.context?.config ?? getDefaultConfig();
63
+ const account = params?.account ?? await initProducerAccount({
64
+ config
65
+ });
62
66
  return await super.paramsHandler({
63
67
  ...params,
64
- name: params?.name ?? "Producer"
68
+ name: params?.name ?? "Producer",
69
+ account
65
70
  });
66
71
  }
67
72
  async createHandler() {
@@ -81,18 +86,12 @@ var ProducerActor = class extends Actor {
81
86
  this._producerActorBlocksPublished = this.meter?.createCounter("producer_actor_blocks_published", {
82
87
  description: "Number of blocks published"
83
88
  });
84
- const params = {
85
- account: this.account,
86
- balanceViewer: this.accountBalanceViewer,
87
- config: this.config,
88
- chainId: this.chainId,
89
- mempoolRunner: this.mempoolRunner,
90
- mempoolViewer: this.mempoolViewer,
91
- blockRewardViewer: this.params.blockRewardViewer,
92
- rewardAddress: asAddress(this.config.producer.rewardAddress ?? ZERO_ADDRESS, () => `Producer config must have a valid reward address configured [${this.params.config.producer.rewardAddress}]`),
93
- time: this.params.viewers.time
94
- };
95
- this._producer = await SimpleBlockRunner.create(params);
89
+ this._accountBalanceViewer = await this.locator.getInstance(AccountBalanceViewerMoniker);
90
+ this._blockRunner = await this.locator.getInstance(BlockRunnerMoniker);
91
+ this._blockViewer = await this.locator.getInstance(BlockViewerMoniker);
92
+ this._mempoolRunner = await this.locator.getInstance(MempoolRunnerMoniker);
93
+ this._mempoolViewer = await this.locator.getInstance(MempoolViewerMoniker);
94
+ this._stakeTotalsViewer = await this.locator.getInstance(StakeTotalsViewerMoniker);
96
95
  }
97
96
  async startHandler() {
98
97
  await super.startHandler();
@@ -111,21 +110,9 @@ var ProducerActor = class extends Actor {
111
110
  }, TEN_MINUTES, TEN_MINUTES);
112
111
  }
113
112
  }
114
- // protected async calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): Promise<number> {
115
- // // Decide if we need to redeclare intent
116
- // const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.account.address, 'producer')
117
- // // TODO: This doesn't handle the case where the producer had declared a range for the future
118
- // // but we're in a range that's not the future
119
- // // Sort in ascending order based on ending range to get range with highest ending block
120
- // const lastRange = ranges.toSorted((a, b) => a[1] > b[1] ? 1 : -1).at(-1)
121
- // // Use the most recent range's end block as the current declaration end OR
122
- // const [, currentDeclarationEnd] = lastRange
123
- // // If we have no ranges, we need to declare intent, so use the current block
124
- // ?? [undefined, currentBlock]
125
- // // Calculate the time until the producer's declaration expires
126
- // const timeToProducerExpiration = currentDeclarationEnd - currentBlock
127
- // return timeToProducerExpiration
128
- // }
113
+ calculateBlocksUntilProducerDeclarationExpiration(currentBlock) {
114
+ return (this._lastRedeclarationIntent?.exp ?? currentBlock) - currentBlock;
115
+ }
129
116
  async produceBlock() {
130
117
  this._producerActorBlockProductionChecks?.add(1, this._metricAttributes);
131
118
  await this.spanAsync("produceBlock", async () => {
@@ -134,19 +121,13 @@ var ProducerActor = class extends Actor {
134
121
  return;
135
122
  }
136
123
  await this._produceBlockMutex.runExclusive(async () => {
137
- const headStart = Date.now();
138
124
  const head = (await this.blockViewer.currentBlock())[0];
139
- const headDuration = Date.now() - headStart;
140
- if (headDuration > 500) this.logger?.warn(`[Slow] Fetched head in ${headDuration}ms: 0x${toHex(head._hash)}`);
141
125
  const headHash = head._hash;
142
126
  if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {
143
127
  this.logger?.log("Block already produced:", `0x${toHex(this._lastProducedBlock[0].block)}`, this._lastProducedBlock[0].block);
144
128
  } else {
145
129
  this._producerActorBlockProductionAttempts?.add(1, this._metricAttributes);
146
- const nextStart = Date.now();
147
- const nextBlock = await this.producer.next(head);
148
- const nextDuration = Date.now() - nextStart;
149
- if (nextDuration > 1e3) this.logger?.warn(`[Slow] Generated next block in ${nextDuration}ms, block: ${nextBlock?.[0]._hash}`);
130
+ const nextBlock = await this.blockRunner.next(head);
150
131
  if (nextBlock) {
151
132
  const displayBlockNumber = `0x${toHex(nextBlock[0].block)}`;
152
133
  this.logger?.log("Produced block:", displayBlockNumber);
@@ -166,10 +147,15 @@ var ProducerActor = class extends Actor {
166
147
  }
167
148
  async redeclareIntent() {
168
149
  await this.spanAsync("redeclareIntent", async () => {
169
- if (this.params.config.producer.disableIntentRedeclaration) return;
150
+ if (this.config.producer.disableIntentRedeclaration) return;
170
151
  const head = (await this.blockViewer.currentBlock())[0];
171
152
  if (isUndefined(head)) return;
172
153
  const currentBlock = head.block;
154
+ const blocksUntilExpiration = this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock);
155
+ if (blocksUntilExpiration > _ProducerActor.RedeclarationWindow * 0.1) {
156
+ this._lastRedeclarationIntent = void 0;
157
+ return;
158
+ }
173
159
  if (this._lastRedeclarationIntent) {
174
160
  if (this._lastRedeclarationIntent.exp > currentBlock) return;
175
161
  this._lastRedeclarationIntent = void 0;
@@ -179,7 +165,7 @@ var ProducerActor = class extends Actor {
179
165
  return;
180
166
  }
181
167
  if (!await this.validateCurrentStake()) {
182
- this.logger?.error(`Add stake to contract address ${this.params.config.chain.id} for the producer to declare it's intent.`);
168
+ this.logger?.error(`Add stake to contract address ${this.config.chain.id} for the producer to declare it's intent.`);
183
169
  return;
184
170
  }
185
171
  this.logger?.log("Creating redeclaration intent for producer:", this.account.address);
@@ -203,7 +189,9 @@ var ProducerActor = class extends Actor {
203
189
  if (isDefined(head)) {
204
190
  const balances = await this.accountBalanceViewer.accountBalances([
205
191
  this.account.address
206
- ], head);
192
+ ], {
193
+ head
194
+ });
207
195
  const currentBalance = balances[this.account.address] ?? 0n;
208
196
  if (currentBalance <= 0n) {
209
197
  this.logger?.error(`Producer ${this.account.address} has no balance.`);
@@ -228,87 +216,52 @@ ProducerActor = _ts_decorate([
228
216
  ], ProducerActor);
229
217
 
230
218
  // src/runProducer.ts
231
- import { assertEx, exists } from "@xylabs/sdk-js";
232
- import { initProducerAccount } from "@xyo-network/chain-orchestration";
233
- import { initBlockRewardViewer, initChainService, initTimeService } from "@xyo-network/chain-services";
234
- import { ChainContractViewerMoniker } from "@xyo-network/xl1-protocol-sdk";
235
- import { AccountBalanceViewerRpcSchemas, BlockViewerRpcSchemas, HttpRpcTransport, JsonRpcAccountBalanceViewer, JsonRpcBlockViewer, JsonRpcMempoolRunner, JsonRpcMempoolViewer, JsonRpcStakeTotalsViewer, MempoolRunnerRpcSchemas, MempoolViewerRpcSchemas, StakeTotalsViewerRpcSchemas } from "@xyo-network/xl1-rpc";
236
- var runProducer = /* @__PURE__ */ __name(async (context) => {
237
- const { config, logger, orchestrator } = context;
238
- const endpoint = assertEx(config.services?.apiEndpoint, () => "No API endpoint configured");
239
- const account = await initProducerAccount({
240
- config,
241
- logger
219
+ import { asAddress, assertEx, exists } from "@xylabs/sdk-js";
220
+ import { initProducerAccount as initProducerAccount2 } from "@xyo-network/chain-orchestration";
221
+ import { validateHydratedBlock, validateHydratedBlockState } from "@xyo-network/chain-validation";
222
+ import { SimpleBlockRunner as SimpleBlockRunner2 } from "@xyo-network/chain-services";
223
+ import { SimpleBlockRewardViewer, SimpleBlockValidationViewer } from "@xyo-network/xl1-protocol-sdk";
224
+ import { buildJsonRpcProviderLocator } from "@xyo-network/xl1-providers";
225
+ import { HttpRpcTransport } from "@xyo-network/xl1-rpc";
226
+ var getProviderFactoryLocator = /* @__PURE__ */ __name(async (context, account, rewardAddress) => {
227
+ const endpoint = assertEx(context.config.services.apiEndpoint, () => "API endpoint is required in config.services.apiEndpoint");
228
+ const transportFactory = /* @__PURE__ */ __name((schemas) => new HttpRpcTransport(endpoint, schemas), "transportFactory");
229
+ const locator = await buildJsonRpcProviderLocator({
230
+ context,
231
+ transportFactory
242
232
  });
243
- const accountBalanceViewer = new JsonRpcAccountBalanceViewer(new HttpRpcTransport(endpoint, {
244
- ...AccountBalanceViewerRpcSchemas
245
- }));
246
- const blockViewer = new JsonRpcBlockViewer(new HttpRpcTransport(endpoint, {
247
- ...BlockViewerRpcSchemas
233
+ locator.register(SimpleBlockRewardViewer.factory());
234
+ locator.register(SimpleBlockValidationViewer.factory({
235
+ state: validateHydratedBlockState,
236
+ value: validateHydratedBlock
248
237
  }));
249
- const stakeTotalsViewer = new JsonRpcStakeTotalsViewer(new HttpRpcTransport(endpoint, {
250
- ...StakeTotalsViewerRpcSchemas
251
- }));
252
- const chainId = (await blockViewer.currentBlock())[0].chain;
253
- const mempoolViewer = new JsonRpcMempoolViewer(new HttpRpcTransport(endpoint, {
254
- ...MempoolViewerRpcSchemas
255
- }));
256
- const mempoolRunner = new JsonRpcMempoolRunner(new HttpRpcTransport(endpoint, {
257
- ...MempoolRunnerRpcSchemas
258
- }));
259
- const chainService = await initChainService({
238
+ locator.register(SimpleBlockRunner2.factory({
260
239
  account,
261
- config,
262
- logger
240
+ rewardAddress
241
+ }));
242
+ return locator;
243
+ }, "getProviderFactoryLocator");
244
+ var runProducer = /* @__PURE__ */ __name(async ({ config, logger, orchestrator }) => {
245
+ const account = await initProducerAccount2({
246
+ config
263
247
  });
264
- const chainContractViewer = {
265
- forkedAtBlockNumber: /* @__PURE__ */ __name(function() {
266
- return chainService.forkedAtBlockNumber();
267
- }, "forkedAtBlockNumber"),
268
- forkedAtHash: /* @__PURE__ */ __name(function() {
269
- return chainService.forkedAtHash();
270
- }, "forkedAtHash"),
271
- forkedChainId: /* @__PURE__ */ __name(function() {
272
- return chainService.forkedChainId();
273
- }, "forkedChainId"),
274
- minWithdrawalBlocks: /* @__PURE__ */ __name(function() {
275
- return chainService.minWithdrawalBlocks();
276
- }, "minWithdrawalBlocks"),
277
- rewardsContract: /* @__PURE__ */ __name(function() {
278
- return chainService.rewardsContract();
279
- }, "rewardsContract"),
280
- stakingTokenAddress: /* @__PURE__ */ __name(function() {
281
- return chainService.stakingTokenAddress();
282
- }, "stakingTokenAddress"),
283
- moniker: ChainContractViewerMoniker
284
- };
285
- const blockRewardViewer = await initBlockRewardViewer({
248
+ logger.info(`Running producer for account ${account.address}`);
249
+ const rewardAddress = asAddress(config.producer.rewardAddress, () => "rewardAddress is required in config.producer");
250
+ logger.info(`Using reward address ${rewardAddress}`);
251
+ const locator = await getProviderFactoryLocator({
286
252
  config,
287
253
  logger,
288
- chainContractViewer
289
- });
290
- const timeSyncViewer = await initTimeService({
254
+ singletons: {}
255
+ }, account, rewardAddress);
256
+ const context = {
257
+ locator,
291
258
  config,
292
- logger,
293
- blockViewer
294
- });
259
+ singletons: locator.context.singletons
260
+ };
295
261
  const params = {
296
- account,
297
262
  id: "ProducerActor",
298
- chainId,
299
- config,
300
- viewers: {
301
- accountBalanceViewer,
302
- blockViewer,
303
- stakeTotalsViewer,
304
- mempoolViewer,
305
- time: timeSyncViewer
306
- },
307
- blockRewardViewer,
308
- runners: {
309
- mempoolRunner
310
- },
311
- logger
263
+ context,
264
+ account
312
265
  };
313
266
  const producer = await ProducerActor.create(params);
314
267
  const actors = [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ProducerActor.ts","../../src/runProducer.ts"],"sourcesContent":["import type { Attributes, Counter } from '@opentelemetry/api'\nimport type { CreatableName } from '@xylabs/sdk-js'\nimport {\n asAddress,\n creatable, isDefined, isUndefined, toHex,\n ZERO_ADDRESS,\n} from '@xylabs/sdk-js'\nimport { AccountInstance } from '@xyo-network/account-model'\nimport { Actor, type ActorParams } from '@xyo-network/chain-orchestration'\nimport { createDeclarationIntent } from '@xyo-network/chain-protocol'\nimport { SimpleBlockRunner, SimpleBlockRunnerParams } from '@xyo-network/chain-services'\nimport type {\n ChainId,\n ChainStakeIntent, HydratedBlockWithHashMeta,\n XL1BlockNumber,\n} from '@xyo-network/xl1-protocol'\nimport { asXL1BlockNumber } from '@xyo-network/xl1-protocol'\nimport {\n AccountBalanceViewer,\n BlockProducerService, BlockRewardViewer, BlockViewer, buildTransaction,\n Config,\n MempoolRunner,\n MempoolViewer,\n StakeTotalsViewer,\n TimeSyncViewer,\n} from '@xyo-network/xl1-protocol-sdk'\nimport { Mutex } from 'async-mutex'\n\nexport type ProducerActorParams = ActorParams<{\n account: AccountInstance\n blockRewardViewer: BlockRewardViewer\n chainId: ChainId\n config: Config\n runners: {\n mempoolRunner: MempoolRunner\n }\n viewers: {\n accountBalanceViewer: AccountBalanceViewer\n blockViewer: BlockViewer\n mempoolViewer: MempoolViewer\n stakeTotalsViewer: StakeTotalsViewer\n time: TimeSyncViewer\n }\n}>\n\nconst SHOULD_REGISTER_REDECLARATION_INTENT_TIMER = true\nconst TEN_MINUTES = 10 * 60 * 1000 // 10 minutes in milliseconds\n\n@creatable()\nexport class ProducerActor extends Actor<ProducerActorParams> {\n protected _lastProducedBlock: HydratedBlockWithHashMeta | undefined\n protected _lastRedeclarationIntent: ChainStakeIntent | undefined\n protected _metricAttributes: Attributes | undefined\n protected _producerActorBlockProductionAttempts: Counter<Attributes> | undefined\n protected _producerActorBlockProductionChecks: Counter<Attributes> | undefined\n protected _producerActorBlocksProduced: Counter<Attributes> | undefined\n protected _producerActorBlocksPublished: Counter<Attributes> | undefined\n\n private _produceBlockMutex = new Mutex()\n private _producer: BlockProducerService | undefined\n\n protected get account() {\n return this.params.account!\n }\n\n protected get accountBalanceViewer() {\n return this.params.viewers.accountBalanceViewer!\n }\n\n protected get blockViewer() {\n return this.params.viewers.blockViewer!\n }\n\n protected get chainId() {\n return this.params.chainId!\n }\n\n protected get config() {\n return this.params.config!\n }\n\n protected get mempoolRunner() {\n return this.params.runners.mempoolRunner!\n }\n\n protected get mempoolViewer() {\n return this.params.viewers.mempoolViewer!\n }\n\n protected get producer() {\n return this._producer!\n }\n\n protected get stakeTotalsViewer() {\n return this.params.viewers.stakeTotalsViewer!\n }\n\n static override async paramsHandler<T extends ActorParams>(params?: Partial<T>) {\n return await super.paramsHandler({ ...params, name: (params?.name ?? 'Producer') as CreatableName })\n }\n\n override async createHandler() {\n await super.createHandler()\n // Create the consistent meter attributes that will\n // be included with all metrics from this actor\n this._metricAttributes = { address: this.account.address.toString() }\n // Create the metrics\n this._producerActorBlockProductionChecks = this.meter?.createCounter(\n 'producer_actor_block_production_checks',\n { description: 'Number of block production checks' },\n )\n this._producerActorBlockProductionAttempts = this.meter?.createCounter(\n 'producer_actor_block_production_attempts',\n { description: 'Number of block production attempts' },\n )\n this._producerActorBlocksProduced = this.meter?.createCounter(\n 'producer_actor_blocks_produced',\n { description: 'Number of blocks produced' },\n )\n this._producerActorBlocksPublished = this.meter?.createCounter(\n 'producer_actor_blocks_published',\n { description: 'Number of blocks published' },\n )\n const params = {\n account: this.account,\n balanceViewer: this.accountBalanceViewer,\n config: this.config,\n chainId: this.chainId,\n mempoolRunner: this.mempoolRunner,\n mempoolViewer: this.mempoolViewer,\n blockRewardViewer: this.params.blockRewardViewer!,\n rewardAddress: asAddress(\n this.config.producer.rewardAddress ?? ZERO_ADDRESS,\n () => `Producer config must have a valid reward address configured [${this.params.config.producer.rewardAddress}]`,\n ),\n time: this.params.viewers.time!,\n } satisfies SimpleBlockRunnerParams\n this._producer = await SimpleBlockRunner.create(params)\n }\n\n override async startHandler() {\n await super.startHandler()\n // Register a timer to check if we should produce a block\n this.registerTimer('BlockProductionTimer', async () => {\n await this.produceBlock()\n }, 2000, 1500/* 500 */)\n\n if (SHOULD_REGISTER_REDECLARATION_INTENT_TIMER) {\n // Register a timer to check if we should redeclare the producer\n this.registerTimer('ProducerRedeclarationTimer', async () => {\n await this.redeclareIntent()\n }, TEN_MINUTES, TEN_MINUTES)\n }\n }\n\n // protected async calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): Promise<number> {\n // // Decide if we need to redeclare intent\n // const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.account.address, 'producer')\n // // TODO: This doesn't handle the case where the producer had declared a range for the future\n // // but we're in a range that's not the future\n // // Sort in ascending order based on ending range to get range with highest ending block\n // const lastRange = ranges.toSorted((a, b) => a[1] > b[1] ? 1 : -1).at(-1)\n\n // // Use the most recent range's end block as the current declaration end OR\n // const [, currentDeclarationEnd] = lastRange\n // // If we have no ranges, we need to declare intent, so use the current block\n // ?? [undefined, currentBlock]\n\n // // Calculate the time until the producer's declaration expires\n // const timeToProducerExpiration = currentDeclarationEnd - currentBlock\n // return timeToProducerExpiration\n // }\n\n protected async produceBlock(): Promise<void> {\n this._producerActorBlockProductionChecks?.add(1, this._metricAttributes)\n await this.spanAsync('produceBlock', async () => {\n if (this._produceBlockMutex.isLocked()) {\n this.logger?.log('Skipping block production, previous production still in progress')\n return\n }\n\n await this._produceBlockMutex.runExclusive(async () => {\n // Get the updated head\n const headStart = Date.now()\n const head = (await this.blockViewer.currentBlock())[0]\n const headDuration = Date.now() - headStart\n if (headDuration > 500) this.logger?.warn(`[Slow] Fetched head in ${headDuration}ms: 0x${toHex(head._hash)}`)\n // Check if we've already produced the next block for this head\n const headHash = head._hash\n // If our last produced block was the next block for the current head, we do not\n // need to produce another. This prevents duplicate blocks from being produced\n if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {\n this.logger?.log('Block already produced:', `0x${toHex(this._lastProducedBlock[0].block)}`, this._lastProducedBlock[0].block)\n } else {\n this._producerActorBlockProductionAttempts?.add(1, this._metricAttributes)\n // Produce the next block\n const nextStart = Date.now()\n const nextBlock = await this.producer.next(head)\n const nextDuration = Date.now() - nextStart\n if (nextDuration > 1000) this.logger?.warn(`[Slow] Generated next block in ${nextDuration}ms, block: ${nextBlock?.[0]._hash}`)\n // If it was produced\n if (nextBlock) {\n const displayBlockNumber = `0x${toHex(nextBlock[0].block)}`\n this.logger?.log('Produced block:', displayBlockNumber)\n this._producerActorBlocksProduced?.add(1, this._metricAttributes)\n // Insert the block into the chain\n await this.mempoolRunner.submitBlocks([nextBlock])\n this.logger?.log('Published block:', displayBlockNumber, nextBlock[0].block)\n this._producerActorBlocksPublished?.add(1, this._metricAttributes)\n // Record that we have produced a block so we do not produce it again\n this._lastProducedBlock = nextBlock\n } else {\n this.logger?.log('No block produced at this time.')\n }\n }\n })\n })\n }\n\n protected async redeclareIntent(): Promise<void> {\n await this.spanAsync('redeclareIntent', async () => {\n // Decide if we should redeclare intent\n if (this.params.config.producer.disableIntentRedeclaration) return\n\n // Get the current block\n const head = (await this.blockViewer.currentBlock())[0]\n if (isUndefined(head)) return\n const currentBlock = head.block\n\n // // Calculate the time until the producer's declaration expires\n // const blocksUntilExpiration = await this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock)\n\n // // Allow the producer time to redeclare itself via block production\n // // (for free) before submitting a redeclaration intent transaction.\n // if (blocksUntilExpiration > BaseBlockProducerService.RedeclarationWindow * 0.1) {\n // // Clear any previous redeclaration intent\n // this._lastRedeclarationIntent = undefined\n // // No need to redeclare yet\n // return\n // }\n\n // If we already have a valid redeclaration intent, do not create another\n // unless it has expired.\n if (this._lastRedeclarationIntent) {\n // Check if the last redeclaration intent is still valid\n if (this._lastRedeclarationIntent.exp > currentBlock) return\n // If it has expired, clear the last redeclaration intent\n this._lastRedeclarationIntent = undefined\n }\n\n // Check if we have a valid balance before declaring intent\n if (!await this.validateCurrentBalance()) {\n this.logger?.error(\n `Add balance to address ${this.account.address} for the producer to declare it's intent.`,\n )\n return\n }\n\n // Check if we have a valid stake before declaring intent\n if (!(await this.validateCurrentStake())) {\n this.logger?.error(\n `Add stake to contract address ${this.params.config.chain.id}`\n + ' for the producer to declare it\\'s intent.',\n )\n return\n }\n\n // Create a redeclaration intent\n this.logger?.log('Creating redeclaration intent for producer:', this.account.address)\n const redeclarationIntent = createDeclarationIntent(\n this.account.address,\n 'producer',\n currentBlock,\n currentBlock + SimpleBlockRunner.RedeclarationDuration,\n )\n\n // Submit the redeclaration intent\n await this.submitRedeclarationIntent(currentBlock, redeclarationIntent)\n\n // On successful submission, save the redeclaration intent\n this._lastRedeclarationIntent = redeclarationIntent\n })\n }\n\n protected async submitRedeclarationIntent(currentBlock: XL1BlockNumber, redeclarationIntent: ChainStakeIntent): Promise<void> {\n this.logger?.log('Submitting redeclaration intent for producer:', this.account.address)\n // Create a transaction to submit the redeclaration intent\n const tx = await buildTransaction(\n this.chainId,\n [redeclarationIntent],\n [],\n this.account,\n currentBlock,\n asXL1BlockNumber(currentBlock + 1000, true),\n )\n\n // Submit the redeclaration intent\n await this.mempoolRunner.submitTransactions([tx])\n\n this.logger?.log('Submitted redeclaration intent for producer:', this.account.address)\n }\n\n protected async validateCurrentBalance(): Promise<boolean> {\n // Check if we have a valid balance before declaring intent\n const head = this._lastProducedBlock?.[0]._hash\n if (isDefined(head)) {\n const balances = await this.accountBalanceViewer.accountBalances([this.account.address], head)\n const currentBalance = balances[this.account.address] ?? 0n\n if (currentBalance <= 0n) {\n this.logger?.error(`Producer ${this.account.address} has no balance.`)\n return false\n }\n return true\n }\n return true\n }\n\n protected async validateCurrentStake(): Promise<boolean> {\n // Use StakeIntentService to get the required minimum stake\n const requiredMinimumStake = 1n // this.stakeIntentService.getRequiredMinimumStakeForIntent('producer')\n // Check if we have a valid stake before declaring intent\n const currentStake = await this.stakeTotalsViewer.activeByStaked(this.account.address)\n if (currentStake < requiredMinimumStake) {\n this.logger?.error(`Producer ${this.account.address} has insufficient stake.`)\n return false\n }\n return true\n }\n}\n","import type { Address, Logger } from '@xylabs/sdk-js'\nimport { assertEx, exists } from '@xylabs/sdk-js'\nimport { initProducerAccount, type OrchestratorInstance } from '@xyo-network/chain-orchestration'\nimport {\n initBlockRewardViewer, initChainService, initTimeService,\n} from '@xyo-network/chain-services'\nimport {\n type ChainContractViewer, ChainContractViewerMoniker, type Config,\n} from '@xyo-network/xl1-protocol-sdk'\nimport {\n AccountBalanceViewerRpcSchemas, BlockViewerRpcSchemas, HttpRpcTransport, JsonRpcAccountBalanceViewer,\n JsonRpcBlockViewer,\n JsonRpcMempoolRunner,\n JsonRpcMempoolViewer,\n JsonRpcStakeTotalsViewer,\n MempoolRunnerRpcSchemas,\n MempoolViewerRpcSchemas,\n StakeTotalsViewerRpcSchemas,\n} from '@xyo-network/xl1-rpc'\n\nimport { ProducerActor, type ProducerActorParams } from './ProducerActor.ts'\n\ninterface RunProducerContext {\n config: Config\n logger: Logger\n orchestrator: OrchestratorInstance\n}\n\nexport const runProducer = async (context: RunProducerContext) => {\n const {\n config, logger, orchestrator,\n } = context\n\n const endpoint = assertEx(config.services?.apiEndpoint, () => 'No API endpoint configured')\n const account = await initProducerAccount({ config, logger })\n const accountBalanceViewer = new JsonRpcAccountBalanceViewer(new HttpRpcTransport(endpoint, { ...AccountBalanceViewerRpcSchemas }))\n const blockViewer = new JsonRpcBlockViewer(new HttpRpcTransport(endpoint, { ...BlockViewerRpcSchemas }))\n const stakeTotalsViewer = new JsonRpcStakeTotalsViewer(new HttpRpcTransport(endpoint, { ...StakeTotalsViewerRpcSchemas }))\n const chainId = (await blockViewer.currentBlock())[0].chain\n const mempoolViewer = new JsonRpcMempoolViewer(new HttpRpcTransport(endpoint, { ...MempoolViewerRpcSchemas }))\n const mempoolRunner = new JsonRpcMempoolRunner(new HttpRpcTransport(endpoint, { ...MempoolRunnerRpcSchemas }))\n const chainService = await initChainService({\n account, config, logger,\n })\n const chainContractViewer = {\n forkedAtBlockNumber: function (): Promise<bigint> {\n return chainService.forkedAtBlockNumber()\n },\n forkedAtHash: function (): Promise<bigint> {\n return chainService.forkedAtHash()\n },\n forkedChainId: function (): Promise<Address> {\n return chainService.forkedChainId()\n },\n minWithdrawalBlocks: function (): Promise<bigint> {\n return chainService.minWithdrawalBlocks()\n },\n rewardsContract: function (): Promise<string> {\n return chainService.rewardsContract()\n },\n stakingTokenAddress: function (): Promise<string> {\n return chainService.stakingTokenAddress()\n },\n moniker: ChainContractViewerMoniker,\n } satisfies ChainContractViewer\n const blockRewardViewer = await initBlockRewardViewer({\n config, logger, chainContractViewer,\n })\n const timeSyncViewer = await initTimeService({\n config, logger, blockViewer,\n })\n\n // Create actors\n const params = {\n account,\n id: 'ProducerActor',\n chainId,\n config,\n viewers: {\n accountBalanceViewer,\n blockViewer,\n stakeTotalsViewer,\n mempoolViewer,\n time: timeSyncViewer,\n },\n blockRewardViewer,\n runners: { mempoolRunner },\n logger,\n } satisfies ProducerActorParams\n // const apiEndpoint = config.services.apiEndpoint\n // const balances = isDefined(apiEndpoint) ? undefined : await BalanceActor.create(params)\n const producer = await ProducerActor.create(params)\n const actors = [producer].filter(exists)\n\n for (const actor of actors) {\n // Register the actor with the orchestrator\n await orchestrator.registerActor(actor)\n }\n // Start the orchestrator => automatically activates the actor\n await orchestrator.start()\n}\n"],"mappings":"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","names":["asAddress","creatable","isDefined","isUndefined","toHex","ZERO_ADDRESS","Actor","createDeclarationIntent","SimpleBlockRunner","asXL1BlockNumber","buildTransaction","Mutex","SHOULD_REGISTER_REDECLARATION_INTENT_TIMER","TEN_MINUTES","ProducerActor","Actor","_lastProducedBlock","_lastRedeclarationIntent","_metricAttributes","_producerActorBlockProductionAttempts","_producerActorBlockProductionChecks","_producerActorBlocksProduced","_producerActorBlocksPublished","_produceBlockMutex","Mutex","_producer","account","params","accountBalanceViewer","viewers","blockViewer","chainId","config","mempoolRunner","runners","mempoolViewer","producer","stakeTotalsViewer","paramsHandler","name","createHandler","address","toString","meter","createCounter","description","balanceViewer","blockRewardViewer","rewardAddress","asAddress","ZERO_ADDRESS","time","SimpleBlockRunner","create","startHandler","registerTimer","produceBlock","redeclareIntent","add","spanAsync","isLocked","logger","log","runExclusive","headStart","Date","now","head","currentBlock","headDuration","warn","toHex","_hash","headHash","previous","block","nextStart","nextBlock","next","nextDuration","displayBlockNumber","submitBlocks","disableIntentRedeclaration","isUndefined","exp","undefined","validateCurrentBalance","error","validateCurrentStake","chain","id","redeclarationIntent","createDeclarationIntent","RedeclarationDuration","submitRedeclarationIntent","tx","buildTransaction","asXL1BlockNumber","submitTransactions","isDefined","balances","accountBalances","currentBalance","requiredMinimumStake","currentStake","activeByStaked","assertEx","exists","initProducerAccount","initBlockRewardViewer","initChainService","initTimeService","ChainContractViewerMoniker","AccountBalanceViewerRpcSchemas","BlockViewerRpcSchemas","HttpRpcTransport","JsonRpcAccountBalanceViewer","JsonRpcBlockViewer","JsonRpcMempoolRunner","JsonRpcMempoolViewer","JsonRpcStakeTotalsViewer","MempoolRunnerRpcSchemas","MempoolViewerRpcSchemas","StakeTotalsViewerRpcSchemas","runProducer","context","config","logger","orchestrator","endpoint","assertEx","services","apiEndpoint","account","initProducerAccount","accountBalanceViewer","JsonRpcAccountBalanceViewer","HttpRpcTransport","AccountBalanceViewerRpcSchemas","blockViewer","JsonRpcBlockViewer","BlockViewerRpcSchemas","stakeTotalsViewer","JsonRpcStakeTotalsViewer","StakeTotalsViewerRpcSchemas","chainId","currentBlock","chain","mempoolViewer","JsonRpcMempoolViewer","MempoolViewerRpcSchemas","mempoolRunner","JsonRpcMempoolRunner","MempoolRunnerRpcSchemas","chainService","initChainService","chainContractViewer","forkedAtBlockNumber","forkedAtHash","forkedChainId","minWithdrawalBlocks","rewardsContract","stakingTokenAddress","moniker","ChainContractViewerMoniker","blockRewardViewer","initBlockRewardViewer","timeSyncViewer","initTimeService","params","id","viewers","time","runners","producer","ProducerActor","create","actors","filter","exists","actor","registerActor","start"]}
1
+ {"version":3,"sources":["../../src/ProducerActor.ts","../../src/runProducer.ts"],"sourcesContent":["import type { Attributes, Counter } from '@opentelemetry/api'\nimport type { CreatableName } from '@xylabs/sdk-js'\nimport {\n creatable, isDefined, isUndefined, toHex,\n} from '@xylabs/sdk-js'\nimport {\n Actor, type ActorParams, initProducerAccount,\n} from '@xyo-network/chain-orchestration'\nimport { SimpleBlockRunner } from '@xyo-network/chain-services'\nimport type {\n ChainId,\n ChainStakeIntent, HydratedBlockWithHashMeta,\n XL1BlockNumber,\n} from '@xyo-network/xl1-protocol'\nimport { asXL1BlockNumber } from '@xyo-network/xl1-protocol'\nimport {\n AccountBalanceViewer, AccountBalanceViewerMoniker, BlockRunner, BlockRunnerMoniker,\n BlockViewer, BlockViewerMoniker, buildTransaction,\n Config,\n createDeclarationIntent,\n getDefaultConfig,\n MempoolRunner,\n MempoolRunnerMoniker,\n MempoolViewer,\n MempoolViewerMoniker,\n StakeTotalsViewer,\n StakeTotalsViewerMoniker,\n} from '@xyo-network/xl1-protocol-sdk'\nimport { Mutex } from 'async-mutex'\n\nexport type ProducerActorParams = ActorParams\n\nconst SHOULD_REGISTER_REDECLARATION_INTENT_TIMER = true\nconst TEN_MINUTES = 10 * 60 * 1000 // 10 minutes in milliseconds\n\n@creatable()\nexport class ProducerActor extends Actor<ProducerActorParams> {\n static readonly RedeclarationWindow = 10_000\n\n protected _lastProducedBlock?: HydratedBlockWithHashMeta\n protected _lastRedeclarationIntent?: ChainStakeIntent\n protected _metricAttributes?: Attributes\n protected _producerActorBlockProductionAttempts?: Counter<Attributes>\n protected _producerActorBlockProductionChecks?: Counter<Attributes>\n protected _producerActorBlocksProduced?: Counter<Attributes>\n protected _producerActorBlocksPublished?: Counter<Attributes>\n\n private _accountBalanceViewer?: AccountBalanceViewer\n private _blockRunner?: BlockRunner\n private _blockViewer?: BlockViewer\n private _chainId?: ChainId\n private _mempoolRunner?: MempoolRunner\n private _mempoolViewer?: MempoolViewer\n\n private _produceBlockMutex = new Mutex()\n\n private _stakeTotalsViewer?: StakeTotalsViewer\n\n protected get accountBalanceViewer() {\n return this._accountBalanceViewer!\n }\n\n protected get blockRunner() {\n return this._blockRunner!\n }\n\n protected get blockViewer() {\n return this._blockViewer!\n }\n\n protected get chainId() {\n return this._chainId!\n }\n\n protected get mempoolRunner() {\n return this._mempoolRunner!\n }\n\n protected get mempoolViewer() {\n return this._mempoolViewer!\n }\n\n protected get stakeTotalsViewer() {\n return this._stakeTotalsViewer!\n }\n\n static override async paramsHandler<T extends ActorParams>(params?: Partial<T>) {\n const config: Config = params?.context?.config ?? getDefaultConfig()\n const account = params?.account ?? await initProducerAccount({ config })\n return await super.paramsHandler({\n ...params, name: (params?.name ?? 'Producer') as CreatableName, account,\n })\n }\n\n override async createHandler() {\n await super.createHandler()\n // Create the consistent meter attributes that will\n // be included with all metrics from this actor\n this._metricAttributes = { address: this.account.address.toString() }\n // Create the metrics\n this._producerActorBlockProductionChecks = this.meter?.createCounter(\n 'producer_actor_block_production_checks',\n { description: 'Number of block production checks' },\n )\n this._producerActorBlockProductionAttempts = this.meter?.createCounter(\n 'producer_actor_block_production_attempts',\n { description: 'Number of block production attempts' },\n )\n this._producerActorBlocksProduced = this.meter?.createCounter(\n 'producer_actor_blocks_produced',\n { description: 'Number of blocks produced' },\n )\n this._producerActorBlocksPublished = this.meter?.createCounter(\n 'producer_actor_blocks_published',\n { description: 'Number of blocks published' },\n )\n this._accountBalanceViewer = await this.locator.getInstance<AccountBalanceViewer>(AccountBalanceViewerMoniker)\n this._blockRunner = await this.locator.getInstance<BlockRunner>(BlockRunnerMoniker)\n this._blockViewer = await this.locator.getInstance<BlockViewer>(BlockViewerMoniker)\n this._mempoolRunner = await this.locator.getInstance<MempoolRunner>(MempoolRunnerMoniker)\n this._mempoolViewer = await this.locator.getInstance<MempoolViewer>(MempoolViewerMoniker)\n this._stakeTotalsViewer = await this.locator.getInstance<StakeTotalsViewer>(StakeTotalsViewerMoniker)\n }\n\n override async startHandler() {\n await super.startHandler()\n // Register a timer to check if we should produce a block\n this.registerTimer('BlockProductionTimer', async () => {\n await this.produceBlock()\n }, 2000, 1500/* 500 */)\n\n if (SHOULD_REGISTER_REDECLARATION_INTENT_TIMER) {\n // Register a timer to check if we should redeclare the producer\n this.registerTimer('ProducerRedeclarationTimer', async () => {\n await this.redeclareIntent()\n }, TEN_MINUTES, TEN_MINUTES)\n }\n }\n\n protected calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): number {\n return (this._lastRedeclarationIntent?.exp ?? currentBlock) - currentBlock\n }\n\n protected async produceBlock(): Promise<void> {\n this._producerActorBlockProductionChecks?.add(1, this._metricAttributes)\n await this.spanAsync('produceBlock', async () => {\n if (this._produceBlockMutex.isLocked()) {\n this.logger?.log('Skipping block production, previous production still in progress')\n return\n }\n\n await this._produceBlockMutex.runExclusive(async () => {\n // Get the updated head\n const head = (await this.blockViewer.currentBlock())[0]\n // Check if we've already produced the next block for this head\n const headHash = head._hash\n // If our last produced block was the next block for the current head, we do not\n // need to produce another. This prevents duplicate blocks from being produced\n if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {\n this.logger?.log('Block already produced:', `0x${toHex(this._lastProducedBlock[0].block)}`, this._lastProducedBlock[0].block)\n } else {\n this._producerActorBlockProductionAttempts?.add(1, this._metricAttributes)\n // Produce the next block\n const nextBlock = await this.blockRunner.next(head)\n // If it was produced\n if (nextBlock) {\n const displayBlockNumber = `0x${toHex(nextBlock[0].block)}`\n this.logger?.log('Produced block:', displayBlockNumber)\n this._producerActorBlocksProduced?.add(1, this._metricAttributes)\n // Insert the block into the chain\n await this.mempoolRunner.submitBlocks([nextBlock])\n this.logger?.log('Published block:', displayBlockNumber, nextBlock[0].block)\n this._producerActorBlocksPublished?.add(1, this._metricAttributes)\n // Record that we have produced a block so we do not produce it again\n this._lastProducedBlock = nextBlock\n } else {\n this.logger?.log('No block produced at this time.')\n }\n }\n })\n })\n }\n\n protected async redeclareIntent(): Promise<void> {\n await this.spanAsync('redeclareIntent', async () => {\n // Decide if we should redeclare intent\n if (this.config.producer.disableIntentRedeclaration) return\n\n // Get the current block\n const head = (await this.blockViewer.currentBlock())[0]\n if (isUndefined(head)) return\n const currentBlock = head.block\n\n // // Calculate the time until the producer's declaration expires\n const blocksUntilExpiration = this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock)\n\n // Allow the producer time to redeclare itself via block production\n // (for free) before submitting a redeclaration intent transaction.\n if (blocksUntilExpiration > ProducerActor.RedeclarationWindow * 0.1) {\n // Clear any previous redeclaration intent\n this._lastRedeclarationIntent = undefined\n // No need to redeclare yet\n return\n }\n\n // If we already have a valid redeclaration intent, do not create another\n // unless it has expired.\n if (this._lastRedeclarationIntent) {\n // Check if the last redeclaration intent is still valid\n if (this._lastRedeclarationIntent.exp > currentBlock) return\n // If it has expired, clear the last redeclaration intent\n this._lastRedeclarationIntent = undefined\n }\n\n // Check if we have a valid balance before declaring intent\n if (!await this.validateCurrentBalance()) {\n this.logger?.error(\n `Add balance to address ${this.account.address} for the producer to declare it's intent.`,\n )\n return\n }\n\n // Check if we have a valid stake before declaring intent\n if (!(await this.validateCurrentStake())) {\n this.logger?.error(\n `Add stake to contract address ${this.config.chain.id}`\n + ' for the producer to declare it\\'s intent.',\n )\n return\n }\n\n // Create a redeclaration intent\n this.logger?.log('Creating redeclaration intent for producer:', this.account.address)\n const redeclarationIntent = createDeclarationIntent(\n this.account.address,\n 'producer',\n currentBlock,\n currentBlock + SimpleBlockRunner.RedeclarationDuration,\n )\n\n // Submit the redeclaration intent\n await this.submitRedeclarationIntent(currentBlock, redeclarationIntent)\n\n // On successful submission, save the redeclaration intent\n this._lastRedeclarationIntent = redeclarationIntent\n })\n }\n\n protected async submitRedeclarationIntent(currentBlock: XL1BlockNumber, redeclarationIntent: ChainStakeIntent): Promise<void> {\n this.logger?.log('Submitting redeclaration intent for producer:', this.account.address)\n // Create a transaction to submit the redeclaration intent\n const tx = await buildTransaction(\n this.chainId,\n [redeclarationIntent],\n [],\n this.account,\n currentBlock,\n asXL1BlockNumber(currentBlock + 1000, true),\n )\n\n // Submit the redeclaration intent\n await this.mempoolRunner.submitTransactions([tx])\n\n this.logger?.log('Submitted redeclaration intent for producer:', this.account.address)\n }\n\n protected async validateCurrentBalance(): Promise<boolean> {\n // Check if we have a valid balance before declaring intent\n const head = this._lastProducedBlock?.[0]._hash\n if (isDefined(head)) {\n const balances = await this.accountBalanceViewer.accountBalances([this.account.address], { head })\n const currentBalance = balances[this.account.address] ?? 0n\n if (currentBalance <= 0n) {\n this.logger?.error(`Producer ${this.account.address} has no balance.`)\n return false\n }\n return true\n }\n return true\n }\n\n protected async validateCurrentStake(): Promise<boolean> {\n // Use StakeIntentService to get the required minimum stake\n const requiredMinimumStake = 1n // this.stakeIntentService.getRequiredMinimumStakeForIntent('producer')\n // Check if we have a valid stake before declaring intent\n const currentStake = await this.stakeTotalsViewer.activeByStaked(this.account.address)\n if (currentStake < requiredMinimumStake) {\n this.logger?.error(`Producer ${this.account.address} has insufficient stake.`)\n return false\n }\n return true\n }\n}\n","import type { Address, Logger } from '@xylabs/sdk-js'\nimport {\n asAddress, assertEx, exists,\n} from '@xylabs/sdk-js'\nimport type { AccountInstance } from '@xyo-network/account-model'\nimport {\n type ActorContext, initProducerAccount, type OrchestratorInstance,\n} from '@xyo-network/chain-orchestration'\nimport { validateHydratedBlock, validateHydratedBlockState } from '@xyo-network/chain-validation'\nimport { SimpleBlockRunner } from '@xyo-network/chain-services'\nimport type {\n Config, CreatableProviderContext, ProviderFactoryLocatorInstance,\n} from '@xyo-network/xl1-protocol-sdk'\nimport { SimpleBlockRewardViewer, SimpleBlockValidationViewer } from '@xyo-network/xl1-protocol-sdk'\nimport { buildJsonRpcProviderLocator } from '@xyo-network/xl1-providers'\nimport {\n HttpRpcTransport, type RpcSchemaMap, type TransportFactory,\n} from '@xyo-network/xl1-rpc'\n\nimport { ProducerActor, type ProducerActorParams } from './ProducerActor.ts'\n\ninterface RunProducerContext {\n config: Config\n locator?: ProviderFactoryLocatorInstance\n logger: Logger\n orchestrator: OrchestratorInstance\n}\n\nconst getProviderFactoryLocator = async (\n context: Omit<CreatableProviderContext, 'locator'>,\n account: AccountInstance,\n rewardAddress: Address,\n) => {\n const endpoint = assertEx(context.config.services.apiEndpoint, () => 'API endpoint is required in config.services.apiEndpoint')\n const transportFactory: TransportFactory = (schemas: RpcSchemaMap) => new HttpRpcTransport(endpoint, schemas)\n const locator = await buildJsonRpcProviderLocator({ context, transportFactory })\n locator.register(SimpleBlockRewardViewer.factory())\n locator.register(SimpleBlockValidationViewer.factory<SimpleBlockValidationViewer>({ state: validateHydratedBlockState, value: validateHydratedBlock }))\n locator.register(SimpleBlockRunner.factory<SimpleBlockRunner>({ account, rewardAddress }))\n return locator\n}\n\nexport const runProducer = async ({\n config, logger, orchestrator,\n}: RunProducerContext) => {\n const account = await initProducerAccount({ config })\n logger.info(`Running producer for account ${account.address}`)\n const rewardAddress = asAddress(config.producer.rewardAddress, () => 'rewardAddress is required in config.producer')\n logger.info(`Using reward address ${rewardAddress}`)\n\n const locator = await getProviderFactoryLocator({\n config, logger, singletons: {},\n }, account, rewardAddress)\n\n const context: ActorContext = {\n locator, config, singletons: locator.context.singletons,\n }\n\n // Create actors\n const params = {\n id: 'ProducerActor', context, account,\n } satisfies ProducerActorParams\n // const apiEndpoint = config.services.apiEndpoint\n // const balances = isDefined(apiEndpoint) ? undefined : await BalanceActor.create(params)\n const producer = await ProducerActor.create(params)\n const actors = [producer].filter(exists)\n\n for (const actor of actors) {\n // Register the actor with the orchestrator\n await orchestrator.registerActor(actor)\n }\n // Start the orchestrator => automatically activates the actor\n await orchestrator.start()\n}\n"],"mappings":"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","names":["creatable","isDefined","isUndefined","toHex","Actor","initProducerAccount","SimpleBlockRunner","asXL1BlockNumber","AccountBalanceViewerMoniker","BlockRunnerMoniker","BlockViewerMoniker","buildTransaction","createDeclarationIntent","getDefaultConfig","MempoolRunnerMoniker","MempoolViewerMoniker","StakeTotalsViewerMoniker","Mutex","SHOULD_REGISTER_REDECLARATION_INTENT_TIMER","TEN_MINUTES","ProducerActor","Actor","RedeclarationWindow","_lastProducedBlock","_lastRedeclarationIntent","_metricAttributes","_producerActorBlockProductionAttempts","_producerActorBlockProductionChecks","_producerActorBlocksProduced","_producerActorBlocksPublished","_accountBalanceViewer","_blockRunner","_blockViewer","_chainId","_mempoolRunner","_mempoolViewer","_produceBlockMutex","Mutex","_stakeTotalsViewer","accountBalanceViewer","blockRunner","blockViewer","chainId","mempoolRunner","mempoolViewer","stakeTotalsViewer","paramsHandler","params","config","context","getDefaultConfig","account","initProducerAccount","name","createHandler","address","toString","meter","createCounter","description","locator","getInstance","AccountBalanceViewerMoniker","BlockRunnerMoniker","BlockViewerMoniker","MempoolRunnerMoniker","MempoolViewerMoniker","StakeTotalsViewerMoniker","startHandler","registerTimer","produceBlock","redeclareIntent","calculateBlocksUntilProducerDeclarationExpiration","currentBlock","exp","add","spanAsync","isLocked","logger","log","runExclusive","head","headHash","_hash","previous","toHex","block","nextBlock","next","displayBlockNumber","submitBlocks","producer","disableIntentRedeclaration","isUndefined","blocksUntilExpiration","undefined","validateCurrentBalance","error","validateCurrentStake","chain","id","redeclarationIntent","createDeclarationIntent","SimpleBlockRunner","RedeclarationDuration","submitRedeclarationIntent","tx","buildTransaction","asXL1BlockNumber","submitTransactions","isDefined","balances","accountBalances","currentBalance","requiredMinimumStake","currentStake","activeByStaked","asAddress","assertEx","exists","initProducerAccount","validateHydratedBlock","validateHydratedBlockState","SimpleBlockRunner","SimpleBlockRewardViewer","SimpleBlockValidationViewer","buildJsonRpcProviderLocator","HttpRpcTransport","getProviderFactoryLocator","context","account","rewardAddress","endpoint","assertEx","config","services","apiEndpoint","transportFactory","schemas","HttpRpcTransport","locator","buildJsonRpcProviderLocator","register","SimpleBlockRewardViewer","factory","SimpleBlockValidationViewer","state","validateHydratedBlockState","value","validateHydratedBlock","SimpleBlockRunner","runProducer","logger","orchestrator","initProducerAccount","info","address","asAddress","producer","singletons","params","id","ProducerActor","create","actors","filter","exists","actor","registerActor","start"]}
@@ -1,11 +1,12 @@
1
1
  import type { Logger } from '@xylabs/sdk-js';
2
2
  import { type OrchestratorInstance } from '@xyo-network/chain-orchestration';
3
- import { type Config } from '@xyo-network/xl1-protocol-sdk';
3
+ import type { Config, ProviderFactoryLocatorInstance } from '@xyo-network/xl1-protocol-sdk';
4
4
  interface RunProducerContext {
5
5
  config: Config;
6
+ locator?: ProviderFactoryLocatorInstance;
6
7
  logger: Logger;
7
8
  orchestrator: OrchestratorInstance;
8
9
  }
9
- export declare const runProducer: (context: RunProducerContext) => Promise<void>;
10
+ export declare const runProducer: ({ config, logger, orchestrator, }: RunProducerContext) => Promise<void>;
10
11
  export {};
11
12
  //# sourceMappingURL=runProducer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runProducer.d.ts","sourceRoot":"","sources":["../../src/runProducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAErD,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AAIjG,OAAO,EACiD,KAAK,MAAM,EAClE,MAAM,+BAA+B,CAAA;AActC,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,oBAAoB,CAAA;CACnC;AAED,eAAO,MAAM,WAAW,GAAU,SAAS,kBAAkB,kBAwE5D,CAAA"}
1
+ {"version":3,"file":"runProducer.d.ts","sourceRoot":"","sources":["../../src/runProducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAKrD,OAAO,EACmC,KAAK,oBAAoB,EAClE,MAAM,kCAAkC,CAAA;AAGzC,OAAO,KAAK,EACV,MAAM,EAA4B,8BAA8B,EACjE,MAAM,+BAA+B,CAAA;AAStC,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,8BAA8B,CAAA;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,oBAAoB,CAAA;CACnC;AAgBD,eAAO,MAAM,WAAW,GAAU,mCAE/B,kBAAkB,kBA6BpB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/chain-producer",
3
- "version": "1.17.7",
3
+ "version": "1.18.0",
4
4
  "description": "XYO Layer One Producer",
5
5
  "homepage": "https://xylabs.com",
6
6
  "bugs": {
@@ -50,36 +50,36 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@xylabs/sdk-js": "~5.0.51",
53
- "@xyo-network/chain-orchestration": "~1.17.7",
54
- "@xyo-network/chain-protocol": "~1.17.7",
55
- "@xyo-network/chain-services": "~1.17.7",
53
+ "@xyo-network/chain-orchestration": "~1.18.0",
54
+ "@xyo-network/chain-services": "~1.18.0",
56
55
  "@xyo-network/xl1-protocol": "~1.14.17",
57
- "@xyo-network/xl1-protocol-sdk": "~1.17.7",
58
- "@xyo-network/xl1-rpc": "~1.17.7",
56
+ "@xyo-network/xl1-protocol-sdk": "~1.18.0",
57
+ "@xyo-network/xl1-providers": "~1.18.0",
58
+ "@xyo-network/xl1-rpc": "~1.18.0",
59
59
  "async-mutex": "~0.5.0"
60
60
  },
61
61
  "devDependencies": {
62
- "@opentelemetry/api": "~1.9.0",
62
+ "@opentelemetry/api": "^1.9.0",
63
63
  "@types/compression": "~1.8.1",
64
64
  "@types/cors": "~2.8.19",
65
65
  "@types/express": "5.0.6",
66
66
  "@types/express-serve-static-core": "~5.1.0",
67
- "@types/node": "~25.0.1",
67
+ "@types/node": "~25.0.2",
68
68
  "@xylabs/sdk-js": "~5.0.51",
69
- "@xylabs/ts-scripts-yarn3": "~7.2.30",
70
- "@xylabs/tsconfig": "~7.2.30",
69
+ "@xylabs/ts-scripts-yarn3": "~7.2.32",
70
+ "@xylabs/tsconfig": "~7.2.32",
71
71
  "@xyo-network/account": "~5.2.17",
72
72
  "@xyo-network/account-model": "~5.2.17",
73
73
  "@xyo-network/archivist-abstract": "~5.2.17",
74
74
  "@xyo-network/bios-model": "~7.2.0",
75
75
  "@xyo-network/boundwitness-builder": "~5.2.17",
76
- "@xyo-network/chain-services": "~1.17.7",
76
+ "@xyo-network/chain-services": "~1.18.0",
77
77
  "@xyo-network/module-abstract-mongodb": "~5.2.17",
78
78
  "@xyo-network/module-model-mongodb": "~5.2.17",
79
79
  "@xyo-network/node-memory": "~5.2.17",
80
80
  "@xyo-network/xl1-protocol": "~1.14.17",
81
81
  "dotenv": "~17.2.3",
82
- "eslint": "^9.39.1",
82
+ "eslint": "^9.39.2",
83
83
  "nodemon": "~3.1.11",
84
84
  "tslib": "~2.8.1",
85
85
  "typescript": "~5.9.3",
@@ -1,14 +1,12 @@
1
1
  import type { Attributes, Counter } from '@opentelemetry/api'
2
2
  import type { CreatableName } from '@xylabs/sdk-js'
3
3
  import {
4
- asAddress,
5
4
  creatable, isDefined, isUndefined, toHex,
6
- ZERO_ADDRESS,
7
5
  } from '@xylabs/sdk-js'
8
- import { AccountInstance } from '@xyo-network/account-model'
9
- import { Actor, type ActorParams } from '@xyo-network/chain-orchestration'
10
- import { createDeclarationIntent } from '@xyo-network/chain-protocol'
11
- import { SimpleBlockRunner, SimpleBlockRunnerParams } from '@xyo-network/chain-services'
6
+ import {
7
+ Actor, type ActorParams, initProducerAccount,
8
+ } from '@xyo-network/chain-orchestration'
9
+ import { SimpleBlockRunner } from '@xyo-network/chain-services'
12
10
  import type {
13
11
  ChainId,
14
12
  ChainStakeIntent, HydratedBlockWithHashMeta,
@@ -16,87 +14,82 @@ import type {
16
14
  } from '@xyo-network/xl1-protocol'
17
15
  import { asXL1BlockNumber } from '@xyo-network/xl1-protocol'
18
16
  import {
19
- AccountBalanceViewer,
20
- BlockProducerService, BlockRewardViewer, BlockViewer, buildTransaction,
17
+ AccountBalanceViewer, AccountBalanceViewerMoniker, BlockRunner, BlockRunnerMoniker,
18
+ BlockViewer, BlockViewerMoniker, buildTransaction,
21
19
  Config,
20
+ createDeclarationIntent,
21
+ getDefaultConfig,
22
22
  MempoolRunner,
23
+ MempoolRunnerMoniker,
23
24
  MempoolViewer,
25
+ MempoolViewerMoniker,
24
26
  StakeTotalsViewer,
25
- TimeSyncViewer,
27
+ StakeTotalsViewerMoniker,
26
28
  } from '@xyo-network/xl1-protocol-sdk'
27
29
  import { Mutex } from 'async-mutex'
28
30
 
29
- export type ProducerActorParams = ActorParams<{
30
- account: AccountInstance
31
- blockRewardViewer: BlockRewardViewer
32
- chainId: ChainId
33
- config: Config
34
- runners: {
35
- mempoolRunner: MempoolRunner
36
- }
37
- viewers: {
38
- accountBalanceViewer: AccountBalanceViewer
39
- blockViewer: BlockViewer
40
- mempoolViewer: MempoolViewer
41
- stakeTotalsViewer: StakeTotalsViewer
42
- time: TimeSyncViewer
43
- }
44
- }>
31
+ export type ProducerActorParams = ActorParams
45
32
 
46
33
  const SHOULD_REGISTER_REDECLARATION_INTENT_TIMER = true
47
34
  const TEN_MINUTES = 10 * 60 * 1000 // 10 minutes in milliseconds
48
35
 
49
36
  @creatable()
50
37
  export class ProducerActor extends Actor<ProducerActorParams> {
51
- protected _lastProducedBlock: HydratedBlockWithHashMeta | undefined
52
- protected _lastRedeclarationIntent: ChainStakeIntent | undefined
53
- protected _metricAttributes: Attributes | undefined
54
- protected _producerActorBlockProductionAttempts: Counter<Attributes> | undefined
55
- protected _producerActorBlockProductionChecks: Counter<Attributes> | undefined
56
- protected _producerActorBlocksProduced: Counter<Attributes> | undefined
57
- protected _producerActorBlocksPublished: Counter<Attributes> | undefined
38
+ static readonly RedeclarationWindow = 10_000
39
+
40
+ protected _lastProducedBlock?: HydratedBlockWithHashMeta
41
+ protected _lastRedeclarationIntent?: ChainStakeIntent
42
+ protected _metricAttributes?: Attributes
43
+ protected _producerActorBlockProductionAttempts?: Counter<Attributes>
44
+ protected _producerActorBlockProductionChecks?: Counter<Attributes>
45
+ protected _producerActorBlocksProduced?: Counter<Attributes>
46
+ protected _producerActorBlocksPublished?: Counter<Attributes>
47
+
48
+ private _accountBalanceViewer?: AccountBalanceViewer
49
+ private _blockRunner?: BlockRunner
50
+ private _blockViewer?: BlockViewer
51
+ private _chainId?: ChainId
52
+ private _mempoolRunner?: MempoolRunner
53
+ private _mempoolViewer?: MempoolViewer
58
54
 
59
55
  private _produceBlockMutex = new Mutex()
60
- private _producer: BlockProducerService | undefined
61
56
 
62
- protected get account() {
63
- return this.params.account!
64
- }
57
+ private _stakeTotalsViewer?: StakeTotalsViewer
65
58
 
66
59
  protected get accountBalanceViewer() {
67
- return this.params.viewers.accountBalanceViewer!
60
+ return this._accountBalanceViewer!
68
61
  }
69
62
 
70
- protected get blockViewer() {
71
- return this.params.viewers.blockViewer!
63
+ protected get blockRunner() {
64
+ return this._blockRunner!
72
65
  }
73
66
 
74
- protected get chainId() {
75
- return this.params.chainId!
67
+ protected get blockViewer() {
68
+ return this._blockViewer!
76
69
  }
77
70
 
78
- protected get config() {
79
- return this.params.config!
71
+ protected get chainId() {
72
+ return this._chainId!
80
73
  }
81
74
 
82
75
  protected get mempoolRunner() {
83
- return this.params.runners.mempoolRunner!
76
+ return this._mempoolRunner!
84
77
  }
85
78
 
86
79
  protected get mempoolViewer() {
87
- return this.params.viewers.mempoolViewer!
88
- }
89
-
90
- protected get producer() {
91
- return this._producer!
80
+ return this._mempoolViewer!
92
81
  }
93
82
 
94
83
  protected get stakeTotalsViewer() {
95
- return this.params.viewers.stakeTotalsViewer!
84
+ return this._stakeTotalsViewer!
96
85
  }
97
86
 
98
87
  static override async paramsHandler<T extends ActorParams>(params?: Partial<T>) {
99
- return await super.paramsHandler({ ...params, name: (params?.name ?? 'Producer') as CreatableName })
88
+ const config: Config = params?.context?.config ?? getDefaultConfig()
89
+ const account = params?.account ?? await initProducerAccount({ config })
90
+ return await super.paramsHandler({
91
+ ...params, name: (params?.name ?? 'Producer') as CreatableName, account,
92
+ })
100
93
  }
101
94
 
102
95
  override async createHandler() {
@@ -121,21 +114,12 @@ export class ProducerActor extends Actor<ProducerActorParams> {
121
114
  'producer_actor_blocks_published',
122
115
  { description: 'Number of blocks published' },
123
116
  )
124
- const params = {
125
- account: this.account,
126
- balanceViewer: this.accountBalanceViewer,
127
- config: this.config,
128
- chainId: this.chainId,
129
- mempoolRunner: this.mempoolRunner,
130
- mempoolViewer: this.mempoolViewer,
131
- blockRewardViewer: this.params.blockRewardViewer!,
132
- rewardAddress: asAddress(
133
- this.config.producer.rewardAddress ?? ZERO_ADDRESS,
134
- () => `Producer config must have a valid reward address configured [${this.params.config.producer.rewardAddress}]`,
135
- ),
136
- time: this.params.viewers.time!,
137
- } satisfies SimpleBlockRunnerParams
138
- this._producer = await SimpleBlockRunner.create(params)
117
+ this._accountBalanceViewer = await this.locator.getInstance<AccountBalanceViewer>(AccountBalanceViewerMoniker)
118
+ this._blockRunner = await this.locator.getInstance<BlockRunner>(BlockRunnerMoniker)
119
+ this._blockViewer = await this.locator.getInstance<BlockViewer>(BlockViewerMoniker)
120
+ this._mempoolRunner = await this.locator.getInstance<MempoolRunner>(MempoolRunnerMoniker)
121
+ this._mempoolViewer = await this.locator.getInstance<MempoolViewer>(MempoolViewerMoniker)
122
+ this._stakeTotalsViewer = await this.locator.getInstance<StakeTotalsViewer>(StakeTotalsViewerMoniker)
139
123
  }
140
124
 
141
125
  override async startHandler() {
@@ -153,23 +137,9 @@ export class ProducerActor extends Actor<ProducerActorParams> {
153
137
  }
154
138
  }
155
139
 
156
- // protected async calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): Promise<number> {
157
- // // Decide if we need to redeclare intent
158
- // const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.account.address, 'producer')
159
- // // TODO: This doesn't handle the case where the producer had declared a range for the future
160
- // // but we're in a range that's not the future
161
- // // Sort in ascending order based on ending range to get range with highest ending block
162
- // const lastRange = ranges.toSorted((a, b) => a[1] > b[1] ? 1 : -1).at(-1)
163
-
164
- // // Use the most recent range's end block as the current declaration end OR
165
- // const [, currentDeclarationEnd] = lastRange
166
- // // If we have no ranges, we need to declare intent, so use the current block
167
- // ?? [undefined, currentBlock]
168
-
169
- // // Calculate the time until the producer's declaration expires
170
- // const timeToProducerExpiration = currentDeclarationEnd - currentBlock
171
- // return timeToProducerExpiration
172
- // }
140
+ protected calculateBlocksUntilProducerDeclarationExpiration(currentBlock: number): number {
141
+ return (this._lastRedeclarationIntent?.exp ?? currentBlock) - currentBlock
142
+ }
173
143
 
174
144
  protected async produceBlock(): Promise<void> {
175
145
  this._producerActorBlockProductionChecks?.add(1, this._metricAttributes)
@@ -181,10 +151,7 @@ export class ProducerActor extends Actor<ProducerActorParams> {
181
151
 
182
152
  await this._produceBlockMutex.runExclusive(async () => {
183
153
  // Get the updated head
184
- const headStart = Date.now()
185
154
  const head = (await this.blockViewer.currentBlock())[0]
186
- const headDuration = Date.now() - headStart
187
- if (headDuration > 500) this.logger?.warn(`[Slow] Fetched head in ${headDuration}ms: 0x${toHex(head._hash)}`)
188
155
  // Check if we've already produced the next block for this head
189
156
  const headHash = head._hash
190
157
  // If our last produced block was the next block for the current head, we do not
@@ -194,10 +161,7 @@ export class ProducerActor extends Actor<ProducerActorParams> {
194
161
  } else {
195
162
  this._producerActorBlockProductionAttempts?.add(1, this._metricAttributes)
196
163
  // Produce the next block
197
- const nextStart = Date.now()
198
- const nextBlock = await this.producer.next(head)
199
- const nextDuration = Date.now() - nextStart
200
- if (nextDuration > 1000) this.logger?.warn(`[Slow] Generated next block in ${nextDuration}ms, block: ${nextBlock?.[0]._hash}`)
164
+ const nextBlock = await this.blockRunner.next(head)
201
165
  // If it was produced
202
166
  if (nextBlock) {
203
167
  const displayBlockNumber = `0x${toHex(nextBlock[0].block)}`
@@ -220,7 +184,7 @@ export class ProducerActor extends Actor<ProducerActorParams> {
220
184
  protected async redeclareIntent(): Promise<void> {
221
185
  await this.spanAsync('redeclareIntent', async () => {
222
186
  // Decide if we should redeclare intent
223
- if (this.params.config.producer.disableIntentRedeclaration) return
187
+ if (this.config.producer.disableIntentRedeclaration) return
224
188
 
225
189
  // Get the current block
226
190
  const head = (await this.blockViewer.currentBlock())[0]
@@ -228,16 +192,16 @@ export class ProducerActor extends Actor<ProducerActorParams> {
228
192
  const currentBlock = head.block
229
193
 
230
194
  // // Calculate the time until the producer's declaration expires
231
- // const blocksUntilExpiration = await this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock)
195
+ const blocksUntilExpiration = this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock)
232
196
 
233
- // // Allow the producer time to redeclare itself via block production
234
- // // (for free) before submitting a redeclaration intent transaction.
235
- // if (blocksUntilExpiration > BaseBlockProducerService.RedeclarationWindow * 0.1) {
236
- // // Clear any previous redeclaration intent
237
- // this._lastRedeclarationIntent = undefined
238
- // // No need to redeclare yet
239
- // return
240
- // }
197
+ // Allow the producer time to redeclare itself via block production
198
+ // (for free) before submitting a redeclaration intent transaction.
199
+ if (blocksUntilExpiration > ProducerActor.RedeclarationWindow * 0.1) {
200
+ // Clear any previous redeclaration intent
201
+ this._lastRedeclarationIntent = undefined
202
+ // No need to redeclare yet
203
+ return
204
+ }
241
205
 
242
206
  // If we already have a valid redeclaration intent, do not create another
243
207
  // unless it has expired.
@@ -259,7 +223,7 @@ export class ProducerActor extends Actor<ProducerActorParams> {
259
223
  // Check if we have a valid stake before declaring intent
260
224
  if (!(await this.validateCurrentStake())) {
261
225
  this.logger?.error(
262
- `Add stake to contract address ${this.params.config.chain.id}`
226
+ `Add stake to contract address ${this.config.chain.id}`
263
227
  + ' for the producer to declare it\'s intent.',
264
228
  )
265
229
  return
@@ -304,7 +268,7 @@ export class ProducerActor extends Actor<ProducerActorParams> {
304
268
  // Check if we have a valid balance before declaring intent
305
269
  const head = this._lastProducedBlock?.[0]._hash
306
270
  if (isDefined(head)) {
307
- const balances = await this.accountBalanceViewer.accountBalances([this.account.address], head)
271
+ const balances = await this.accountBalanceViewer.accountBalances([this.account.address], { head })
308
272
  const currentBalance = balances[this.account.address] ?? 0n
309
273
  if (currentBalance <= 0n) {
310
274
  this.logger?.error(`Producer ${this.account.address} has no balance.`)
@@ -1,91 +1,64 @@
1
1
  import type { Address, Logger } from '@xylabs/sdk-js'
2
- import { assertEx, exists } from '@xylabs/sdk-js'
3
- import { initProducerAccount, type OrchestratorInstance } from '@xyo-network/chain-orchestration'
4
2
  import {
5
- initBlockRewardViewer, initChainService, initTimeService,
6
- } from '@xyo-network/chain-services'
3
+ asAddress, assertEx, exists,
4
+ } from '@xylabs/sdk-js'
5
+ import type { AccountInstance } from '@xyo-network/account-model'
7
6
  import {
8
- type ChainContractViewer, ChainContractViewerMoniker, type Config,
7
+ type ActorContext, initProducerAccount, type OrchestratorInstance,
8
+ } from '@xyo-network/chain-orchestration'
9
+ import { validateHydratedBlock, validateHydratedBlockState } from '@xyo-network/chain-validation'
10
+ import { SimpleBlockRunner } from '@xyo-network/chain-services'
11
+ import type {
12
+ Config, CreatableProviderContext, ProviderFactoryLocatorInstance,
9
13
  } from '@xyo-network/xl1-protocol-sdk'
14
+ import { SimpleBlockRewardViewer, SimpleBlockValidationViewer } from '@xyo-network/xl1-protocol-sdk'
15
+ import { buildJsonRpcProviderLocator } from '@xyo-network/xl1-providers'
10
16
  import {
11
- AccountBalanceViewerRpcSchemas, BlockViewerRpcSchemas, HttpRpcTransport, JsonRpcAccountBalanceViewer,
12
- JsonRpcBlockViewer,
13
- JsonRpcMempoolRunner,
14
- JsonRpcMempoolViewer,
15
- JsonRpcStakeTotalsViewer,
16
- MempoolRunnerRpcSchemas,
17
- MempoolViewerRpcSchemas,
18
- StakeTotalsViewerRpcSchemas,
17
+ HttpRpcTransport, type RpcSchemaMap, type TransportFactory,
19
18
  } from '@xyo-network/xl1-rpc'
20
19
 
21
20
  import { ProducerActor, type ProducerActorParams } from './ProducerActor.ts'
22
21
 
23
22
  interface RunProducerContext {
24
23
  config: Config
24
+ locator?: ProviderFactoryLocatorInstance
25
25
  logger: Logger
26
26
  orchestrator: OrchestratorInstance
27
27
  }
28
28
 
29
- export const runProducer = async (context: RunProducerContext) => {
30
- const {
31
- config, logger, orchestrator,
32
- } = context
29
+ const getProviderFactoryLocator = async (
30
+ context: Omit<CreatableProviderContext, 'locator'>,
31
+ account: AccountInstance,
32
+ rewardAddress: Address,
33
+ ) => {
34
+ const endpoint = assertEx(context.config.services.apiEndpoint, () => 'API endpoint is required in config.services.apiEndpoint')
35
+ const transportFactory: TransportFactory = (schemas: RpcSchemaMap) => new HttpRpcTransport(endpoint, schemas)
36
+ const locator = await buildJsonRpcProviderLocator({ context, transportFactory })
37
+ locator.register(SimpleBlockRewardViewer.factory())
38
+ locator.register(SimpleBlockValidationViewer.factory<SimpleBlockValidationViewer>({ state: validateHydratedBlockState, value: validateHydratedBlock }))
39
+ locator.register(SimpleBlockRunner.factory<SimpleBlockRunner>({ account, rewardAddress }))
40
+ return locator
41
+ }
42
+
43
+ export const runProducer = async ({
44
+ config, logger, orchestrator,
45
+ }: RunProducerContext) => {
46
+ const account = await initProducerAccount({ config })
47
+ logger.info(`Running producer for account ${account.address}`)
48
+ const rewardAddress = asAddress(config.producer.rewardAddress, () => 'rewardAddress is required in config.producer')
49
+ logger.info(`Using reward address ${rewardAddress}`)
33
50
 
34
- const endpoint = assertEx(config.services?.apiEndpoint, () => 'No API endpoint configured')
35
- const account = await initProducerAccount({ config, logger })
36
- const accountBalanceViewer = new JsonRpcAccountBalanceViewer(new HttpRpcTransport(endpoint, { ...AccountBalanceViewerRpcSchemas }))
37
- const blockViewer = new JsonRpcBlockViewer(new HttpRpcTransport(endpoint, { ...BlockViewerRpcSchemas }))
38
- const stakeTotalsViewer = new JsonRpcStakeTotalsViewer(new HttpRpcTransport(endpoint, { ...StakeTotalsViewerRpcSchemas }))
39
- const chainId = (await blockViewer.currentBlock())[0].chain
40
- const mempoolViewer = new JsonRpcMempoolViewer(new HttpRpcTransport(endpoint, { ...MempoolViewerRpcSchemas }))
41
- const mempoolRunner = new JsonRpcMempoolRunner(new HttpRpcTransport(endpoint, { ...MempoolRunnerRpcSchemas }))
42
- const chainService = await initChainService({
43
- account, config, logger,
44
- })
45
- const chainContractViewer = {
46
- forkedAtBlockNumber: function (): Promise<bigint> {
47
- return chainService.forkedAtBlockNumber()
48
- },
49
- forkedAtHash: function (): Promise<bigint> {
50
- return chainService.forkedAtHash()
51
- },
52
- forkedChainId: function (): Promise<Address> {
53
- return chainService.forkedChainId()
54
- },
55
- minWithdrawalBlocks: function (): Promise<bigint> {
56
- return chainService.minWithdrawalBlocks()
57
- },
58
- rewardsContract: function (): Promise<string> {
59
- return chainService.rewardsContract()
60
- },
61
- stakingTokenAddress: function (): Promise<string> {
62
- return chainService.stakingTokenAddress()
63
- },
64
- moniker: ChainContractViewerMoniker,
65
- } satisfies ChainContractViewer
66
- const blockRewardViewer = await initBlockRewardViewer({
67
- config, logger, chainContractViewer,
68
- })
69
- const timeSyncViewer = await initTimeService({
70
- config, logger, blockViewer,
71
- })
51
+ const locator = await getProviderFactoryLocator({
52
+ config, logger, singletons: {},
53
+ }, account, rewardAddress)
54
+
55
+ const context: ActorContext = {
56
+ locator, config, singletons: locator.context.singletons,
57
+ }
72
58
 
73
59
  // Create actors
74
60
  const params = {
75
- account,
76
- id: 'ProducerActor',
77
- chainId,
78
- config,
79
- viewers: {
80
- accountBalanceViewer,
81
- blockViewer,
82
- stakeTotalsViewer,
83
- mempoolViewer,
84
- time: timeSyncViewer,
85
- },
86
- blockRewardViewer,
87
- runners: { mempoolRunner },
88
- logger,
61
+ id: 'ProducerActor', context, account,
89
62
  } satisfies ProducerActorParams
90
63
  // const apiEndpoint = config.services.apiEndpoint
91
64
  // const balances = isDefined(apiEndpoint) ? undefined : await BalanceActor.create(params)