@lodestar/state-transition 1.46.0-dev.8fc4e297d2 → 1.46.0-dev.92d84f9b7f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/lib/block/externalData.js +2 -4
  2. package/lib/block/externalData.js.map +1 -1
  3. package/lib/block/index.d.ts.map +1 -1
  4. package/lib/block/index.js +3 -2
  5. package/lib/block/index.js.map +1 -1
  6. package/lib/block/initiateValidatorExit.js.map +1 -1
  7. package/lib/block/isValidIndexedAttestation.js.map +1 -1
  8. package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -1
  9. package/lib/block/processAttestationPhase0.js.map +1 -1
  10. package/lib/block/processAttestations.d.ts +2 -2
  11. package/lib/block/processAttestations.d.ts.map +1 -1
  12. package/lib/block/processAttestations.js +2 -2
  13. package/lib/block/processAttestations.js.map +1 -1
  14. package/lib/block/processAttestationsAltair.d.ts +3 -3
  15. package/lib/block/processAttestationsAltair.d.ts.map +1 -1
  16. package/lib/block/processAttestationsAltair.js +7 -4
  17. package/lib/block/processAttestationsAltair.js.map +1 -1
  18. package/lib/block/processAttesterSlashing.js.map +1 -1
  19. package/lib/block/processBlobKzgCommitments.js.map +1 -1
  20. package/lib/block/processBlockHeader.js.map +1 -1
  21. package/lib/block/processBlsToExecutionChange.js.map +1 -1
  22. package/lib/block/processBuilderDepositRequest.js.map +1 -1
  23. package/lib/block/processBuilderExitRequest.js.map +1 -1
  24. package/lib/block/processConsolidationRequest.js.map +1 -1
  25. package/lib/block/processDeposit.js.map +1 -1
  26. package/lib/block/processDepositRequest.js.map +1 -1
  27. package/lib/block/processEth1Data.js.map +1 -1
  28. package/lib/block/processExecutionPayload.js.map +1 -1
  29. package/lib/block/processExecutionPayloadBid.d.ts +2 -2
  30. package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
  31. package/lib/block/processExecutionPayloadBid.js +2 -0
  32. package/lib/block/processExecutionPayloadBid.js.map +1 -1
  33. package/lib/block/processOperations.d.ts +2 -2
  34. package/lib/block/processOperations.d.ts.map +1 -1
  35. package/lib/block/processOperations.js +2 -2
  36. package/lib/block/processOperations.js.map +1 -1
  37. package/lib/block/processParentExecutionPayload.js.map +1 -1
  38. package/lib/block/processPayloadAttestation.js.map +1 -1
  39. package/lib/block/processProposerSlashing.js.map +1 -1
  40. package/lib/block/processRandao.js.map +1 -1
  41. package/lib/block/processSyncCommittee.js.map +1 -1
  42. package/lib/block/processVoluntaryExit.js +1 -2
  43. package/lib/block/processVoluntaryExit.js.map +1 -1
  44. package/lib/block/processWithdrawalRequest.d.ts.map +1 -1
  45. package/lib/block/processWithdrawalRequest.js +2 -2
  46. package/lib/block/processWithdrawalRequest.js.map +1 -1
  47. package/lib/block/processWithdrawals.js.map +1 -1
  48. package/lib/block/slashValidator.js.map +1 -1
  49. package/lib/block/types.js +1 -2
  50. package/lib/block/types.js.map +1 -1
  51. package/lib/cache/effectiveBalanceIncrements.js.map +1 -1
  52. package/lib/cache/epochCache.d.ts.map +1 -1
  53. package/lib/cache/epochCache.js +19 -21
  54. package/lib/cache/epochCache.js.map +1 -1
  55. package/lib/cache/epochTransitionCache.js.map +1 -1
  56. package/lib/cache/pubkeyCache.js.map +1 -1
  57. package/lib/cache/rewardCache.js.map +1 -1
  58. package/lib/cache/stateCache.d.ts.map +1 -1
  59. package/lib/cache/stateCache.js +3 -2
  60. package/lib/cache/stateCache.js.map +1 -1
  61. package/lib/cache/syncCommitteeCache.js.map +1 -1
  62. package/lib/epoch/computeUnrealizedCheckpoints.js.map +1 -1
  63. package/lib/epoch/getAttestationDeltas.js.map +1 -1
  64. package/lib/epoch/getRewardsAndPenalties.js.map +1 -1
  65. package/lib/epoch/index.js +1 -2
  66. package/lib/epoch/index.js.map +1 -1
  67. package/lib/epoch/processBuilderPendingPayments.js.map +1 -1
  68. package/lib/epoch/processEffectiveBalanceUpdates.js.map +1 -1
  69. package/lib/epoch/processEth1DataReset.js.map +1 -1
  70. package/lib/epoch/processHistoricalRootsUpdate.js.map +1 -1
  71. package/lib/epoch/processHistoricalSummariesUpdate.js.map +1 -1
  72. package/lib/epoch/processInactivityUpdates.js.map +1 -1
  73. package/lib/epoch/processJustificationAndFinalization.js.map +1 -1
  74. package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
  75. package/lib/epoch/processParticipationRecordUpdates.js.map +1 -1
  76. package/lib/epoch/processPendingAttestations.js.map +1 -1
  77. package/lib/epoch/processPendingConsolidations.js.map +1 -1
  78. package/lib/epoch/processPendingDeposits.js.map +1 -1
  79. package/lib/epoch/processProposerLookahead.js.map +1 -1
  80. package/lib/epoch/processPtcWindow.js.map +1 -1
  81. package/lib/epoch/processRandaoMixesReset.js.map +1 -1
  82. package/lib/epoch/processRegistryUpdates.js.map +1 -1
  83. package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
  84. package/lib/epoch/processSlashings.js.map +1 -1
  85. package/lib/epoch/processSlashingsReset.js.map +1 -1
  86. package/lib/epoch/processSyncCommitteeUpdates.js.map +1 -1
  87. package/lib/lightClient/proofs.js.map +1 -1
  88. package/lib/lightClient/spec/index.js.map +1 -1
  89. package/lib/lightClient/spec/isBetterUpdate.js.map +1 -1
  90. package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -1
  91. package/lib/lightClient/spec/store.js.map +1 -1
  92. package/lib/lightClient/spec/utils.d.ts +0 -2
  93. package/lib/lightClient/spec/utils.d.ts.map +1 -1
  94. package/lib/lightClient/spec/utils.js +2 -2
  95. package/lib/lightClient/spec/utils.js.map +1 -1
  96. package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
  97. package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
  98. package/lib/metrics.d.ts.map +1 -1
  99. package/lib/metrics.js +3 -2
  100. package/lib/metrics.js.map +1 -1
  101. package/lib/rewards/attestationsRewards.js.map +1 -1
  102. package/lib/rewards/blockRewards.d.ts.map +1 -1
  103. package/lib/rewards/blockRewards.js +7 -4
  104. package/lib/rewards/blockRewards.js.map +1 -1
  105. package/lib/rewards/syncCommitteeRewards.js.map +1 -1
  106. package/lib/signatureSets/attesterSlashings.js.map +1 -1
  107. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  108. package/lib/signatureSets/executionPayloadBid.js.map +1 -1
  109. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  110. package/lib/signatureSets/index.js.map +1 -1
  111. package/lib/signatureSets/indexedAttestation.js.map +1 -1
  112. package/lib/signatureSets/indexedPayloadAttestation.js.map +1 -1
  113. package/lib/signatureSets/proposer.js.map +1 -1
  114. package/lib/signatureSets/proposerPreferences.js.map +1 -1
  115. package/lib/signatureSets/proposerSlashings.js.map +1 -1
  116. package/lib/signatureSets/randao.js.map +1 -1
  117. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  118. package/lib/slot/index.js.map +1 -1
  119. package/lib/slot/upgradeStateToAltair.js +1 -1
  120. package/lib/slot/upgradeStateToAltair.js.map +1 -1
  121. package/lib/slot/upgradeStateToBellatrix.js.map +1 -1
  122. package/lib/slot/upgradeStateToCapella.js.map +1 -1
  123. package/lib/slot/upgradeStateToDeneb.js.map +1 -1
  124. package/lib/slot/upgradeStateToElectra.js.map +1 -1
  125. package/lib/slot/upgradeStateToFulu.js.map +1 -1
  126. package/lib/slot/upgradeStateToGloas.js +1 -1
  127. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  128. package/lib/stateTransition.js +2 -4
  129. package/lib/stateTransition.js.map +1 -1
  130. package/lib/stateView/beaconStateView.js.map +1 -1
  131. package/lib/stateView/interface.js.map +1 -1
  132. package/lib/stateView/nativeBeaconStateView.js.map +1 -1
  133. package/lib/stateView/stateViewFactory.js.map +1 -1
  134. package/lib/testUtils/infura.js.map +1 -1
  135. package/lib/testUtils/interop.js.map +1 -1
  136. package/lib/testUtils/params.d.ts.map +1 -1
  137. package/lib/testUtils/state.js +1 -1
  138. package/lib/testUtils/state.js.map +1 -1
  139. package/lib/testUtils/testFileCache.js.map +1 -1
  140. package/lib/testUtils/util.d.ts +1 -1
  141. package/lib/testUtils/util.d.ts.map +1 -1
  142. package/lib/testUtils/util.js +2 -2
  143. package/lib/testUtils/util.js.map +1 -1
  144. package/lib/util/aggregator.js.map +1 -1
  145. package/lib/util/altair.js.map +1 -1
  146. package/lib/util/array.js.map +1 -1
  147. package/lib/util/attestation.js.map +1 -1
  148. package/lib/util/attesterStatus.js.map +1 -1
  149. package/lib/util/balance.js.map +1 -1
  150. package/lib/util/blindedBlock.js.map +1 -1
  151. package/lib/util/blockRoot.js.map +1 -1
  152. package/lib/util/capella.js.map +1 -1
  153. package/lib/util/clock.d.ts +61 -0
  154. package/lib/util/clock.d.ts.map +1 -0
  155. package/lib/util/clock.js +141 -0
  156. package/lib/util/clock.js.map +1 -0
  157. package/lib/util/computeAnchorCheckpoint.js.map +1 -1
  158. package/lib/util/deposit.d.ts.map +1 -1
  159. package/lib/util/deposit.js +10 -8
  160. package/lib/util/deposit.js.map +1 -1
  161. package/lib/util/domain.js.map +1 -1
  162. package/lib/util/electra.js.map +1 -1
  163. package/lib/util/epoch.js.map +1 -1
  164. package/lib/util/epochShuffling.js.map +1 -1
  165. package/lib/util/execution.js.map +1 -1
  166. package/lib/util/finality.js.map +1 -1
  167. package/lib/util/fulu.js.map +1 -1
  168. package/lib/util/genesis.js +2 -2
  169. package/lib/util/genesis.js.map +1 -1
  170. package/lib/util/gloas.d.ts +2 -1
  171. package/lib/util/gloas.d.ts.map +1 -1
  172. package/lib/util/gloas.js +7 -4
  173. package/lib/util/gloas.js.map +1 -1
  174. package/lib/util/index.d.ts +1 -0
  175. package/lib/util/index.d.ts.map +1 -1
  176. package/lib/util/index.js +1 -0
  177. package/lib/util/index.js.map +1 -1
  178. package/lib/util/interop.js.map +1 -1
  179. package/lib/util/loadState/findModifiedInactivityScores.js.map +1 -1
  180. package/lib/util/loadState/findModifiedValidators.js.map +1 -1
  181. package/lib/util/loadState/loadState.d.ts.map +1 -1
  182. package/lib/util/loadState/loadState.js +36 -5
  183. package/lib/util/loadState/loadState.js.map +1 -1
  184. package/lib/util/loadState/loadValidator.js.map +1 -1
  185. package/lib/util/pendingDepositsLookup.js.map +1 -1
  186. package/lib/util/rootCache.js.map +1 -1
  187. package/lib/util/seed.js.map +1 -1
  188. package/lib/util/shuffling.js +1 -2
  189. package/lib/util/shuffling.js.map +1 -1
  190. package/lib/util/signatureSets.js +1 -2
  191. package/lib/util/signatureSets.js.map +1 -1
  192. package/lib/util/signingRoot.js.map +1 -1
  193. package/lib/util/slot.js.map +1 -1
  194. package/lib/util/ssz.d.ts +5 -0
  195. package/lib/util/ssz.d.ts.map +1 -1
  196. package/lib/util/ssz.js +8 -1
  197. package/lib/util/ssz.js.map +1 -1
  198. package/lib/util/sszBytes.js.map +1 -1
  199. package/lib/util/syncCommittee.js.map +1 -1
  200. package/lib/util/targetUnslashedBalance.js.map +1 -1
  201. package/lib/util/validator.js.map +1 -1
  202. package/lib/util/weakSubjectivity.js.map +1 -1
  203. package/package.json +15 -15
  204. package/src/block/index.ts +4 -3
  205. package/src/block/processAttestations.ts +10 -2
  206. package/src/block/processAttestationsAltair.ts +10 -4
  207. package/src/block/processExecutionPayloadBid.ts +5 -2
  208. package/src/block/processOperations.ts +3 -2
  209. package/src/block/processWithdrawalRequest.ts +6 -2
  210. package/src/cache/epochCache.ts +19 -22
  211. package/src/cache/stateCache.ts +3 -2
  212. package/src/lightClient/spec/utils.ts +2 -2
  213. package/src/metrics.ts +3 -2
  214. package/src/rewards/blockRewards.ts +20 -5
  215. package/src/slot/upgradeStateToAltair.ts +1 -0
  216. package/src/slot/upgradeStateToGloas.ts +1 -1
  217. package/src/testUtils/state.ts +1 -1
  218. package/src/testUtils/util.ts +2 -2
  219. package/src/util/clock.ts +183 -0
  220. package/src/util/deposit.ts +11 -9
  221. package/src/util/genesis.ts +2 -2
  222. package/src/util/gloas.ts +9 -5
  223. package/src/util/index.ts +1 -0
  224. package/src/util/loadState/loadState.ts +50 -11
  225. package/src/util/ssz.ts +9 -1
@@ -14,7 +14,7 @@ import {
14
14
  TIMELY_TARGET_WEIGHT,
15
15
  WEIGHT_DENOMINATOR,
16
16
  } from "@lodestar/params";
17
- import {Attestation, Epoch, phase0} from "@lodestar/types";
17
+ import {Attestation, Epoch, Slot, phase0} from "@lodestar/types";
18
18
  import {byteArrayEquals, intSqrt} from "@lodestar/utils";
19
19
  import {BeaconStateTransitionMetrics} from "../metrics.js";
20
20
  import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js";
@@ -37,6 +37,7 @@ export function processAttestationsAltair(
37
37
  fork: ForkSeq,
38
38
  state: CachedBeaconStateAltair | CachedBeaconStateGloas,
39
39
  attestations: Attestation[],
40
+ parentSlot: Slot | null,
40
41
  verifySignature = true,
41
42
  metrics?: BeaconStateTransitionMetrics | null
42
43
  ): void {
@@ -82,7 +83,8 @@ export function processAttestationsAltair(
82
83
  stateSlot - data.slot,
83
84
  epochCtx.epoch,
84
85
  rootCache,
85
- fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).executionPayloadAvailability : null
86
+ fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).executionPayloadAvailability : null,
87
+ parentSlot
86
88
  );
87
89
 
88
90
  // For each participant, update their participation
@@ -179,7 +181,8 @@ export function getAttestationParticipationStatus(
179
181
  inclusionDelay: number,
180
182
  currentEpoch: Epoch,
181
183
  rootCache: RootCache,
182
- executionPayloadAvailability: BitArray | null
184
+ executionPayloadAvailability: BitArray | null,
185
+ parentSlot: Slot | null
183
186
  ): {flags: number; isSameSlotAttestation: boolean} {
184
187
  const justifiedCheckpoint =
185
188
  data.target.epoch === currentEpoch ? rootCache.currentJustifiedCheckpoint : rootCache.previousJustifiedCheckpoint;
@@ -221,13 +224,16 @@ export function getAttestationParticipationStatus(
221
224
  if (executionPayloadAvailability === null) {
222
225
  throw new Error("Must supply executionPayloadAvailability post-gloas");
223
226
  }
227
+ if (parentSlot === null) {
228
+ throw new Error("Must supply parentSlot post-gloas");
229
+ }
224
230
 
225
231
  if (data.index !== 0 && data.index !== 1) {
226
232
  throw new Error(`data index must be 0 or 1 index=${data.index}`);
227
233
  }
228
234
 
229
235
  isMatchingPayload =
230
- Boolean(data.index) === executionPayloadAvailability.get(data.slot % SLOTS_PER_HISTORICAL_ROOT);
236
+ Boolean(data.index) === executionPayloadAvailability.get(parentSlot % SLOTS_PER_HISTORICAL_ROOT);
231
237
  }
232
238
 
233
239
  isMatchingHead = isMatchingHead && isMatchingPayload;
@@ -1,6 +1,6 @@
1
1
  import {PublicKey, Signature, verify} from "@chainsafe/blst";
2
2
  import {BUILDER_INDEX_SELF_BUILD, GENESIS_SLOT, PAYLOAD_BUILDER_VERSION, SLOTS_PER_EPOCH} from "@lodestar/params";
3
- import {gloas, ssz} from "@lodestar/types";
3
+ import {Slot, gloas, ssz} from "@lodestar/types";
4
4
  import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
5
5
  import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
6
6
  import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
@@ -11,7 +11,7 @@ import {getBlockRootAtSlot, getCurrentEpoch, getRandaoMix} from "../util/index.j
11
11
  export function processExecutionPayloadBid(
12
12
  state: CachedBeaconStateGloas,
13
13
  signedBid: gloas.SignedExecutionPayloadBid
14
- ): void {
14
+ ): Slot {
15
15
  const bid = signedBid.message;
16
16
  const {builderIndex, value: amount} = bid;
17
17
 
@@ -99,7 +99,10 @@ export function processExecutionPayloadBid(
99
99
  state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView);
100
100
  }
101
101
 
102
+ const parentSlot = state.latestExecutionPayloadBid.slot;
102
103
  state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
104
+
105
+ return parentSlot;
103
106
  }
104
107
 
105
108
  function verifyExecutionPayloadBidSignature(
@@ -7,7 +7,7 @@ import {
7
7
  MAX_PROPOSER_SLASHINGS,
8
8
  MAX_VOLUNTARY_EXITS,
9
9
  } from "@lodestar/params";
10
- import {BeaconBlockBody, capella, electra, gloas} from "@lodestar/types";
10
+ import {BeaconBlockBody, Slot, capella, electra, gloas} from "@lodestar/types";
11
11
  import {BeaconStateTransitionMetrics} from "../metrics.js";
12
12
  import {
13
13
  CachedBeaconStateAllForks,
@@ -44,6 +44,7 @@ export function processOperations(
44
44
  fork: ForkSeq,
45
45
  state: CachedBeaconStateAllForks,
46
46
  body: BeaconBlockBody,
47
+ parentSlot: Slot | null,
47
48
  opts: ProcessBlockOpts = {verifySignatures: true},
48
49
  metrics?: BeaconStateTransitionMetrics | null
49
50
  ): void {
@@ -67,7 +68,7 @@ export function processOperations(
67
68
  processAttesterSlashing(fork, state, attesterSlashing, opts.verifySignatures);
68
69
  }
69
70
 
70
- processAttestations(fork, state, body.attestations, opts.verifySignatures, metrics);
71
+ processAttestations(fork, state, body.attestations, parentSlot, opts.verifySignatures, metrics);
71
72
 
72
73
  for (const deposit of body.deposits) {
73
74
  processDeposit(fork, state, deposit);
@@ -8,7 +8,11 @@ import {
8
8
  import {electra, phase0, ssz} from "@lodestar/types";
9
9
  import {toHex} from "@lodestar/utils";
10
10
  import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
11
- import {hasCompoundingWithdrawalCredential, hasExecutionWithdrawalCredential} from "../util/electra.js";
11
+ import {
12
+ hasCompoundingWithdrawalCredential,
13
+ hasExecutionWithdrawalCredential,
14
+ isValidatorKnown,
15
+ } from "../util/electra.js";
12
16
  import {computeExitEpochAndUpdateChurn} from "../util/epoch.js";
13
17
  import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js";
14
18
  import {initiateValidatorExit} from "./initiateValidatorExit.js";
@@ -32,7 +36,7 @@ export function processWithdrawalRequest(
32
36
  // bail out if validator is not in beacon state
33
37
  // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway
34
38
  const validatorIndex = pubkeyCache.getIndex(withdrawalRequest.validatorPubkey);
35
- if (validatorIndex === null) {
39
+ if (!isValidatorKnown(state, validatorIndex)) {
36
40
  return;
37
41
  }
38
42
 
@@ -408,12 +408,17 @@ export class EpochCache {
408
408
 
409
409
  const nextShuffling = cachedNextShuffling ?? computeEpochShuffling(state, nextActiveIndices, nextEpoch);
410
410
 
411
- const currentProposerSeed = getSeed(state, currentEpoch, DOMAIN_BEACON_PROPOSER);
412
-
413
- let proposers: number[];
411
+ let proposers: ValidatorIndex[];
412
+ let proposersNextEpoch: ProposersDeferred;
414
413
  if (currentEpoch >= config.FULU_FORK_EPOCH) {
415
- // Overwrite proposers with state.proposerLookahead
416
- proposers = (state as CachedBeaconStateFulu).proposerLookahead.getAll().slice(0, SLOTS_PER_EPOCH);
414
+ // After fulu, use state.proposerLookahead for current and next epoch proposers.
415
+ // Computing from the unfiltered active shuffling would include slashed validators in gloas.
416
+ const proposerLookahead = (state as CachedBeaconStateFulu).proposerLookahead.getAll();
417
+ proposers = proposerLookahead.slice(0, SLOTS_PER_EPOCH);
418
+ proposersNextEpoch = {
419
+ computed: true,
420
+ indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
421
+ };
417
422
  } else {
418
423
  // We need to calculate Pre-fulu
419
424
  // Allow to create CachedBeaconState for empty states, or no active validators
@@ -421,18 +426,17 @@ export class EpochCache {
421
426
  currentShuffling.activeIndices.length > 0
422
427
  ? computeProposers(
423
428
  config.getForkSeqAtEpoch(currentEpoch),
424
- currentProposerSeed,
429
+ getSeed(state, currentEpoch, DOMAIN_BEACON_PROPOSER),
425
430
  currentShuffling,
426
431
  effectiveBalanceIncrements
427
432
  )
428
433
  : [];
434
+ proposersNextEpoch = {
435
+ computed: false,
436
+ seed: getSeed(state, nextEpoch, DOMAIN_BEACON_PROPOSER),
437
+ };
429
438
  }
430
439
 
431
- const proposersNextEpoch: ProposersDeferred = {
432
- computed: false,
433
- seed: getSeed(state, nextEpoch, DOMAIN_BEACON_PROPOSER),
434
- };
435
-
436
440
  // Only after altair, compute the indices of the current sync committee
437
441
  const afterAltairFork = currentEpoch >= config.ALTAIR_FORK_EPOCH;
438
442
 
@@ -713,17 +717,10 @@ export class EpochCache {
713
717
  // Populate proposer cache with lookahead from state
714
718
  const proposerLookahead = (state as CachedBeaconStateFulu).proposerLookahead.getAll();
715
719
  this.proposers = proposerLookahead.slice(0, SLOTS_PER_EPOCH);
716
-
717
- if (proposerLookahead.length >= SLOTS_PER_EPOCH * 2) {
718
- this.proposersNextEpoch = {
719
- computed: true,
720
- indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
721
- };
722
- } else {
723
- // This should not happen unless MIN_SEED_LOOKAHEAD is set to 0
724
- // this ensures things don't break if the proposer lookahead is not long enough
725
- this.proposersNextEpoch = {computed: false, seed: getSeed(state, epochAfterUpcoming, DOMAIN_BEACON_PROPOSER)};
726
- }
720
+ this.proposersNextEpoch = {
721
+ computed: true,
722
+ indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
723
+ };
727
724
  } else {
728
725
  // Need to calculate proposers pre-fulu
729
726
  const upcomingProposerSeed = getSeed(state, upcomingEpoch, DOMAIN_BEACON_PROPOSER);
@@ -1,5 +1,6 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {loadState} from "../util/loadState/loadState.js";
3
+ import {isViewDUNodesPopulated} from "../util/ssz.js";
3
4
  import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js";
4
5
  import {RewardCache, createEmptyRewardCache} from "./rewardCache.js";
5
6
  import {
@@ -254,9 +255,9 @@ export function isCachedBeaconState<T extends BeaconStateAllForks>(
254
255
  // This cache is populated during epoch transition, and should be preserved for performance.
255
256
  // If the cache is missing too often, means that our clone strategy is not working well.
256
257
  export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
257
- return (state.validators as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
258
+ return isViewDUNodesPopulated(state.validators);
258
259
  }
259
260
 
260
261
  export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
261
- return (state.balances as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
262
+ return isViewDUNodesPopulated(state.balances);
262
263
  }
@@ -193,11 +193,11 @@ export function nextSyncCommitteeGindexAtFork(fork: ForkName): number {
193
193
  return NEXT_SYNC_COMMITTEE_GINDEX;
194
194
  }
195
195
 
196
- export function getGindexDepth(gindex: number): number {
196
+ function getGindexDepth(gindex: number): number {
197
197
  return Math.floor(Math.log2(gindex));
198
198
  }
199
199
 
200
- export function getGindexIndex(gindex: number): number {
200
+ function getGindexIndex(gindex: number): number {
201
201
  return gindex - 2 ** getGindexDepth(gindex);
202
202
  }
203
203
 
package/src/metrics.ts CHANGED
@@ -3,6 +3,7 @@ import {ProposerRewardType} from "./block/types.js";
3
3
  import {EpochTransitionStep} from "./epoch/index.js";
4
4
  import {StateCloneSource, StateHashTreeRootSource} from "./stateTransition.js";
5
5
  import {CachedBeaconStateAllForks} from "./types.js";
6
+ import {isViewDUNodesPopulated} from "./util/ssz.js";
6
7
 
7
8
  export type BeaconStateTransitionMetrics = ReturnType<typeof getMetrics>;
8
9
 
@@ -159,9 +160,9 @@ export function onPostStateMetrics(postState: CachedBeaconStateAllForks, metrics
159
160
  // This cache is populated during epoch transition, and should be preserved for performance.
160
161
  // If the cache is missing too often, means that our clone strategy is not working well.
161
162
  function isValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
162
- return (state.validators as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
163
+ return isViewDUNodesPopulated(state.validators);
163
164
  }
164
165
 
165
166
  function isBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
166
- return (state.balances as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
167
+ return isViewDUNodesPopulated(state.balances);
167
168
  }
@@ -4,11 +4,17 @@ import {
4
4
  WHISTLEBLOWER_REWARD_QUOTIENT,
5
5
  WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA,
6
6
  isForkPostElectra,
7
+ isForkPostGloas,
7
8
  } from "@lodestar/params";
8
- import {BeaconBlock, altair, phase0, rewards} from "@lodestar/types";
9
+ import {BeaconBlock, Slot, altair, phase0, rewards} from "@lodestar/types";
9
10
  import {processAttestationsAltair} from "../block/processAttestationsAltair.js";
10
11
  import {RewardCache} from "../cache/rewardCache.js";
11
- import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../cache/stateCache.js";
12
+ import {
13
+ CachedBeaconStateAllForks,
14
+ CachedBeaconStateAltair,
15
+ CachedBeaconStateGloas,
16
+ CachedBeaconStatePhase0,
17
+ } from "../cache/stateCache.js";
12
18
  import {getAttesterSlashableIndices} from "../util/attestation.js";
13
19
 
14
20
  type SubRewardValue = number; // All reward values should be integer
@@ -36,10 +42,18 @@ export async function computeBlockRewards(
36
42
  let syncAggregateReward = cachedSyncAggregateReward;
37
43
 
38
44
  if (blockAttestationReward === 0) {
45
+ const parentSlot = isForkPostGloas(fork)
46
+ ? (preState as CachedBeaconStateGloas).latestExecutionPayloadBid.slot
47
+ : null;
39
48
  blockAttestationReward =
40
49
  fork === ForkName.phase0
41
50
  ? computeBlockAttestationRewardPhase0(block as phase0.BeaconBlock, preState as CachedBeaconStatePhase0)
42
- : computeBlockAttestationRewardAltair(config, block as altair.BeaconBlock, preState as CachedBeaconStateAltair);
51
+ : computeBlockAttestationRewardAltair(
52
+ config,
53
+ block as altair.BeaconBlock,
54
+ preState as CachedBeaconStateAltair,
55
+ parentSlot
56
+ );
43
57
  }
44
58
 
45
59
  if (syncAggregateReward === 0) {
@@ -79,12 +93,13 @@ function computeBlockAttestationRewardPhase0(
79
93
  function computeBlockAttestationRewardAltair(
80
94
  config: BeaconConfig,
81
95
  block: altair.BeaconBlock,
82
- preState: CachedBeaconStateAltair
96
+ preState: CachedBeaconStateAltair,
97
+ parentSlot: Slot | null
83
98
  ): SubRewardValue {
84
99
  const fork = config.getForkSeq(block.slot);
85
100
  const {attestations} = block.body;
86
101
 
87
- processAttestationsAltair(fork, preState, attestations, false);
102
+ processAttestationsAltair(fork, preState, attestations, parentSlot, false);
88
103
 
89
104
  return preState.proposerRewards.attestations;
90
105
  }
@@ -137,6 +137,7 @@ function translateParticipation(
137
137
  attestation.inclusionDelay,
138
138
  epochCtx.epoch,
139
139
  rootCache,
140
+ null,
140
141
  null
141
142
  );
142
143
 
@@ -70,7 +70,7 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
70
70
  stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
71
71
  stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
72
72
  stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
73
- stateGloasView.latestExecutionPayloadBid.gasLimit = stateFulu.latestExecutionPayloadHeader.gasLimit;
73
+ stateGloasView.latestExecutionPayloadBid.gasLimit = BigInt(stateFulu.latestExecutionPayloadHeader.gasLimit);
74
74
  stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(
75
75
  ssz.gloas.ExecutionRequests.defaultValue()
76
76
  );
@@ -54,7 +54,7 @@ export function generateState(opts?: TestBeaconState): BeaconStatePhase0 {
54
54
  eth1Data: {
55
55
  depositRoot: Buffer.alloc(32),
56
56
  blockHash: Buffer.alloc(32),
57
- depositCount: 0,
57
+ depositCount: 0n,
58
58
  },
59
59
  eth1DataVotes: [],
60
60
  eth1DepositIndex: 0,
@@ -437,13 +437,13 @@ function buildPerformanceStatePhase0(pubkeysArg?: Uint8Array[]): phase0.BeaconSt
437
437
  historicalRoots: [],
438
438
  // Eth1
439
439
  eth1Data: {
440
- depositCount: pubkeys.length,
440
+ depositCount: BigInt(pubkeys.length),
441
441
  depositRoot: fromHexString("0xcb1f89a924cfd31224823db5a41b1643f10faa7aedf231f1e28887f6ee98c047"),
442
442
  blockHash: fromHexString("0x701fb2869ce16d0f1d14f6705725adb0dec6799da29006dfc6fff83960298f21"),
443
443
  },
444
444
  // minus one so that inserting 1 from block works
445
445
  eth1DataVotes: newFilledArray(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH - 1, {
446
- depositCount: 1,
446
+ depositCount: 1n,
447
447
  depositRoot: Buffer.alloc(32, 1),
448
448
  blockHash: Buffer.alloc(32, 1),
449
449
  }),
@@ -0,0 +1,183 @@
1
+ import {ChainForkConfig} from "@lodestar/config";
2
+ import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params";
3
+ import {Epoch, Slot, TimeSeconds} from "@lodestar/types";
4
+ import {ErrorAborted, Logger, isErrorAborted, sleep} from "@lodestar/utils";
5
+ import {computeEpochAtSlot} from "./epoch.js";
6
+ import {computeTimeAtSlot, getCurrentSlot} from "./slot.js";
7
+
8
+ type RunEveryFn = (slot: Slot, signal: AbortSignal) => Promise<void>;
9
+
10
+ export type ClockOptions = {
11
+ skipSlots?: boolean;
12
+ };
13
+
14
+ export interface IClock {
15
+ readonly genesisTime: number;
16
+ readonly secondsPerSlot: number;
17
+
18
+ readonly currentEpoch: number;
19
+
20
+ start(signal: AbortSignal): void;
21
+ runEverySlot(fn: (slot: Slot, signal: AbortSignal) => Promise<void>): void;
22
+ runEveryEpoch(fn: (epoch: Epoch, signal: AbortSignal) => Promise<void>): void;
23
+ msToSlot(slot: Slot): number;
24
+ msFromSlot(slot: Slot): number;
25
+ secFromSlot(slot: Slot): number;
26
+ getCurrentSlot(): Slot;
27
+ getCurrentEpoch(): Epoch;
28
+ }
29
+
30
+ export enum TimeItem {
31
+ Slot,
32
+ Epoch,
33
+ }
34
+
35
+ export class Clock implements IClock {
36
+ readonly genesisTime: number;
37
+ readonly secondsPerSlot: number;
38
+ private readonly config: ChainForkConfig;
39
+ private readonly logger: Logger;
40
+ private readonly fns: {timeItem: TimeItem; fn: RunEveryFn}[] = [];
41
+
42
+ constructor(
43
+ config: ChainForkConfig,
44
+ logger: Logger,
45
+ private readonly opts: {genesisTime: number} & ClockOptions
46
+ ) {
47
+ this.genesisTime = opts.genesisTime;
48
+ this.secondsPerSlot = config.SLOT_DURATION_MS / 1000;
49
+ this.config = config;
50
+ this.logger = logger;
51
+ }
52
+
53
+ get currentEpoch(): Epoch {
54
+ return computeEpochAtSlot(getCurrentSlot(this.config, this.genesisTime));
55
+ }
56
+
57
+ start(signal: AbortSignal): void {
58
+ for (const {timeItem, fn} of this.fns) {
59
+ this.runAtMostEvery(timeItem, signal, fn).catch((e: Error) => {
60
+ if (!isErrorAborted(e)) {
61
+ this.logger.error("runAtMostEvery", {}, e);
62
+ }
63
+ });
64
+ }
65
+ }
66
+
67
+ getCurrentSlot(): Slot {
68
+ return getCurrentSlot(this.config, this.genesisTime);
69
+ }
70
+
71
+ getCurrentEpoch(): Epoch {
72
+ return computeEpochAtSlot(getCurrentSlot(this.config, this.genesisTime));
73
+ }
74
+
75
+ runEverySlot(fn: RunEveryFn): void {
76
+ this.fns.push({timeItem: TimeItem.Slot, fn});
77
+ }
78
+
79
+ runEveryEpoch(fn: RunEveryFn): void {
80
+ this.fns.push({timeItem: TimeItem.Epoch, fn});
81
+ }
82
+
83
+ /** Milliseconds from now to a specific slot */
84
+ msToSlot(slot: Slot): number {
85
+ return computeTimeAtSlot(this.config, slot, this.genesisTime) * 1000 - Date.now();
86
+ }
87
+
88
+ /** Milliseconds elapsed from a specific slot to now */
89
+ msFromSlot(slot: Slot): number {
90
+ return Date.now() - computeTimeAtSlot(this.config, slot, this.genesisTime) * 1000;
91
+ }
92
+
93
+ /** Seconds elapsed from a specific slot to now */
94
+ secFromSlot(slot: Slot): number {
95
+ return Date.now() / 1000 - computeTimeAtSlot(this.config, slot, this.genesisTime);
96
+ }
97
+
98
+ /**
99
+ * If a task happens to take more than one slot to run, we might skip a slot. This is unfortunate,
100
+ * however the alternative is to *always* process every slot, which has the chance of creating a
101
+ * theoretically unlimited backlog of tasks. It was a conscious decision to choose to drop tasks
102
+ * on an overloaded/latent system rather than overload it even more.
103
+ */
104
+ private async runAtMostEvery(timeItem: TimeItem, signal: AbortSignal, fn: RunEveryFn): Promise<void> {
105
+ // Run immediately first
106
+ let slot = getCurrentSlot(this.config, this.genesisTime);
107
+ let slotOrEpoch = timeItem === TimeItem.Slot ? slot : computeEpochAtSlot(slot);
108
+ while (!signal.aborted) {
109
+ // Must catch fn() to ensure `sleep()` is awaited both for resolve and reject
110
+ const task = fn(slotOrEpoch, signal).catch((e: Error) => {
111
+ if (!isErrorAborted(e)) this.logger.error("Error on runEvery fn", {}, e);
112
+ });
113
+
114
+ if (timeItem !== TimeItem.Slot || this.opts.skipSlots !== false) {
115
+ // await response to only continue with next task if current task finished within slot
116
+ await task;
117
+ }
118
+
119
+ try {
120
+ await sleep(this.timeUntilNext(timeItem), signal);
121
+ // calling getCurrentSlot here may not be correct when we're close to the next slot
122
+ // it's safe to call getCurrentSlotAround after we sleep
123
+ const nextSlot = getCurrentSlotAround(this.config, this.genesisTime);
124
+
125
+ if (timeItem === TimeItem.Slot) {
126
+ if (nextSlot > slot + 1) {
127
+ // It's not very likely that we skip more than one slot as HTTP timeout is set
128
+ // to SLOT_DURATION_MS so we will fail task before skipping another slot.
129
+ this.logger.warn("Skipped slot due to task taking more than one slot to run", {
130
+ skippedSlot: slot + 1,
131
+ });
132
+ }
133
+ slotOrEpoch = nextSlot;
134
+ } else {
135
+ slotOrEpoch = computeEpochAtSlot(nextSlot);
136
+ }
137
+ slot = nextSlot;
138
+ } catch (e) {
139
+ if (e instanceof ErrorAborted) {
140
+ return;
141
+ }
142
+ throw e;
143
+ }
144
+ }
145
+ }
146
+
147
+ private timeUntilNext(timeItem: TimeItem): number {
148
+ const milliSecondsPerSlot = this.config.SLOT_DURATION_MS;
149
+ const msFromGenesis = Date.now() - this.genesisTime * 1000;
150
+
151
+ if (timeItem === TimeItem.Slot) {
152
+ if (msFromGenesis >= 0) {
153
+ return milliSecondsPerSlot - (msFromGenesis % milliSecondsPerSlot);
154
+ }
155
+ return Math.abs(msFromGenesis) % milliSecondsPerSlot;
156
+ }
157
+ const milliSecondsPerEpoch = SLOTS_PER_EPOCH * milliSecondsPerSlot;
158
+ if (msFromGenesis >= 0) {
159
+ return milliSecondsPerEpoch - (msFromGenesis % milliSecondsPerEpoch);
160
+ }
161
+ return Math.abs(msFromGenesis) % milliSecondsPerEpoch;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Same to the spec but we use Math.round instead of Math.floor.
167
+ */
168
+ export function getCurrentSlotAround(config: ChainForkConfig, genesisTime: TimeSeconds): Slot {
169
+ const diffInSeconds = Date.now() / 1000 - genesisTime;
170
+ const slotsSinceGenesis = Math.round((diffInSeconds * 1000) / config.SLOT_DURATION_MS);
171
+ return GENESIS_SLOT + slotsSinceGenesis;
172
+ }
173
+
174
+ // function useEventStream() {
175
+ // this.stream = this.events.getEventStream([BeaconEventType.BLOCK, BeaconEventType.HEAD, BeaconEventType.CHAIN_REORG]);
176
+ // pipeToEmitter(this.stream, this).catch((e: Error) => {
177
+ // this.logger.error("Error on stream pipe", {}, e);
178
+ // });
179
+
180
+ // // On stop
181
+ // this.stream.stop();
182
+ // this.stream = null;
183
+ // }
@@ -4,19 +4,21 @@ import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js";
4
4
 
5
5
  export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 {
6
6
  const eth1DataToUse = eth1Data ?? state.eth1Data;
7
+ // Proposer can set any value, use in bigint until the result is bounded by MAX_DEPOSITS
8
+ const depositCount = eth1DataToUse.depositCount;
9
+ const eth1DepositIndex = BigInt(state.eth1DepositIndex);
10
+ const maxDeposits = BigInt(MAX_DEPOSITS);
7
11
  if (state.config.getForkSeq(state.slot) >= ForkSeq.electra) {
8
12
  const electraState = state as CachedBeaconStateElectra;
9
- // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64
10
- // since the result lies within upper and lower bound of UintNum64
11
- const eth1DataIndexLimit: UintNum64 =
12
- eth1DataToUse.depositCount < electraState.depositRequestsStartIndex
13
- ? eth1DataToUse.depositCount
14
- : Number(electraState.depositRequestsStartIndex);
13
+ const eth1DataIndexLimit =
14
+ depositCount < electraState.depositRequestsStartIndex ? depositCount : electraState.depositRequestsStartIndex;
15
15
 
16
- if (state.eth1DepositIndex < eth1DataIndexLimit) {
17
- return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex);
16
+ if (eth1DepositIndex < eth1DataIndexLimit) {
17
+ const available = eth1DataIndexLimit - eth1DepositIndex;
18
+ return Number(available < maxDeposits ? available : maxDeposits);
18
19
  }
19
20
  return 0;
20
21
  }
21
- return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex);
22
+ const available = depositCount - eth1DepositIndex;
23
+ return Number(available < maxDeposits ? available : maxDeposits);
22
24
  }
@@ -139,7 +139,7 @@ export function applyDeposits(
139
139
  const fullDepositDataRootArr = fullDepositDataRootList ? fullDepositDataRootList.getAllReadonlyValues() : null;
140
140
 
141
141
  if (fullDepositDataRootArr) {
142
- const depositCount = state.eth1Data.depositCount;
142
+ const depositCount = Number(state.eth1Data.depositCount);
143
143
  for (let index = 0; index < depositCount; index++) {
144
144
  depositDataRootList.push(fullDepositDataRootArr[index]);
145
145
  }
@@ -160,7 +160,7 @@ export function applyDeposits(
160
160
  );
161
161
  }
162
162
 
163
- state.eth1Data.depositCount += 1;
163
+ state.eth1Data.depositCount += 1n;
164
164
 
165
165
  const fork = config.getForkSeq(GENESIS_SLOT);
166
166
  processDeposit(fork, state, deposit);
package/src/util/gloas.ts CHANGED
@@ -87,15 +87,19 @@ export function isActiveBuilder(builder: gloas.Builder, finalizedEpoch: Epoch):
87
87
  * From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
88
88
  */
89
89
  export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: number): number {
90
- const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / 1024), 1) - 1;
90
+ return Number(getExpectedGasLimitBigint(BigInt(parentGasLimit), BigInt(targetGasLimit)));
91
+ }
92
+
93
+ export function getExpectedGasLimitBigint(parentGasLimit: bigint, targetGasLimit: bigint): bigint {
94
+ const maxGasLimitDifference = (parentGasLimit / 1024n > 1n ? parentGasLimit / 1024n : 1n) - 1n;
91
95
 
92
96
  if (targetGasLimit > parentGasLimit) {
93
97
  const gasDiff = targetGasLimit - parentGasLimit;
94
- return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference);
98
+ return parentGasLimit + (gasDiff < maxGasLimitDifference ? gasDiff : maxGasLimitDifference);
95
99
  }
96
100
 
97
101
  const gasDiff = parentGasLimit - targetGasLimit;
98
- return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference);
102
+ return parentGasLimit - (gasDiff < maxGasLimitDifference ? gasDiff : maxGasLimitDifference);
99
103
  }
100
104
 
101
105
  /**
@@ -104,8 +108,8 @@ export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: numb
104
108
  * adjustment step of the parent, otherwise it must hit the clamped boundary.
105
109
  * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/builder.md#new-is_gas_limit_target_compatible
106
110
  */
107
- export function isGasLimitTargetCompatible(parentGasLimit: number, gasLimit: number, targetGasLimit: number): boolean {
108
- return gasLimit === getExpectedGasLimit(parentGasLimit, targetGasLimit);
111
+ export function isGasLimitTargetCompatible(parentGasLimit: bigint, gasLimit: bigint, targetGasLimit: bigint): boolean {
112
+ return gasLimit === getExpectedGasLimitBigint(parentGasLimit, targetGasLimit);
109
113
  }
110
114
 
111
115
  /**
package/src/util/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./balance.js";
6
6
  export * from "./blindedBlock.js";
7
7
  export * from "./blockRoot.js";
8
8
  export * from "./capella.js";
9
+ export * from "./clock.js";
9
10
  export * from "./computeAnchorCheckpoint.js";
10
11
  export * from "./deposit.js";
11
12
  export * from "./domain.js";