@lodestar/state-transition 1.43.0 → 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.
Files changed (82) hide show
  1. package/lib/block/processDepositRequest.d.ts +3 -11
  2. package/lib/block/processDepositRequest.d.ts.map +1 -1
  3. package/lib/block/processDepositRequest.js +27 -35
  4. package/lib/block/processDepositRequest.js.map +1 -1
  5. package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
  6. package/lib/block/processParentExecutionPayload.js +4 -3
  7. package/lib/block/processParentExecutionPayload.js.map +1 -1
  8. package/lib/cache/epochCache.d.ts.map +1 -1
  9. package/lib/cache/epochCache.js +10 -7
  10. package/lib/cache/epochCache.js.map +1 -1
  11. package/lib/lightClient/spec/index.d.ts +22 -0
  12. package/lib/lightClient/spec/index.d.ts.map +1 -0
  13. package/lib/lightClient/spec/index.js +58 -0
  14. package/lib/lightClient/spec/index.js.map +1 -0
  15. package/lib/lightClient/spec/isBetterUpdate.d.ts +23 -0
  16. package/lib/lightClient/spec/isBetterUpdate.d.ts.map +1 -0
  17. package/lib/lightClient/spec/isBetterUpdate.js +66 -0
  18. package/lib/lightClient/spec/isBetterUpdate.js.map +1 -0
  19. package/lib/lightClient/spec/processLightClientUpdate.d.ts +12 -0
  20. package/lib/lightClient/spec/processLightClientUpdate.d.ts.map +1 -0
  21. package/lib/lightClient/spec/processLightClientUpdate.js +80 -0
  22. package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -0
  23. package/lib/lightClient/spec/store.d.ts +45 -0
  24. package/lib/lightClient/spec/store.d.ts.map +1 -0
  25. package/lib/lightClient/spec/store.js +56 -0
  26. package/lib/lightClient/spec/store.js.map +1 -0
  27. package/lib/lightClient/spec/utils.d.ts +47 -0
  28. package/lib/lightClient/spec/utils.d.ts.map +1 -0
  29. package/lib/lightClient/spec/utils.js +197 -0
  30. package/lib/lightClient/spec/utils.js.map +1 -0
  31. package/lib/lightClient/spec/validateLightClientBootstrap.d.ts +4 -0
  32. package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -0
  33. package/lib/lightClient/spec/validateLightClientBootstrap.js +22 -0
  34. package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -0
  35. package/lib/lightClient/spec/validateLightClientUpdate.d.ts +5 -0
  36. package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -0
  37. package/lib/lightClient/spec/validateLightClientUpdate.js +88 -0
  38. package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -0
  39. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
  40. package/lib/slot/upgradeStateToGloas.js +35 -29
  41. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  42. package/lib/stateView/beaconStateView.d.ts +9 -3
  43. package/lib/stateView/beaconStateView.d.ts.map +1 -1
  44. package/lib/stateView/beaconStateView.js +23 -4
  45. package/lib/stateView/beaconStateView.js.map +1 -1
  46. package/lib/stateView/interface.d.ts +2 -1
  47. package/lib/stateView/interface.d.ts.map +1 -1
  48. package/lib/stateView/interface.js.map +1 -1
  49. package/lib/util/gloas.d.ts +14 -0
  50. package/lib/util/gloas.d.ts.map +1 -1
  51. package/lib/util/gloas.js +24 -0
  52. package/lib/util/gloas.js.map +1 -1
  53. package/lib/util/index.d.ts +1 -0
  54. package/lib/util/index.d.ts.map +1 -1
  55. package/lib/util/index.js +1 -0
  56. package/lib/util/index.js.map +1 -1
  57. package/lib/util/pendingDepositsLookup.d.ts +40 -0
  58. package/lib/util/pendingDepositsLookup.d.ts.map +1 -0
  59. package/lib/util/pendingDepositsLookup.js +84 -0
  60. package/lib/util/pendingDepositsLookup.js.map +1 -0
  61. package/lib/util/shuffling.d.ts +6 -5
  62. package/lib/util/shuffling.d.ts.map +1 -1
  63. package/lib/util/shuffling.js +13 -15
  64. package/lib/util/shuffling.js.map +1 -1
  65. package/package.json +12 -7
  66. package/src/block/processDepositRequest.ts +29 -47
  67. package/src/block/processParentExecutionPayload.ts +4 -3
  68. package/src/cache/epochCache.ts +10 -7
  69. package/src/lightClient/spec/index.ts +101 -0
  70. package/src/lightClient/spec/isBetterUpdate.ts +94 -0
  71. package/src/lightClient/spec/processLightClientUpdate.ts +119 -0
  72. package/src/lightClient/spec/store.ts +106 -0
  73. package/src/lightClient/spec/utils.ts +317 -0
  74. package/src/lightClient/spec/validateLightClientBootstrap.ts +39 -0
  75. package/src/lightClient/spec/validateLightClientUpdate.ts +145 -0
  76. package/src/slot/upgradeStateToGloas.ts +43 -45
  77. package/src/stateView/beaconStateView.ts +23 -4
  78. package/src/stateView/interface.ts +2 -1
  79. package/src/util/gloas.ts +28 -0
  80. package/src/util/index.ts +1 -0
  81. package/src/util/pendingDepositsLookup.ts +105 -0
  82. package/src/util/shuffling.ts +17 -15
@@ -0,0 +1,84 @@
1
+ import { toPubkeyHex } from "@lodestar/utils";
2
+ import { isValidDepositSignature } from "../block/processDeposit.js";
3
+ /**
4
+ * Mutable lookup for the pending-deposit sequence used by builder-routing logic.
5
+ *
6
+ * This is to implement the spec's `is_pending_validator(pending_deposits, pubkey)` lazily:
7
+ * deposits are grouped by pubkey without verifying signatures, and BLS verification is
8
+ * deferred until a builder deposit needs to know whether the same pubkey already has a
9
+ * valid pending validator deposit.
10
+ *
11
+ * Call `add()` whenever a deposit is appended to the represented sequence. A cached `true`
12
+ * result short-circuits all subsequent checks for that pubkey; a cached `false` records
13
+ * how many deposits were already verified, so appending a new deposit only verifies the
14
+ * newly-appended tail rather than re-running BLS on previously-invalid entries.
15
+ */
16
+ export class PendingDepositsLookup {
17
+ depositsByPubkey;
18
+ validationCache;
19
+ constructor(depositsByPubkey, validationCache) {
20
+ this.depositsByPubkey = depositsByPubkey;
21
+ this.validationCache = validationCache;
22
+ }
23
+ /** Build an empty lookup for a sequence that will be populated incrementally. */
24
+ static buildEmpty() {
25
+ return new PendingDepositsLookup(new Map(), new Map());
26
+ }
27
+ /**
28
+ * Build a pubkey -> pending-deposits lookup from `state.pendingDeposits`.
29
+ * No BLS work is done here; signature verification happens lazily in `hasPendingValidator`.
30
+ */
31
+ static build(state) {
32
+ const lookup = PendingDepositsLookup.buildEmpty();
33
+ for (const pendingDeposit of state.pendingDeposits.getAllReadonly()) {
34
+ lookup.add(pendingDeposit);
35
+ }
36
+ return lookup;
37
+ }
38
+ /**
39
+ * Append a pending deposit to the represented sequence.
40
+ * Pass `pubkeyHex` if the caller has already computed it.
41
+ */
42
+ add(pendingDeposit, pubkeyHex) {
43
+ const key = pubkeyHex ?? toPubkeyHex(pendingDeposit.pubkey);
44
+ const existing = this.depositsByPubkey.get(key);
45
+ if (existing) {
46
+ existing.push(pendingDeposit);
47
+ }
48
+ else {
49
+ this.depositsByPubkey.set(key, [pendingDeposit]);
50
+ }
51
+ }
52
+ /**
53
+ * Returns true if any pending deposit for `pubkeyHex` has a valid BLS deposit signature.
54
+ * Memoizes the result in `validationCache` so repeated checks for the same pubkey
55
+ * within a block only verify deposits that have not already been checked.
56
+ */
57
+ hasPendingValidator(config, pubkeyHex) {
58
+ const validation = this.validationCache.get(pubkeyHex);
59
+ if (validation?.hasValidSignature === true) {
60
+ return true;
61
+ }
62
+ const deposits = this.depositsByPubkey.get(pubkeyHex);
63
+ if (deposits === undefined) {
64
+ return false;
65
+ }
66
+ // hasValidSignature is false or undefined; resume from the last validatedCount so
67
+ // previously-checked invalid deposits are not re-verified.
68
+ const startIndex = validation?.validatedCount ?? 0;
69
+ if (startIndex === deposits.length) {
70
+ // Nothing new to check; the cached false result still holds.
71
+ return false;
72
+ }
73
+ for (let i = startIndex; i < deposits.length; i++) {
74
+ const deposit = deposits[i];
75
+ if (isValidDepositSignature(config, deposit.pubkey, deposit.withdrawalCredentials, deposit.amount, deposit.signature)) {
76
+ this.validationCache.set(pubkeyHex, { hasValidSignature: true, validatedCount: i + 1 });
77
+ return true;
78
+ }
79
+ }
80
+ this.validationCache.set(pubkeyHex, { hasValidSignature: false, validatedCount: deposits.length });
81
+ return false;
82
+ }
83
+ }
84
+ //# sourceMappingURL=pendingDepositsLookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pendingDepositsLookup.js","sourceRoot":"","sources":["../../src/util/pendingDepositsLookup.ts"],"names":[],"mappings":"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"}
@@ -5,13 +5,14 @@ import { CachedBeaconStateAllForks } from "../cache/stateCache.js";
5
5
  import { IBeaconStateView } from "../stateView/interface.js";
6
6
  import { EpochShuffling } from "./epochShuffling.js";
7
7
  /**
8
- * Returns the block root which decided the proposer shuffling for the current epoch. This root
9
- * can be used to key this proposer shuffling.
8
+ * Block root that decided the proposer shuffling for `proposalEpoch` (keys that shuffling).
9
+ * Computed for the requested epoch, not `state.epoch`, so it is correct when `state` is one
10
+ * epoch off the requested epoch (e.g. serving next-epoch duties from the current state).
10
11
  *
11
- * Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
12
- * It should be set to the latest block applied to this `state` or the genesis block root.
12
+ * Returns `null` when the genesis block decides its own shuffling (caller falls back to the
13
+ * genesis block root).
13
14
  */
14
- export declare function proposerShufflingDecisionRoot(fork: ForkName, state: IBeaconStateView): Root | null;
15
+ export declare function proposerShufflingDecisionRoot(fork: ForkName, state: IBeaconStateView, proposalEpoch: Epoch): Root | null;
15
16
  /**
16
17
  * Returns the block root which decided the attester shuffling for the given `requestedEpoch`.
17
18
  * This root can be used to key that attester shuffling.
@@ -1 +1 @@
1
- {"version":3,"file":"shuffling.d.ts","sourceRoot":"","sources":["../../src/util/shuffling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAkC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,WAAW,EACX,cAAc,EACd,KAAK,EACL,kBAAkB,EAClB,IAAI,EACJ,IAAI,EACJ,cAAc,EAEf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,yBAAyB,EAAC,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAMlG;AAaD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAMlH;AAsCD,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,MAAM,CAAC;IAChC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,cAAc,EAC9B,yBAAyB,EAAE,cAAc,EAAE,GAC1C,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAyBnC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,WAAW,GACvB,kBAAkB,CAWpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,CA6BrH;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,GAAG,WAAW,CAEjH;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,cAAc,EAAE,GACxB,WAAW,EAAE,CAoBf;AAED,oBAAY,kBAAkB;IAC5B,4BAA4B,iDAAiD;CAC9E;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,kBAAkB,CAAC,4BAA4B,CAAC;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,cAAe,SAAQ,aAAa,CAAC,kBAAkB,CAAC;CAAG"}
1
+ {"version":3,"file":"shuffling.d.ts","sourceRoot":"","sources":["../../src/util/shuffling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAkC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,WAAW,EACX,cAAc,EACd,KAAK,EACL,kBAAkB,EAClB,IAAI,EACJ,IAAI,EACJ,cAAc,EAEf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,yBAAyB,EAAC,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAEnD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,gBAAgB,EACvB,aAAa,EAAE,KAAK,GACnB,IAAI,GAAG,IAAI,CAMb;AAUD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAMlH;AAsCD,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,MAAM,CAAC;IAChC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,cAAc,EAC9B,yBAAyB,EAAE,cAAc,EAAE,GAC1C,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAyBnC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,WAAW,GACvB,kBAAkB,CAWpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,CA6BrH;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,GAAG,WAAW,CAEjH;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,cAAc,EAAE,GACxB,WAAW,EAAE,CAoBf;AAED,oBAAY,kBAAkB;IAC5B,4BAA4B,iDAAiD;CAC9E;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,kBAAkB,CAAC,4BAA4B,CAAC;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,cAAe,SAAQ,aAAa,CAAC,kBAAkB,CAAC;CAAG"}
@@ -3,28 +3,26 @@ import { LodestarError } from "@lodestar/utils";
3
3
  import { getBlockRootAtSlot } from "./blockRoot.js";
4
4
  import { computeStartSlotAtEpoch } from "./epoch.js";
5
5
  /**
6
- * Returns the block root which decided the proposer shuffling for the current epoch. This root
7
- * can be used to key this proposer shuffling.
6
+ * Block root that decided the proposer shuffling for `proposalEpoch` (keys that shuffling).
7
+ * Computed for the requested epoch, not `state.epoch`, so it is correct when `state` is one
8
+ * epoch off the requested epoch (e.g. serving next-epoch duties from the current state).
8
9
  *
9
- * Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
10
- * It should be set to the latest block applied to this `state` or the genesis block root.
10
+ * Returns `null` when the genesis block decides its own shuffling (caller falls back to the
11
+ * genesis block root).
11
12
  */
12
- export function proposerShufflingDecisionRoot(fork, state) {
13
- const decisionSlot = proposerShufflingDecisionSlot(fork, state);
13
+ export function proposerShufflingDecisionRoot(fork, state, proposalEpoch) {
14
+ const decisionSlot = proposerShufflingDecisionSlot(fork, proposalEpoch);
14
15
  if (state.slot === decisionSlot) {
15
16
  return null;
16
17
  }
17
18
  return state.getBlockRootAtSlot(decisionSlot);
18
19
  }
19
- /**
20
- * Returns the slot at which the proposer shuffling was decided. The block root at this slot
21
- * can be used to key the proposer shuffling for the current epoch.
22
- */
23
- function proposerShufflingDecisionSlot(fork, state) {
24
- // After fulu, the decision slot is in previous epoch due to deterministic proposer lookahead
25
- const epoch = isForkPostFulu(fork) ? state.epoch - 1 : state.epoch;
26
- const startSlot = computeStartSlotAtEpoch(epoch);
27
- return Math.max(startSlot - 1, 0);
20
+ /** Slot whose block root keys the proposer shuffling for `proposalEpoch`. */
21
+ function proposerShufflingDecisionSlot(fork, proposalEpoch) {
22
+ // Post-Fulu the shuffling is decided one epoch earlier (deterministic proposer lookahead,
23
+ // MIN_SEED_LOOKAHEAD = 1); pre-Fulu it is the last block before `proposalEpoch`.
24
+ const decisionEpoch = isForkPostFulu(fork) ? proposalEpoch - 1 : proposalEpoch;
25
+ return Math.max(computeStartSlotAtEpoch(decisionEpoch) - 1, 0);
28
26
  }
29
27
  /**
30
28
  * Returns the block root which decided the attester shuffling for the given `requestedEpoch`.
@@ -1 +1 @@
1
- {"version":3,"file":"shuffling.js","sourceRoot":"","sources":["../../src/util/shuffling.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shuffling.js","sourceRoot":"","sources":["../../src/util/shuffling.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/ChainSafe/lodestar/issues"
13
13
  },
14
- "version": "1.43.0",
14
+ "version": "1.44.0-dev.055b83cb3d",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
@@ -34,6 +34,11 @@
34
34
  "types": "./lib/slot/index.d.ts",
35
35
  "import": "./lib/slot/index.js"
36
36
  },
37
+ "./light-client": {
38
+ "bun": "./src/lightClient/spec/index.ts",
39
+ "types": "./lib/lightClient/spec/index.d.ts",
40
+ "import": "./lib/lightClient/spec/index.js"
41
+ },
37
42
  "./test-utils": {
38
43
  "bun": "./src/testUtils/index.ts",
39
44
  "types": "./lib/testUtils/index.d.ts",
@@ -67,14 +72,14 @@
67
72
  "@chainsafe/pubkey-index-map": "^3.0.0",
68
73
  "@chainsafe/ssz": "^1.4.0",
69
74
  "@chainsafe/swap-or-not-shuffle": "^1.2.1",
70
- "@lodestar/config": "^1.43.0",
71
- "@lodestar/params": "^1.43.0",
72
- "@lodestar/types": "^1.43.0",
73
- "@lodestar/utils": "^1.43.0",
75
+ "@lodestar/config": "^1.44.0-dev.055b83cb3d",
76
+ "@lodestar/params": "^1.44.0-dev.055b83cb3d",
77
+ "@lodestar/types": "^1.44.0-dev.055b83cb3d",
78
+ "@lodestar/utils": "^1.44.0-dev.055b83cb3d",
74
79
  "@vekexasia/bigint-buffer2": "^1.1.1"
75
80
  },
76
81
  "devDependencies": {
77
- "@lodestar/api": "^1.43.0"
82
+ "@lodestar/api": "^1.44.0-dev.055b83cb3d"
78
83
  },
79
84
  "keywords": [
80
85
  "ethereum",
@@ -82,5 +87,5 @@
82
87
  "beacon",
83
88
  "blockchain"
84
89
  ],
85
- "gitHead": "5cb87b7632ff76f9f93947147967618b26da2d0c"
90
+ "gitHead": "4038b49cad701b00bf8287e48f87df9fcb5542a0"
86
91
  }
@@ -1,10 +1,10 @@
1
- import {BeaconConfig} from "@lodestar/config";
2
1
  import {FAR_FUTURE_EPOCH, ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
3
- import {BLSPubkey, Bytes32, PubkeyHex, UintNum64, electra, ssz} from "@lodestar/types";
2
+ import {BLSPubkey, Bytes32, UintNum64, electra, ssz} from "@lodestar/types";
4
3
  import {toPubkeyHex} from "@lodestar/utils";
5
4
  import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
6
5
  import {findBuilderIndexByPubkey, isBuilderWithdrawalCredential} from "../util/gloas.js";
7
6
  import {computeEpochAtSlot, isValidatorKnown} from "../util/index.js";
7
+ import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
8
8
  import {isValidDepositSignature} from "./processDeposit.js";
9
9
 
10
10
  /**
@@ -76,53 +76,60 @@ function addBuilderToRegistry(
76
76
  }
77
77
  }
78
78
 
79
- // TODO GLOAS: pendingValidatorPubkeys cache is currently naive and has room for improvement.
80
- // Currently the cache lives in process_block, but we should put it in epochCache or elsewhere that has longer
81
- // lifetime to avoid duplicated deposit signature computation
79
+ // TODO GLOAS: the PendingDepositsLookup is currently scoped to a single envelope of
80
+ // deposit-requests. We can track it as ephemeral within EpochCache and transfer to the next block
81
+ // transition to reuse cached signature verifications.
82
82
  // See https://github.com/ChainSafe/lodestar/issues/9181
83
83
  export function processDepositRequest(
84
84
  fork: ForkSeq,
85
85
  state: CachedBeaconStateElectra | CachedBeaconStateGloas,
86
86
  depositRequest: electra.DepositRequest,
87
- pendingValidatorPubkeysCache?: Set<PubkeyHex>
87
+ pendingDepositsLookup?: PendingDepositsLookup
88
88
  ): void {
89
89
  const {pubkey, withdrawalCredentials, amount, signature} = depositRequest;
90
90
 
91
- // Check if this is a builder or validator deposit
92
91
  if (fork >= ForkSeq.gloas) {
93
92
  const stateGloas = state as CachedBeaconStateGloas;
94
- const pendingValidatorPubkeys =
95
- pendingValidatorPubkeysCache ?? getPendingValidatorPubkeys(state.config, stateGloas);
93
+ const lookup = pendingDepositsLookup ?? PendingDepositsLookup.build(stateGloas);
96
94
  const pubkeyHex = toPubkeyHex(pubkey);
97
95
  const builderIndex = findBuilderIndexByPubkey(stateGloas, pubkey);
98
96
  const validatorIndex = state.epochCtx.getValidatorIndex(pubkey);
99
97
 
100
- // Regardless of the withdrawal credentials prefix, if a builder/validator
101
- // already exists with this pubkey, apply the deposit to their balance
102
98
  const isBuilder = builderIndex !== null;
103
99
  const isValidator = isValidatorKnown(state, validatorIndex);
104
- const isPendingValidator = pendingValidatorPubkeys.has(pubkeyHex);
105
100
 
106
- if (isBuilder || (isBuilderWithdrawalCredential(withdrawalCredentials) && !isValidator && !isPendingValidator)) {
107
- // Apply builder deposits immediately
101
+ if (isBuilder) {
102
+ // Top up an existing builder regardless of withdrawal credential prefix
108
103
  applyDepositForBuilder(stateGloas, pubkey, withdrawalCredentials, amount, signature, state.slot);
109
104
  return;
110
105
  }
111
106
 
112
- // Keep the shared cache in sync: if this deposit has a valid signature, subsequent
113
- // deposit requests for the same pubkey in this envelope must see it as a pending validator
107
+ // Only check the (expensive) "pending validator" condition when needed
114
108
  if (
115
- pendingValidatorPubkeysCache &&
109
+ isBuilderWithdrawalCredential(withdrawalCredentials) &&
116
110
  !isValidator &&
117
- !isPendingValidator &&
118
- isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)
111
+ !lookup.hasPendingValidator(state.config, pubkeyHex)
119
112
  ) {
120
- pendingValidatorPubkeys.add(pubkeyHex);
113
+ applyDepositForBuilder(stateGloas, pubkey, withdrawalCredentials, amount, signature, state.slot);
114
+ return;
121
115
  }
116
+
117
+ const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({
118
+ pubkey,
119
+ withdrawalCredentials,
120
+ amount,
121
+ signature,
122
+ slot: state.slot,
123
+ });
124
+ // Keep the lookup in sync with state.pendingDeposits so later deposit-requests
125
+ // in the same envelope see this deposit
126
+ lookup.add(pendingDeposit, pubkeyHex);
127
+ state.pendingDeposits.push(pendingDeposit);
128
+ return;
122
129
  }
123
130
 
124
- // Only set deposit_requests_start_index in Electra fork, not Gloas
125
- if (fork < ForkSeq.gloas && state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
131
+ // Pre-Gloas (Electra) path
132
+ if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
126
133
  state.depositRequestsStartIndex = depositRequest.index;
127
134
  }
128
135
 
@@ -136,28 +143,3 @@ export function processDepositRequest(
136
143
  });
137
144
  state.pendingDeposits.push(pendingDeposit);
138
145
  }
139
-
140
- /**
141
- * Build a set of pubkeys (hex-encoded) from pending deposits that have valid signatures.
142
- * This is computed once and passed to each processDepositRequest call to avoid
143
- * repeatedly iterating state.pendingDeposits.
144
- *
145
- * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/beacon-chain.md#new-is_pending_validator
146
- */
147
- export function getPendingValidatorPubkeys(config: BeaconConfig, state: CachedBeaconStateGloas): Set<PubkeyHex> {
148
- const result = new Set<PubkeyHex>();
149
- for (const pendingDeposit of state.pendingDeposits.getAllReadonly()) {
150
- if (
151
- isValidDepositSignature(
152
- config,
153
- pendingDeposit.pubkey,
154
- pendingDeposit.withdrawalCredentials,
155
- pendingDeposit.amount,
156
- pendingDeposit.signature
157
- )
158
- ) {
159
- result.add(toPubkeyHex(pendingDeposit.pubkey));
160
- }
161
- }
162
- return result;
163
- }
@@ -3,8 +3,9 @@ import {BeaconBlock, electra, ssz} from "@lodestar/types";
3
3
  import {byteArrayEquals, toRootHex} from "@lodestar/utils";
4
4
  import {CachedBeaconStateGloas} from "../types.js";
5
5
  import {computeEpochAtSlot} from "../util/epoch.js";
6
+ import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
6
7
  import {processConsolidationRequest} from "./processConsolidationRequest.js";
7
- import {getPendingValidatorPubkeys, processDepositRequest} from "./processDepositRequest.js";
8
+ import {processDepositRequest} from "./processDepositRequest.js";
8
9
  import {processWithdrawalRequest} from "./processWithdrawalRequest.js";
9
10
 
10
11
  /**
@@ -54,9 +55,9 @@ export function applyParentExecutionPayload(state: CachedBeaconStateGloas, reque
54
55
  // Process execution requests from parent's payload. The execution
55
56
  // requests are processed at state.slot (child's slot), not the parent's slot.
56
57
  if (requests.deposits.length > 0) {
57
- const pendingValidatorPubkeys = getPendingValidatorPubkeys(state.config, state);
58
+ const pendingDepositsLookup = PendingDepositsLookup.build(state);
58
59
  for (const deposit of requests.deposits) {
59
- processDepositRequest(fork, state, deposit, pendingValidatorPubkeys);
60
+ processDepositRequest(fork, state, deposit, pendingDepositsLookup);
60
61
  }
61
62
  }
62
63
 
@@ -782,14 +782,17 @@ export class EpochCache {
782
782
  */
783
783
  getBeaconProposer(slot: Slot): ValidatorIndex {
784
784
  const epoch = computeEpochAtSlot(slot);
785
- if (epoch !== this.currentShuffling.epoch) {
786
- throw new EpochCacheError({
787
- code: EpochCacheErrorCode.PROPOSER_EPOCH_MISMATCH,
788
- currentEpoch: this.currentShuffling.epoch,
789
- requestedEpoch: epoch,
790
- });
785
+ if (epoch === this.currentShuffling.epoch) {
786
+ return this.proposers[slot % SLOTS_PER_EPOCH];
787
+ }
788
+ if (epoch === this.nextEpoch) {
789
+ return this.getBeaconProposersNextEpoch()[slot % SLOTS_PER_EPOCH];
791
790
  }
792
- return this.proposers[slot % SLOTS_PER_EPOCH];
791
+ throw new EpochCacheError({
792
+ code: EpochCacheErrorCode.PROPOSER_EPOCH_MISMATCH,
793
+ currentEpoch: this.currentShuffling.epoch,
794
+ requestedEpoch: epoch,
795
+ });
793
796
  }
794
797
 
795
798
  getBeaconProposers(): ValidatorIndex[] {
@@ -0,0 +1,101 @@
1
+ import {BeaconConfig} from "@lodestar/config";
2
+ import {UPDATE_TIMEOUT} from "@lodestar/params";
3
+ import {
4
+ LightClientBootstrap,
5
+ LightClientFinalityUpdate,
6
+ LightClientOptimisticUpdate,
7
+ LightClientUpdate,
8
+ Slot,
9
+ } from "@lodestar/types";
10
+ import {computeSyncPeriodAtSlot} from "../../util/epoch.js";
11
+ import {
12
+ type ProcessUpdateOpts,
13
+ getSyncCommitteeAtPeriod,
14
+ processLightClientUpdate,
15
+ } from "./processLightClientUpdate.js";
16
+ import {type ILightClientStore, LightClientStore, type LightClientStoreEvents} from "./store.js";
17
+ import {ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroFinalityBranch, getZeroSyncCommitteeBranch} from "./utils.js";
18
+
19
+ export type {LightClientUpdateSummary} from "./isBetterUpdate.js";
20
+ export {isBetterUpdate, toLightClientUpdateSummary} from "./isBetterUpdate.js";
21
+ export {
22
+ type ProcessUpdateOpts,
23
+ getSyncCommitteeAtPeriod,
24
+ isSafeLightClientUpdate,
25
+ processLightClientUpdate,
26
+ } from "./processLightClientUpdate.js";
27
+ export {
28
+ type ILightClientStore,
29
+ LightClientStore,
30
+ type LightClientStoreEvents,
31
+ type LightClientUpdateWithSummary,
32
+ type SyncCommitteeFast,
33
+ } from "./store.js";
34
+ export {
35
+ getSafetyThreshold,
36
+ isFinalityUpdate,
37
+ isSyncCommitteeUpdate,
38
+ isValidLightClientHeader,
39
+ normalizeMerkleBranch,
40
+ upgradeLightClientFinalityUpdate,
41
+ upgradeLightClientHeader,
42
+ upgradeLightClientOptimisticUpdate,
43
+ upgradeLightClientStore,
44
+ upgradeLightClientUpdate,
45
+ } from "./utils.js";
46
+ export {validateLightClientBootstrap} from "./validateLightClientBootstrap.js";
47
+ export {validateLightClientUpdate} from "./validateLightClientUpdate.js";
48
+
49
+ export class LightclientSpec {
50
+ readonly store: ILightClientStore;
51
+ readonly config: BeaconConfig;
52
+
53
+ constructor(
54
+ config: BeaconConfig,
55
+ private readonly opts: ProcessUpdateOpts & LightClientStoreEvents,
56
+ bootstrap: LightClientBootstrap
57
+ ) {
58
+ this.store = new LightClientStore(config, bootstrap, opts);
59
+ this.config = config;
60
+ }
61
+
62
+ onUpdate(currentSlot: Slot, update: LightClientUpdate): void {
63
+ processLightClientUpdate(this.config, this.store, currentSlot, this.opts, update);
64
+ }
65
+
66
+ onFinalityUpdate(currentSlot: Slot, finalityUpdate: LightClientFinalityUpdate): void {
67
+ this.onUpdate(currentSlot, {
68
+ attestedHeader: finalityUpdate.attestedHeader,
69
+ nextSyncCommittee: ZERO_SYNC_COMMITTEE,
70
+ nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(finalityUpdate.signatureSlot)),
71
+ finalizedHeader: finalityUpdate.finalizedHeader,
72
+ finalityBranch: finalityUpdate.finalityBranch,
73
+ syncAggregate: finalityUpdate.syncAggregate,
74
+ signatureSlot: finalityUpdate.signatureSlot,
75
+ });
76
+ }
77
+
78
+ onOptimisticUpdate(currentSlot: Slot, optimisticUpdate: LightClientOptimisticUpdate): void {
79
+ this.onUpdate(currentSlot, {
80
+ attestedHeader: optimisticUpdate.attestedHeader,
81
+ nextSyncCommittee: ZERO_SYNC_COMMITTEE,
82
+ nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(optimisticUpdate.signatureSlot)),
83
+ finalizedHeader: {beacon: ZERO_HEADER},
84
+ finalityBranch: getZeroFinalityBranch(this.config.getForkName(optimisticUpdate.signatureSlot)),
85
+ syncAggregate: optimisticUpdate.syncAggregate,
86
+ signatureSlot: optimisticUpdate.signatureSlot,
87
+ });
88
+ }
89
+
90
+ forceUpdate(currentSlot: Slot): void {
91
+ for (const bestValidUpdate of this.store.bestValidUpdates.values()) {
92
+ if (currentSlot > bestValidUpdate.update.finalizedHeader.beacon.slot + UPDATE_TIMEOUT) {
93
+ const updatePeriod = computeSyncPeriodAtSlot(bestValidUpdate.update.signatureSlot);
94
+ // Simulate process_light_client_store_force_update() by forcing to apply a bestValidUpdate
95
+ // https://github.com/ethereum/consensus-specs/blob/a57e15636013eeba3610ff3ade41781dba1bb0cd/specs/altair/light-client/sync-protocol.md?plain=1#L394
96
+ // Call for `updatePeriod + 1` to force the update at `update.signatureSlot` to be applied
97
+ getSyncCommitteeAtPeriod(this.store, updatePeriod + 1, this.opts);
98
+ }
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,94 @@
1
+ import {SYNC_COMMITTEE_SIZE} from "@lodestar/params";
2
+ import {LightClientUpdate, Slot} from "@lodestar/types";
3
+ import {computeSyncPeriodAtSlot} from "../../util/epoch.js";
4
+ import {isFinalityUpdate, isSyncCommitteeUpdate, sumBits} from "./utils.js";
5
+
6
+ /**
7
+ * Wrapper type for `isBetterUpdate()` so we can apply its logic without requiring the full LightClientUpdate type.
8
+ */
9
+ export type LightClientUpdateSummary = {
10
+ activeParticipants: number;
11
+ attestedHeaderSlot: Slot;
12
+ signatureSlot: Slot;
13
+ finalizedHeaderSlot: Slot;
14
+ /** `if update.next_sync_committee_branch != [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]` */
15
+ isSyncCommitteeUpdate: boolean;
16
+ /** `if update.finality_branch != [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))]` */
17
+ isFinalityUpdate: boolean;
18
+ };
19
+
20
+ /**
21
+ * Returns the update with more bits. On ties, prevUpdate is the better
22
+ *
23
+ * https://github.com/ethereum/consensus-specs/blob/be3c774069e16e89145660be511c1b183056017e/specs/altair/light-client/sync-protocol.md#is_better_update
24
+ */
25
+ export function isBetterUpdate(newUpdate: LightClientUpdateSummary, oldUpdate: LightClientUpdateSummary): boolean {
26
+ // Compare supermajority (> 2/3) sync committee participation
27
+ const newNumActiveParticipants = newUpdate.activeParticipants;
28
+ const oldNumActiveParticipants = oldUpdate.activeParticipants;
29
+ const newHasSupermajority = newNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2;
30
+ const oldHasSupermajority = oldNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2;
31
+ if (newHasSupermajority !== oldHasSupermajority) {
32
+ return newHasSupermajority;
33
+ }
34
+ if (!newHasSupermajority && newNumActiveParticipants !== oldNumActiveParticipants) {
35
+ return newNumActiveParticipants > oldNumActiveParticipants;
36
+ }
37
+
38
+ // Compare presence of relevant sync committee
39
+ const newHasRelevantSyncCommittee =
40
+ newUpdate.isSyncCommitteeUpdate &&
41
+ computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.signatureSlot);
42
+ const oldHasRelevantSyncCommittee =
43
+ oldUpdate.isSyncCommitteeUpdate &&
44
+ computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.signatureSlot);
45
+ if (newHasRelevantSyncCommittee !== oldHasRelevantSyncCommittee) {
46
+ return newHasRelevantSyncCommittee;
47
+ }
48
+
49
+ // Compare indication of any finality
50
+ const newHasFinality = newUpdate.isFinalityUpdate;
51
+ const oldHasFinality = oldUpdate.isFinalityUpdate;
52
+ if (newHasFinality !== oldHasFinality) {
53
+ return newHasFinality;
54
+ }
55
+
56
+ // Compare sync committee finality
57
+ if (newHasFinality) {
58
+ const newHasSyncCommitteeFinality =
59
+ computeSyncPeriodAtSlot(newUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot);
60
+ const oldHasSyncCommitteeFinality =
61
+ computeSyncPeriodAtSlot(oldUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot);
62
+ if (newHasSyncCommitteeFinality !== oldHasSyncCommitteeFinality) {
63
+ return newHasSyncCommitteeFinality;
64
+ }
65
+ }
66
+
67
+ // Tiebreaker 1: Sync committee participation beyond supermajority
68
+ if (newNumActiveParticipants !== oldNumActiveParticipants) {
69
+ return newNumActiveParticipants > oldNumActiveParticipants;
70
+ }
71
+
72
+ // Tiebreaker 2: Prefer older data (fewer changes to best)
73
+ if (newUpdate.attestedHeaderSlot !== oldUpdate.attestedHeaderSlot) {
74
+ return newUpdate.attestedHeaderSlot < oldUpdate.attestedHeaderSlot;
75
+ }
76
+ return newUpdate.signatureSlot < oldUpdate.signatureSlot;
77
+ }
78
+
79
+ export function isSafeLightClientUpdate(update: LightClientUpdateSummary): boolean {
80
+ return (
81
+ update.activeParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2 && update.isFinalityUpdate && update.isSyncCommitteeUpdate
82
+ );
83
+ }
84
+
85
+ export function toLightClientUpdateSummary(update: LightClientUpdate): LightClientUpdateSummary {
86
+ return {
87
+ activeParticipants: sumBits(update.syncAggregate.syncCommitteeBits),
88
+ attestedHeaderSlot: update.attestedHeader.beacon.slot,
89
+ signatureSlot: update.signatureSlot,
90
+ finalizedHeaderSlot: update.finalizedHeader.beacon.slot,
91
+ isSyncCommitteeUpdate: isSyncCommitteeUpdate(update),
92
+ isFinalityUpdate: isFinalityUpdate(update),
93
+ };
94
+ }