@lodestar/validator 1.43.0-rc.5 → 1.44.0-dev.055b83cb3d
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/lib/services/block.d.ts +2 -1
- package/lib/services/block.d.ts.map +1 -1
- package/lib/services/block.js +42 -27
- package/lib/services/block.js.map +1 -1
- package/lib/services/blockDuties.d.ts +85 -7
- package/lib/services/blockDuties.d.ts.map +1 -1
- package/lib/services/blockDuties.js +186 -74
- package/lib/services/blockDuties.js.map +1 -1
- package/lib/services/proposerPreferences.d.ts +25 -0
- package/lib/services/proposerPreferences.d.ts.map +1 -0
- package/lib/services/proposerPreferences.js +101 -0
- package/lib/services/proposerPreferences.js.map +1 -0
- package/lib/services/validatorStore.d.ts +1 -0
- package/lib/services/validatorStore.d.ts.map +1 -1
- package/lib/services/validatorStore.js +25 -1
- package/lib/services/validatorStore.js.map +1 -1
- package/lib/util/externalSignerClient.d.ts +5 -1
- package/lib/util/externalSignerClient.d.ts.map +1 -1
- package/lib/util/externalSignerClient.js +4 -0
- package/lib/util/externalSignerClient.js.map +1 -1
- package/lib/util/params.js +1 -0
- package/lib/util/params.js.map +1 -1
- package/lib/validator.d.ts.map +1 -1
- package/lib/validator.js +5 -1
- package/lib/validator.js.map +1 -1
- package/package.json +12 -12
- package/src/services/block.ts +49 -35
- package/src/services/blockDuties.ts +212 -79
- package/src/services/proposerPreferences.ts +124 -0
- package/src/services/validatorStore.ts +37 -0
- package/src/util/externalSignerClient.ts +7 -1
- package/src/util/params.ts +1 -0
- package/src/validator.ts +27 -4
package/lib/services/block.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ChainForkConfig } from "@lodestar/config";
|
|
|
3
3
|
import { Metrics } from "../metrics.js";
|
|
4
4
|
import { PubkeyHex } from "../types.js";
|
|
5
5
|
import { IClock, LoggerVc } from "../util/index.js";
|
|
6
|
+
import { BlockDutiesService } from "./blockDuties.js";
|
|
6
7
|
import { ValidatorStore } from "./validatorStore.js";
|
|
7
8
|
type BlockProposalOpts = {
|
|
8
9
|
broadcastValidation: routes.beacon.BroadcastValidation;
|
|
@@ -20,7 +21,7 @@ export declare class BlockProposingService {
|
|
|
20
21
|
private readonly metrics;
|
|
21
22
|
private readonly opts;
|
|
22
23
|
private readonly dutiesService;
|
|
23
|
-
constructor(config: ChainForkConfig, logger: LoggerVc, api: ApiClient, clock: IClock, validatorStore: ValidatorStore, metrics: Metrics | null, opts: BlockProposalOpts);
|
|
24
|
+
constructor(config: ChainForkConfig, logger: LoggerVc, api: ApiClient, clock: IClock, validatorStore: ValidatorStore, dutiesService: BlockDutiesService, metrics: Metrics | null, opts: BlockProposalOpts);
|
|
24
25
|
removeDutiesForKey(pubkey: PubkeyHex): void;
|
|
25
26
|
/**
|
|
26
27
|
* `BlockDutiesService` must call this fn to trigger block creation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/services/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAejD,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/services/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAejD,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAC,kBAAkB,EAAe,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAkBnD,KAAK,iBAAiB,GAAG;IACvB,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;IACvD,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AACF;;GAEG;AACH,qBAAa,qBAAqB;IAI9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAVvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IAEnD,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,cAAc,EAC/C,aAAa,EAAE,kBAAkB,EAChB,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,IAAI,EAAE,iBAAiB,EAIzC;IAED,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAE1C;IAED;;;OAGG;IACH,OAAO,CAAC,uBAAuB,CAa7B;YAGY,qBAAqB;YAwFrB,0BAA0B;IA8GxC,OAAO,CAAC,mBAAmB,CAmBzB;IAEF,OAAO,CAAC,mBAAmB,CAmCzB;CACH"}
|
package/lib/services/block.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { routes } from "@lodestar/api";
|
|
2
|
-
import { isForkPostGloas } from "@lodestar/params";
|
|
2
|
+
import { BUILDER_INDEX_SELF_BUILD, isForkPostGloas } from "@lodestar/params";
|
|
3
3
|
import { ProducedBlockSource, isBlindedSignedBeaconBlock, } from "@lodestar/types";
|
|
4
4
|
import { extendError, prettyBytes, prettyWeiToEth, toPubkeyHex, toRootHex } from "@lodestar/utils";
|
|
5
|
-
import {
|
|
5
|
+
import { GENESIS_SLOT } from "./blockDuties.js";
|
|
6
6
|
/**
|
|
7
7
|
* Service that sets up and handles validator block proposal duties.
|
|
8
8
|
*/
|
|
@@ -15,7 +15,7 @@ export class BlockProposingService {
|
|
|
15
15
|
metrics;
|
|
16
16
|
opts;
|
|
17
17
|
dutiesService;
|
|
18
|
-
constructor(config, logger, api, clock, validatorStore, metrics, opts) {
|
|
18
|
+
constructor(config, logger, api, clock, validatorStore, dutiesService, metrics, opts) {
|
|
19
19
|
this.config = config;
|
|
20
20
|
this.logger = logger;
|
|
21
21
|
this.api = api;
|
|
@@ -23,7 +23,8 @@ export class BlockProposingService {
|
|
|
23
23
|
this.validatorStore = validatorStore;
|
|
24
24
|
this.metrics = metrics;
|
|
25
25
|
this.opts = opts;
|
|
26
|
-
this.dutiesService =
|
|
26
|
+
this.dutiesService = dutiesService;
|
|
27
|
+
this.dutiesService.setNotifyBlockProductionFn(this.notifyBlockProductionFn);
|
|
27
28
|
}
|
|
28
29
|
removeDutiesForKey(pubkey) {
|
|
29
30
|
this.dutiesService.removeDutiesForKey(pubkey);
|
|
@@ -158,31 +159,45 @@ export class BlockProposingService {
|
|
|
158
159
|
throw extendError(e, "Failed to publish block");
|
|
159
160
|
})).assertOk();
|
|
160
161
|
this.logger.debug("Published beacon block", { ...debugLogCtx, broadcastValidation });
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
162
|
+
const isSelfBuild = block.body.signedExecutionPayloadBid.message.builderIndex === BUILDER_INDEX_SELF_BUILD;
|
|
163
|
+
if (isSelfBuild) {
|
|
164
|
+
// Self-build: proposer is responsible for building and publishing the execution payload envelope
|
|
165
|
+
// Step 3: Get the execution payload envelope
|
|
166
|
+
const envelopeRes = await this.api.validator.getExecutionPayloadEnvelope({
|
|
167
|
+
slot,
|
|
168
|
+
beaconBlockRoot,
|
|
169
|
+
});
|
|
170
|
+
const envelope = envelopeRes.value();
|
|
171
|
+
this.logger.debug("Retrieved execution payload envelope", debugLogCtx);
|
|
172
|
+
// Step 4: Sign and publish the envelope
|
|
173
|
+
const signedEnvelope = await this.validatorStore.signExecutionPayloadEnvelope(pubkey, envelope, slot, this.logger);
|
|
174
|
+
(await this.api.beacon
|
|
175
|
+
.publishExecutionPayloadEnvelope({
|
|
176
|
+
signedExecutionPayloadEnvelope: signedEnvelope,
|
|
177
|
+
})
|
|
178
|
+
.catch((e) => {
|
|
179
|
+
this.metrics?.blockProposingErrors.inc({ error: "publish" });
|
|
180
|
+
throw extendError(e, "Failed to publish execution payload envelope");
|
|
181
|
+
})).assertOk();
|
|
182
|
+
this.logger.info("Published block and execution payload envelope", {
|
|
183
|
+
...logCtx,
|
|
184
|
+
graffiti,
|
|
185
|
+
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
186
|
+
blockRoot: blockRootHex,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// Builder is responsible for broadcasting the execution payload envelope
|
|
191
|
+
this.logger.info("Published block with builder bid, envelope expected from builder", {
|
|
192
|
+
...logCtx,
|
|
193
|
+
graffiti,
|
|
194
|
+
builderIndex: block.body.signedExecutionPayloadBid.message.builderIndex,
|
|
195
|
+
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
196
|
+
blockRoot: blockRootHex,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
178
199
|
this.metrics?.proposerStepCallPublishBlock.observe(this.clock.secFromSlot(slot));
|
|
179
200
|
this.metrics?.blocksPublished.inc();
|
|
180
|
-
this.logger.info("Published block and execution payload envelope", {
|
|
181
|
-
...logCtx,
|
|
182
|
-
graffiti,
|
|
183
|
-
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
184
|
-
blockRoot: blockRootHex,
|
|
185
|
-
});
|
|
186
201
|
}
|
|
187
202
|
publishBlockWrapper = async (signedBlindedBlockOrBlockContents, opts = {}) => {
|
|
188
203
|
if (isBlindedSignedBeaconBlock(signedBlindedBlockOrBlockContents.signedBlock)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/services/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAC,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/services/block.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { ApiClient } from "@lodestar/api";
|
|
1
|
+
import { ApiClient, routes } from "@lodestar/api";
|
|
2
2
|
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
-
import { BLSPubkey, Slot } from "@lodestar/types";
|
|
3
|
+
import { BLSPubkey, Epoch, RootHex, Slot } from "@lodestar/types";
|
|
4
4
|
import { Metrics } from "../metrics.js";
|
|
5
5
|
import { PubkeyHex } from "../types.js";
|
|
6
6
|
import { IClock, LoggerVc } from "../util/index.js";
|
|
7
|
+
import { ChainHeaderTracker } from "./chainHeaderTracker.js";
|
|
7
8
|
import { ValidatorStore } from "./validatorStore.js";
|
|
8
9
|
export declare const GENESIS_SLOT = 0;
|
|
10
|
+
export type BlockDutyAtEpoch = {
|
|
11
|
+
dependentRoot: RootHex;
|
|
12
|
+
data: routes.validator.ProposerDuty[];
|
|
13
|
+
};
|
|
9
14
|
type NotifyBlockProductionFn = (slot: Slot, proposers: BLSPubkey[]) => void;
|
|
10
15
|
export declare class BlockDutiesService {
|
|
11
16
|
private readonly config;
|
|
@@ -15,11 +20,29 @@ export declare class BlockDutiesService {
|
|
|
15
20
|
private readonly validatorStore;
|
|
16
21
|
private readonly metrics;
|
|
17
22
|
/** Notify the block service if it should produce a block. */
|
|
18
|
-
private
|
|
23
|
+
private notifyBlockProductionFn;
|
|
19
24
|
/** Maps an epoch to all *local* proposers in this epoch. Notably, this does not contain
|
|
20
25
|
proposals for any validators which are not registered locally. */
|
|
21
26
|
private readonly proposers;
|
|
22
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Tracks which proposer pubkeys we have already notified for the active slot so that
|
|
29
|
+
* a late-arriving cache update (SSE-driven refetch, slow initial poll) only fires
|
|
30
|
+
* `notifyBlockProductionFn` for *newly discovered* proposers, never duplicates.
|
|
31
|
+
*/
|
|
32
|
+
private notifiedSlot;
|
|
33
|
+
private readonly notifiedProposers;
|
|
34
|
+
/**
|
|
35
|
+
* True once `notifyProposersForSlot` has been invoked for `notifiedSlot`, regardless of
|
|
36
|
+
* whether anything was notified. Any subsequent invocation that finds *new* proposers is
|
|
37
|
+
* therefore a late detection — the signal tracked by `newProposalDutiesDetected`.
|
|
38
|
+
*/
|
|
39
|
+
private notifiedSlotInitialPass;
|
|
40
|
+
constructor(config: ChainForkConfig, logger: LoggerVc, api: ApiClient, clock: IClock, validatorStore: ValidatorStore, chainHeaderTracker: ChainHeaderTracker, metrics: Metrics | null);
|
|
41
|
+
/**
|
|
42
|
+
* Late-bind the production callback. Allows the duties service to be constructed
|
|
43
|
+
* before the consumer that handles proposal production.
|
|
44
|
+
*/
|
|
45
|
+
setNotifyBlockProductionFn(notifyBlockProductionFn: NotifyBlockProductionFn): void;
|
|
23
46
|
/**
|
|
24
47
|
* Returns the pubkeys of the validators which are assigned to propose in the given slot.
|
|
25
48
|
*
|
|
@@ -27,10 +50,65 @@ export declare class BlockDutiesService {
|
|
|
27
50
|
* likely the result of heavy forking (lol) or inconsistent beacon node connections.
|
|
28
51
|
*/
|
|
29
52
|
getblockProposersAtSlot(slot: Slot): BLSPubkey[];
|
|
53
|
+
/**
|
|
54
|
+
* Returns the cached `{dependentRoot, data}` entry for `epoch`, or `undefined` if duties
|
|
55
|
+
* for that epoch are not yet known. Consumers can detect a proposer-shuffling change
|
|
56
|
+
* (e.g. after a reorg) by observing a different `dependentRoot` than the one they last
|
|
57
|
+
* read for the same epoch.
|
|
58
|
+
*/
|
|
59
|
+
getProposersAtEpoch(epoch: Epoch): BlockDutyAtEpoch | undefined;
|
|
30
60
|
removeDutiesForKey(pubkey: PubkeyHex): void;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Baseline per-epoch fetch. Fires at epoch boundaries (and once at startup). Post-Fulu the
|
|
63
|
+
* deterministic 1-epoch lookahead lets us also pre-fetch `epoch + 1`; pre-Fulu the next
|
|
64
|
+
* epoch's dep_root only stabilizes at the boundary and is handled by `runEverySlotTask`.
|
|
65
|
+
*
|
|
66
|
+
* Mid-epoch refreshes (e.g. reorgs) are driven by `onNewHead` instead of polling every slot.
|
|
67
|
+
*/
|
|
68
|
+
private runEveryEpochTask;
|
|
69
|
+
/**
|
|
70
|
+
* Slot-tick handler. Notifies block production for cached proposers in this slot, and on
|
|
71
|
+
* the last slot of a pre-Fulu epoch schedules the boundary fetch for `nextEpoch` duties.
|
|
72
|
+
* Reorg detection is handled by `onNewHead`, so this task does not re-poll on every slot.
|
|
73
|
+
*/
|
|
74
|
+
private runEverySlotTask;
|
|
75
|
+
/**
|
|
76
|
+
* SSE head-event handler. The beacon-API `head` event carries attester-duty dep_roots,
|
|
77
|
+
* which coincide with the proposer dep_roots at a fork-dependent offset:
|
|
78
|
+
*
|
|
79
|
+
* Pre-Fulu (proposer dep_root(E) = block@startSlot(E) - 1):
|
|
80
|
+
* currentDutyDependentRoot ≡ proposer_dep_root(currentEpoch)
|
|
81
|
+
* (next-epoch proposer dep_root is not exposed; pre-Fulu falls back to the
|
|
82
|
+
* `runEverySlotTask` boundary poll.)
|
|
83
|
+
*
|
|
84
|
+
* Post-Fulu (proposer dep_root(E) = block@startSlot(E - 1) - 1, EIP-7917):
|
|
85
|
+
* previousDutyDependentRoot ≡ proposer_dep_root(currentEpoch)
|
|
86
|
+
* currentDutyDependentRoot ≡ proposer_dep_root(nextEpoch)
|
|
87
|
+
*
|
|
88
|
+
* On a dep_root mismatch (reorg, or initial sync delivering a fresher head) we refetch
|
|
89
|
+
* just the affected epoch, mirroring `AttestationDutiesService.onNewHead`.
|
|
90
|
+
*/
|
|
91
|
+
private onNewHead;
|
|
92
|
+
private refetchIfDepRootChanged;
|
|
93
|
+
private pollBeaconProposersBeforeBoundary;
|
|
94
|
+
/**
|
|
95
|
+
* Notify block production for *newly discovered* proposers in this slot. Notifications are
|
|
96
|
+
* deduplicated per-slot so that a late SSE refetch can extend the proposer set without
|
|
97
|
+
* triggering a duplicate `createAndPublishBlock` for already-notified validators.
|
|
98
|
+
*
|
|
99
|
+
* ## Multi-notification safety
|
|
100
|
+
*
|
|
101
|
+
* Within a single slot the cache can be updated from several sources (cold-cache backfill at
|
|
102
|
+
* startup, SSE-driven reorg refetch). Each update may fire this function again. The contract
|
|
103
|
+
* we keep is: each pubkey is notified *at most once per slot*. The additional notifications
|
|
104
|
+
* only carry proposers that were not part of an earlier notification.
|
|
105
|
+
*
|
|
106
|
+
* Is this safe? Firstly, the dedup above guarantees we never ask the same validator to
|
|
107
|
+
* propose twice for the same slot. Secondly, slashing protection in `ValidatorStore` acts as
|
|
108
|
+
* a second line of defense should the dedup ever fail. Together they provide an acceptable
|
|
109
|
+
* level of safety for the "notify-from-cache, refine-after-refetch" pattern.
|
|
110
|
+
*/
|
|
111
|
+
private notifyProposersForSlot;
|
|
34
112
|
private pollBeaconProposers;
|
|
35
113
|
/** Run once per epoch to prune `this.proposers` map */
|
|
36
114
|
private pruneOldDuties;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blockDuties.d.ts","sourceRoot":"","sources":["../../src/services/blockDuties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"blockDuties.d.ts","sourceRoot":"","sources":["../../src/services/blockDuties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAC,kBAAkB,EAAgB,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAoBnD,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,MAAM,MAAM,gBAAgB,GAAG;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,CAAA;CAAC,CAAC;AAC/F,KAAK,uBAAuB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;AAE5E,qBAAa,kBAAkB;IAsB3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IA3B1B,6DAA6D;IAC7D,OAAO,CAAC,uBAAuB,CAAqC;IACpE;yEACqE;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAEhE;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwB;IAC1D;;;;OAIG;IACH,OAAO,CAAC,uBAAuB,CAAS;IAExC,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,cAAc,EAC/C,kBAAkB,EAAE,kBAAkB,EACrB,OAAO,EAAE,OAAO,GAAG,IAAI,EAWzC;IAED;;;OAGG;IACH,0BAA0B,CAAC,uBAAuB,EAAE,uBAAuB,GAAG,IAAI,CAEjF;IAED;;;;;OAKG;IACH,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,CAc/C;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,gBAAgB,GAAG,SAAS,CAE9D;IAED,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAM1C;IAED;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB,CAuBvB;IAEF;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAqBtB;IAEF;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,SAAS,CAcf;YAEY,uBAAuB;YAuBvB,iCAAiC;IAa/C;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,sBAAsB;YA8BhB,mBAAmB;IA0CjC,uDAAuD;IACvD,OAAO,CAAC,cAAc;CAOvB"}
|