@lodestar/state-transition 1.43.0-dev.bc569affb9 → 1.43.0-dev.c98da75ec7
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/block/processConsolidationRequest.d.ts.map +1 -1
- package/lib/block/processConsolidationRequest.js +2 -1
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDepositRequest.d.ts +3 -11
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js +27 -35
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts +2 -2
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
- package/lib/block/processParentExecutionPayload.js +7 -6
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +4 -6
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.js +3 -3
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/epoch/processPendingDeposits.d.ts.map +1 -1
- package/lib/epoch/processPendingDeposits.js +4 -2
- package/lib/epoch/processPendingDeposits.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts +22 -0
- package/lib/lightClient/spec/index.d.ts.map +1 -0
- package/lib/lightClient/spec/index.js +58 -0
- package/lib/lightClient/spec/index.js.map +1 -0
- package/lib/lightClient/spec/isBetterUpdate.d.ts +23 -0
- package/lib/lightClient/spec/isBetterUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/isBetterUpdate.js +66 -0
- package/lib/lightClient/spec/isBetterUpdate.js.map +1 -0
- package/lib/lightClient/spec/processLightClientUpdate.d.ts +12 -0
- package/lib/lightClient/spec/processLightClientUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/processLightClientUpdate.js +80 -0
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -0
- package/lib/lightClient/spec/store.d.ts +45 -0
- package/lib/lightClient/spec/store.d.ts.map +1 -0
- package/lib/lightClient/spec/store.js +56 -0
- package/lib/lightClient/spec/store.js.map +1 -0
- package/lib/lightClient/spec/utils.d.ts +47 -0
- package/lib/lightClient/spec/utils.d.ts.map +1 -0
- package/lib/lightClient/spec/utils.js +197 -0
- package/lib/lightClient/spec/utils.js.map +1 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts +4 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.js +22 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -0
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts +5 -0
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/validateLightClientUpdate.js +88 -0
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -0
- package/lib/signatureSets/index.d.ts +1 -0
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +1 -0
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/proposerPreferences.d.ts +4 -0
- package/lib/signatureSets/proposerPreferences.d.ts.map +1 -0
- package/lib/signatureSets/proposerPreferences.js +8 -0
- package/lib/signatureSets/proposerPreferences.js.map +1 -0
- package/lib/slot/upgradeStateToElectra.d.ts.map +1 -1
- package/lib/slot/upgradeStateToElectra.js +2 -2
- package/lib/slot/upgradeStateToElectra.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +33 -28
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +14 -5
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +40 -11
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +7 -5
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/util/epoch.d.ts.map +1 -1
- package/lib/util/epoch.js +6 -4
- package/lib/util/epoch.js.map +1 -1
- package/lib/util/gloas.d.ts +0 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +0 -4
- package/lib/util/gloas.js.map +1 -1
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -0
- package/lib/util/index.js.map +1 -1
- package/lib/util/loadState/loadState.js +4 -4
- package/lib/util/loadState/loadState.js.map +1 -1
- package/lib/util/pendingDepositsLookup.d.ts +40 -0
- package/lib/util/pendingDepositsLookup.d.ts.map +1 -0
- package/lib/util/pendingDepositsLookup.js +84 -0
- package/lib/util/pendingDepositsLookup.js.map +1 -0
- package/lib/util/validator.d.ts +14 -2
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +24 -2
- package/lib/util/validator.js.map +1 -1
- package/package.json +13 -8
- package/src/block/processConsolidationRequest.ts +2 -1
- package/src/block/processDepositRequest.ts +29 -47
- package/src/block/processParentExecutionPayload.ts +7 -6
- package/src/block/processWithdrawals.ts +6 -6
- package/src/cache/epochCache.ts +3 -3
- package/src/epoch/processPendingDeposits.ts +5 -2
- package/src/lightClient/spec/index.ts +101 -0
- package/src/lightClient/spec/isBetterUpdate.ts +94 -0
- package/src/lightClient/spec/processLightClientUpdate.ts +119 -0
- package/src/lightClient/spec/store.ts +106 -0
- package/src/lightClient/spec/utils.ts +317 -0
- package/src/lightClient/spec/validateLightClientBootstrap.ts +39 -0
- package/src/lightClient/spec/validateLightClientUpdate.ts +145 -0
- package/src/signatureSets/index.ts +1 -0
- package/src/signatureSets/proposerPreferences.ts +12 -0
- package/src/slot/upgradeStateToElectra.ts +4 -2
- package/src/slot/upgradeStateToGloas.ts +41 -44
- package/src/stateView/beaconStateView.ts +43 -12
- package/src/stateView/interface.ts +7 -5
- package/src/util/epoch.ts +13 -4
- package/src/util/gloas.ts +0 -5
- package/src/util/index.ts +1 -0
- package/src/util/loadState/loadState.ts +4 -4
- package/src/util/pendingDepositsLookup.ts +105 -0
- package/src/util/validator.ts +42 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { UPDATE_TIMEOUT } from "@lodestar/params";
|
|
2
|
+
import { computeSyncPeriodAtSlot } from "../../util/epoch.js";
|
|
3
|
+
import { getSyncCommitteeAtPeriod, processLightClientUpdate, } from "./processLightClientUpdate.js";
|
|
4
|
+
import { LightClientStore } from "./store.js";
|
|
5
|
+
import { ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroFinalityBranch, getZeroSyncCommitteeBranch } from "./utils.js";
|
|
6
|
+
export { isBetterUpdate, toLightClientUpdateSummary } from "./isBetterUpdate.js";
|
|
7
|
+
export { getSyncCommitteeAtPeriod, isSafeLightClientUpdate, processLightClientUpdate, } from "./processLightClientUpdate.js";
|
|
8
|
+
export { LightClientStore, } from "./store.js";
|
|
9
|
+
export { getSafetyThreshold, isFinalityUpdate, isSyncCommitteeUpdate, isValidLightClientHeader, normalizeMerkleBranch, upgradeLightClientFinalityUpdate, upgradeLightClientHeader, upgradeLightClientOptimisticUpdate, upgradeLightClientStore, upgradeLightClientUpdate, } from "./utils.js";
|
|
10
|
+
export { validateLightClientBootstrap } from "./validateLightClientBootstrap.js";
|
|
11
|
+
export { validateLightClientUpdate } from "./validateLightClientUpdate.js";
|
|
12
|
+
export class LightclientSpec {
|
|
13
|
+
opts;
|
|
14
|
+
store;
|
|
15
|
+
config;
|
|
16
|
+
constructor(config, opts, bootstrap) {
|
|
17
|
+
this.opts = opts;
|
|
18
|
+
this.store = new LightClientStore(config, bootstrap, opts);
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
onUpdate(currentSlot, update) {
|
|
22
|
+
processLightClientUpdate(this.config, this.store, currentSlot, this.opts, update);
|
|
23
|
+
}
|
|
24
|
+
onFinalityUpdate(currentSlot, finalityUpdate) {
|
|
25
|
+
this.onUpdate(currentSlot, {
|
|
26
|
+
attestedHeader: finalityUpdate.attestedHeader,
|
|
27
|
+
nextSyncCommittee: ZERO_SYNC_COMMITTEE,
|
|
28
|
+
nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(finalityUpdate.signatureSlot)),
|
|
29
|
+
finalizedHeader: finalityUpdate.finalizedHeader,
|
|
30
|
+
finalityBranch: finalityUpdate.finalityBranch,
|
|
31
|
+
syncAggregate: finalityUpdate.syncAggregate,
|
|
32
|
+
signatureSlot: finalityUpdate.signatureSlot,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
onOptimisticUpdate(currentSlot, optimisticUpdate) {
|
|
36
|
+
this.onUpdate(currentSlot, {
|
|
37
|
+
attestedHeader: optimisticUpdate.attestedHeader,
|
|
38
|
+
nextSyncCommittee: ZERO_SYNC_COMMITTEE,
|
|
39
|
+
nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(optimisticUpdate.signatureSlot)),
|
|
40
|
+
finalizedHeader: { beacon: ZERO_HEADER },
|
|
41
|
+
finalityBranch: getZeroFinalityBranch(this.config.getForkName(optimisticUpdate.signatureSlot)),
|
|
42
|
+
syncAggregate: optimisticUpdate.syncAggregate,
|
|
43
|
+
signatureSlot: optimisticUpdate.signatureSlot,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
forceUpdate(currentSlot) {
|
|
47
|
+
for (const bestValidUpdate of this.store.bestValidUpdates.values()) {
|
|
48
|
+
if (currentSlot > bestValidUpdate.update.finalizedHeader.beacon.slot + UPDATE_TIMEOUT) {
|
|
49
|
+
const updatePeriod = computeSyncPeriodAtSlot(bestValidUpdate.update.signatureSlot);
|
|
50
|
+
// Simulate process_light_client_store_force_update() by forcing to apply a bestValidUpdate
|
|
51
|
+
// https://github.com/ethereum/consensus-specs/blob/a57e15636013eeba3610ff3ade41781dba1bb0cd/specs/altair/light-client/sync-protocol.md?plain=1#L394
|
|
52
|
+
// Call for `updatePeriod + 1` to force the update at `update.signatureSlot` to be applied
|
|
53
|
+
getSyncCommitteeAtPeriod(this.store, updatePeriod + 1, this.opts);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lightClient/spec/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { LightClientUpdate, Slot } from "@lodestar/types";
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper type for `isBetterUpdate()` so we can apply its logic without requiring the full LightClientUpdate type.
|
|
4
|
+
*/
|
|
5
|
+
export type LightClientUpdateSummary = {
|
|
6
|
+
activeParticipants: number;
|
|
7
|
+
attestedHeaderSlot: Slot;
|
|
8
|
+
signatureSlot: Slot;
|
|
9
|
+
finalizedHeaderSlot: Slot;
|
|
10
|
+
/** `if update.next_sync_committee_branch != [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]` */
|
|
11
|
+
isSyncCommitteeUpdate: boolean;
|
|
12
|
+
/** `if update.finality_branch != [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))]` */
|
|
13
|
+
isFinalityUpdate: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Returns the update with more bits. On ties, prevUpdate is the better
|
|
17
|
+
*
|
|
18
|
+
* https://github.com/ethereum/consensus-specs/blob/be3c774069e16e89145660be511c1b183056017e/specs/altair/light-client/sync-protocol.md#is_better_update
|
|
19
|
+
*/
|
|
20
|
+
export declare function isBetterUpdate(newUpdate: LightClientUpdateSummary, oldUpdate: LightClientUpdateSummary): boolean;
|
|
21
|
+
export declare function isSafeLightClientUpdate(update: LightClientUpdateSummary): boolean;
|
|
22
|
+
export declare function toLightClientUpdateSummary(update: LightClientUpdate): LightClientUpdateSummary;
|
|
23
|
+
//# sourceMappingURL=isBetterUpdate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBetterUpdate.d.ts","sourceRoot":"","sources":["../../../src/lightClient/spec/isBetterUpdate.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,iBAAiB,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAIxD;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,IAAI,CAAC;IACzB,aAAa,EAAE,IAAI,CAAC;IACpB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,iHAAiH;IACjH,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iGAAiG;IACjG,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,wBAAwB,EAAE,SAAS,EAAE,wBAAwB,GAAG,OAAO,CAoDhH;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAIjF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,wBAAwB,CAS9F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { SYNC_COMMITTEE_SIZE } from "@lodestar/params";
|
|
2
|
+
import { computeSyncPeriodAtSlot } from "../../util/epoch.js";
|
|
3
|
+
import { isFinalityUpdate, isSyncCommitteeUpdate, sumBits } from "./utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Returns the update with more bits. On ties, prevUpdate is the better
|
|
6
|
+
*
|
|
7
|
+
* https://github.com/ethereum/consensus-specs/blob/be3c774069e16e89145660be511c1b183056017e/specs/altair/light-client/sync-protocol.md#is_better_update
|
|
8
|
+
*/
|
|
9
|
+
export function isBetterUpdate(newUpdate, oldUpdate) {
|
|
10
|
+
// Compare supermajority (> 2/3) sync committee participation
|
|
11
|
+
const newNumActiveParticipants = newUpdate.activeParticipants;
|
|
12
|
+
const oldNumActiveParticipants = oldUpdate.activeParticipants;
|
|
13
|
+
const newHasSupermajority = newNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2;
|
|
14
|
+
const oldHasSupermajority = oldNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2;
|
|
15
|
+
if (newHasSupermajority !== oldHasSupermajority) {
|
|
16
|
+
return newHasSupermajority;
|
|
17
|
+
}
|
|
18
|
+
if (!newHasSupermajority && newNumActiveParticipants !== oldNumActiveParticipants) {
|
|
19
|
+
return newNumActiveParticipants > oldNumActiveParticipants;
|
|
20
|
+
}
|
|
21
|
+
// Compare presence of relevant sync committee
|
|
22
|
+
const newHasRelevantSyncCommittee = newUpdate.isSyncCommitteeUpdate &&
|
|
23
|
+
computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.signatureSlot);
|
|
24
|
+
const oldHasRelevantSyncCommittee = oldUpdate.isSyncCommitteeUpdate &&
|
|
25
|
+
computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.signatureSlot);
|
|
26
|
+
if (newHasRelevantSyncCommittee !== oldHasRelevantSyncCommittee) {
|
|
27
|
+
return newHasRelevantSyncCommittee;
|
|
28
|
+
}
|
|
29
|
+
// Compare indication of any finality
|
|
30
|
+
const newHasFinality = newUpdate.isFinalityUpdate;
|
|
31
|
+
const oldHasFinality = oldUpdate.isFinalityUpdate;
|
|
32
|
+
if (newHasFinality !== oldHasFinality) {
|
|
33
|
+
return newHasFinality;
|
|
34
|
+
}
|
|
35
|
+
// Compare sync committee finality
|
|
36
|
+
if (newHasFinality) {
|
|
37
|
+
const newHasSyncCommitteeFinality = computeSyncPeriodAtSlot(newUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot);
|
|
38
|
+
const oldHasSyncCommitteeFinality = computeSyncPeriodAtSlot(oldUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot);
|
|
39
|
+
if (newHasSyncCommitteeFinality !== oldHasSyncCommitteeFinality) {
|
|
40
|
+
return newHasSyncCommitteeFinality;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Tiebreaker 1: Sync committee participation beyond supermajority
|
|
44
|
+
if (newNumActiveParticipants !== oldNumActiveParticipants) {
|
|
45
|
+
return newNumActiveParticipants > oldNumActiveParticipants;
|
|
46
|
+
}
|
|
47
|
+
// Tiebreaker 2: Prefer older data (fewer changes to best)
|
|
48
|
+
if (newUpdate.attestedHeaderSlot !== oldUpdate.attestedHeaderSlot) {
|
|
49
|
+
return newUpdate.attestedHeaderSlot < oldUpdate.attestedHeaderSlot;
|
|
50
|
+
}
|
|
51
|
+
return newUpdate.signatureSlot < oldUpdate.signatureSlot;
|
|
52
|
+
}
|
|
53
|
+
export function isSafeLightClientUpdate(update) {
|
|
54
|
+
return (update.activeParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2 && update.isFinalityUpdate && update.isSyncCommitteeUpdate);
|
|
55
|
+
}
|
|
56
|
+
export function toLightClientUpdateSummary(update) {
|
|
57
|
+
return {
|
|
58
|
+
activeParticipants: sumBits(update.syncAggregate.syncCommitteeBits),
|
|
59
|
+
attestedHeaderSlot: update.attestedHeader.beacon.slot,
|
|
60
|
+
signatureSlot: update.signatureSlot,
|
|
61
|
+
finalizedHeaderSlot: update.finalizedHeader.beacon.slot,
|
|
62
|
+
isSyncCommitteeUpdate: isSyncCommitteeUpdate(update),
|
|
63
|
+
isFinalityUpdate: isFinalityUpdate(update),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=isBetterUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBetterUpdate.js","sourceRoot":"","sources":["../../../src/lightClient/spec/isBetterUpdate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
2
|
+
import { LightClientUpdate, Slot, SyncPeriod } from "@lodestar/types";
|
|
3
|
+
import { LightClientUpdateSummary } from "./isBetterUpdate.js";
|
|
4
|
+
import { type ILightClientStore, type SyncCommitteeFast } from "./store.js";
|
|
5
|
+
export interface ProcessUpdateOpts {
|
|
6
|
+
allowForcedUpdates?: boolean;
|
|
7
|
+
updateHeadersOnForcedUpdate?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function processLightClientUpdate(config: ChainForkConfig, store: ILightClientStore, currentSlot: Slot, opts: ProcessUpdateOpts, update: LightClientUpdate): void;
|
|
10
|
+
export declare function getSyncCommitteeAtPeriod(store: ILightClientStore, period: SyncPeriod, opts: ProcessUpdateOpts): SyncCommitteeFast;
|
|
11
|
+
export declare function isSafeLightClientUpdate(update: LightClientUpdateSummary): boolean;
|
|
12
|
+
//# sourceMappingURL=processLightClientUpdate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processLightClientUpdate.d.ts","sourceRoot":"","sources":["../../../src/lightClient/spec/processLightClientUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAGpE,OAAO,EAAC,wBAAwB,EAA6C,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAC,KAAK,iBAAiB,EAA0B,KAAK,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAIlG,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,IAAI,EACjB,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,iBAAiB,GACxB,IAAI,CA8CN;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,iBAAiB,GACtB,iBAAiB,CAuCnB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAIjF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { SYNC_COMMITTEE_SIZE } from "@lodestar/params";
|
|
2
|
+
import { pruneSetToMax } from "@lodestar/utils";
|
|
3
|
+
import { computeSyncPeriodAtSlot } from "../../util/epoch.js";
|
|
4
|
+
import { isBetterUpdate, toLightClientUpdateSummary } from "./isBetterUpdate.js";
|
|
5
|
+
import { MAX_SYNC_PERIODS_CACHE } from "./store.js";
|
|
6
|
+
import { deserializeSyncCommittee, getSafetyThreshold, isSyncCommitteeUpdate, sumBits } from "./utils.js";
|
|
7
|
+
import { validateLightClientUpdate } from "./validateLightClientUpdate.js";
|
|
8
|
+
export function processLightClientUpdate(config, store, currentSlot, opts, update) {
|
|
9
|
+
if (update.signatureSlot > currentSlot) {
|
|
10
|
+
throw Error(`update slot ${update.signatureSlot} must not be in the future, current slot ${currentSlot}`);
|
|
11
|
+
}
|
|
12
|
+
const updateSignaturePeriod = computeSyncPeriodAtSlot(update.signatureSlot);
|
|
13
|
+
// TODO: Consider attempting to retrieve LightClientUpdate from transport if missing
|
|
14
|
+
// Note: store.getSyncCommitteeAtPeriod() may advance store
|
|
15
|
+
const syncCommittee = getSyncCommitteeAtPeriod(store, updateSignaturePeriod, opts);
|
|
16
|
+
validateLightClientUpdate(config, store, update, syncCommittee);
|
|
17
|
+
// Track the maximum number of active participants in the committee signatures
|
|
18
|
+
const syncCommitteeTrueBits = sumBits(update.syncAggregate.syncCommitteeBits);
|
|
19
|
+
store.setActiveParticipants(updateSignaturePeriod, syncCommitteeTrueBits);
|
|
20
|
+
// Update the optimistic header
|
|
21
|
+
if (syncCommitteeTrueBits > getSafetyThreshold(store.getMaxActiveParticipants(updateSignaturePeriod)) &&
|
|
22
|
+
update.attestedHeader.beacon.slot > store.optimisticHeader.beacon.slot) {
|
|
23
|
+
store.optimisticHeader = update.attestedHeader;
|
|
24
|
+
}
|
|
25
|
+
// Update finalized header
|
|
26
|
+
if (syncCommitteeTrueBits * 3 >= SYNC_COMMITTEE_SIZE * 2 &&
|
|
27
|
+
update.finalizedHeader.beacon.slot > store.finalizedHeader.beacon.slot) {
|
|
28
|
+
store.finalizedHeader = update.finalizedHeader;
|
|
29
|
+
if (store.finalizedHeader.beacon.slot > store.optimisticHeader.beacon.slot) {
|
|
30
|
+
store.optimisticHeader = store.finalizedHeader;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (isSyncCommitteeUpdate(update)) {
|
|
34
|
+
// Update the best update in case we have to force-update to it if the timeout elapses
|
|
35
|
+
const bestValidUpdate = store.bestValidUpdates.get(updateSignaturePeriod);
|
|
36
|
+
const updateSummary = toLightClientUpdateSummary(update);
|
|
37
|
+
if (!bestValidUpdate || isBetterUpdate(updateSummary, bestValidUpdate.summary)) {
|
|
38
|
+
store.bestValidUpdates.set(updateSignaturePeriod, { update, summary: updateSummary });
|
|
39
|
+
pruneSetToMax(store.bestValidUpdates, MAX_SYNC_PERIODS_CACHE);
|
|
40
|
+
}
|
|
41
|
+
// Note: defer update next sync committee to a future getSyncCommitteeAtPeriod() call
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function getSyncCommitteeAtPeriod(store, period, opts) {
|
|
45
|
+
const syncCommittee = store.syncCommittees.get(period);
|
|
46
|
+
if (syncCommittee) {
|
|
47
|
+
return syncCommittee;
|
|
48
|
+
}
|
|
49
|
+
const bestValidUpdate = store.bestValidUpdates.get(period - 1);
|
|
50
|
+
if (bestValidUpdate && (isSafeLightClientUpdate(bestValidUpdate.summary) || opts.allowForcedUpdates)) {
|
|
51
|
+
const { update } = bestValidUpdate;
|
|
52
|
+
const syncCommittee = deserializeSyncCommittee(update.nextSyncCommittee);
|
|
53
|
+
store.syncCommittees.set(period, syncCommittee);
|
|
54
|
+
pruneSetToMax(store.syncCommittees, MAX_SYNC_PERIODS_CACHE);
|
|
55
|
+
store.bestValidUpdates.delete(period - 1);
|
|
56
|
+
if (opts.updateHeadersOnForcedUpdate) {
|
|
57
|
+
// From https://github.com/ethereum/consensus-specs/blob/a57e15636013eeba3610ff3ade41781dba1bb0cd/specs/altair/light-client/sync-protocol.md?plain=1#L403
|
|
58
|
+
if (update.finalizedHeader.beacon.slot <= store.finalizedHeader.beacon.slot) {
|
|
59
|
+
update.finalizedHeader = update.attestedHeader;
|
|
60
|
+
}
|
|
61
|
+
// From https://github.com/ethereum/consensus-specs/blob/a57e15636013eeba3610ff3ade41781dba1bb0cd/specs/altair/light-client/sync-protocol.md?plain=1#L374
|
|
62
|
+
if (update.finalizedHeader.beacon.slot > store.finalizedHeader.beacon.slot) {
|
|
63
|
+
store.finalizedHeader = update.finalizedHeader;
|
|
64
|
+
}
|
|
65
|
+
if (store.finalizedHeader.beacon.slot > store.optimisticHeader.beacon.slot) {
|
|
66
|
+
store.optimisticHeader = store.finalizedHeader;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return syncCommittee;
|
|
70
|
+
}
|
|
71
|
+
const availableSyncCommittees = Array.from(store.syncCommittees.keys());
|
|
72
|
+
const availableBestValidUpdates = Array.from(store.bestValidUpdates.keys());
|
|
73
|
+
throw Error(`No SyncCommittee for period ${period}` +
|
|
74
|
+
` available syncCommittees ${JSON.stringify(availableSyncCommittees)}` +
|
|
75
|
+
` available bestValidUpdates ${JSON.stringify(availableBestValidUpdates)}`);
|
|
76
|
+
}
|
|
77
|
+
export function isSafeLightClientUpdate(update) {
|
|
78
|
+
return (update.activeParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2 && update.isFinalityUpdate && update.isSyncCommitteeUpdate);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=processLightClientUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processLightClientUpdate.js","sourceRoot":"","sources":["../../../src/lightClient/spec/processLightClientUpdate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PublicKey } from "@chainsafe/blst";
|
|
2
|
+
import { BeaconConfig } from "@lodestar/config";
|
|
3
|
+
import { LightClientBootstrap, LightClientHeader, LightClientUpdate, SyncPeriod } from "@lodestar/types";
|
|
4
|
+
import type { LightClientUpdateSummary } from "./isBetterUpdate.js";
|
|
5
|
+
export declare const MAX_SYNC_PERIODS_CACHE = 2;
|
|
6
|
+
export interface ILightClientStore {
|
|
7
|
+
readonly config: BeaconConfig;
|
|
8
|
+
/** Map of trusted SyncCommittee to be used for sig validation */
|
|
9
|
+
readonly syncCommittees: Map<SyncPeriod, SyncCommitteeFast>;
|
|
10
|
+
/** Map of best valid updates */
|
|
11
|
+
readonly bestValidUpdates: Map<SyncPeriod, LightClientUpdateWithSummary>;
|
|
12
|
+
getMaxActiveParticipants(period: SyncPeriod): number;
|
|
13
|
+
setActiveParticipants(period: SyncPeriod, activeParticipants: number): void;
|
|
14
|
+
finalizedHeader: LightClientHeader;
|
|
15
|
+
optimisticHeader: LightClientHeader;
|
|
16
|
+
}
|
|
17
|
+
export interface LightClientStoreEvents {
|
|
18
|
+
onSetFinalizedHeader?: (header: LightClientHeader) => void;
|
|
19
|
+
onSetOptimisticHeader?: (header: LightClientHeader) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare class LightClientStore implements ILightClientStore {
|
|
22
|
+
readonly config: BeaconConfig;
|
|
23
|
+
private readonly events;
|
|
24
|
+
readonly syncCommittees: Map<number, SyncCommitteeFast>;
|
|
25
|
+
readonly bestValidUpdates: Map<number, LightClientUpdateWithSummary>;
|
|
26
|
+
private finalizedHeaderValue;
|
|
27
|
+
private optimisticHeaderValue;
|
|
28
|
+
private readonly maxActiveParticipants;
|
|
29
|
+
constructor(config: BeaconConfig, bootstrap: LightClientBootstrap, events: LightClientStoreEvents);
|
|
30
|
+
get finalizedHeader(): LightClientHeader;
|
|
31
|
+
set finalizedHeader(value: LightClientHeader);
|
|
32
|
+
get optimisticHeader(): LightClientHeader;
|
|
33
|
+
set optimisticHeader(value: LightClientHeader);
|
|
34
|
+
getMaxActiveParticipants(period: SyncPeriod): number;
|
|
35
|
+
setActiveParticipants(period: SyncPeriod, activeParticipants: number): void;
|
|
36
|
+
}
|
|
37
|
+
export type SyncCommitteeFast = {
|
|
38
|
+
pubkeys: PublicKey[];
|
|
39
|
+
aggregatePubkey: PublicKey;
|
|
40
|
+
};
|
|
41
|
+
export type LightClientUpdateWithSummary = {
|
|
42
|
+
update: LightClientUpdate;
|
|
43
|
+
summary: LightClientUpdateSummary;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lightClient/spec/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAC,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAEvG,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,qBAAqB,CAAC;AAGlE,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAE9B,iEAAiE;IACjE,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IAC5D,gCAAgC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;IAEzE,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IACrD,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5E,eAAe,EAAE,iBAAiB,CAAC;IAGnC,gBAAgB,EAAE,iBAAiB,CAAC;CACrC;AAED,MAAM,WAAW,sBAAsB;IACrC,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3D,qBAAqB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC7D;AAED,qBAAa,gBAAiB,YAAW,iBAAiB;IAUtD,QAAQ,CAAC,MAAM,EAAE,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAXzB,QAAQ,CAAC,cAAc,iCAA4C;IACnE,QAAQ,CAAC,gBAAgB,4CAAuD;IAEhF,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,qBAAqB,CAAoB;IAEjD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAiC;IAEvE,YACW,MAAM,EAAE,YAAY,EAC7B,SAAS,EAAE,oBAAoB,EACd,MAAM,EAAE,sBAAsB,EAMhD;IAED,IAAI,eAAe,IAAI,iBAAiB,CAEvC;IAED,IAAI,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAG3C;IAED,IAAI,gBAAgB,IAAI,iBAAiB,CAExC;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAG5C;IAED,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAKnD;IAED,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAY1E;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,eAAe,EAAE,SAAS,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,wBAAwB,CAAC;CACnC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { computeSyncPeriodAtSlot } from "../../util/epoch.js";
|
|
2
|
+
import { deserializeSyncCommittee } from "./utils.js";
|
|
3
|
+
export const MAX_SYNC_PERIODS_CACHE = 2;
|
|
4
|
+
export class LightClientStore {
|
|
5
|
+
config;
|
|
6
|
+
events;
|
|
7
|
+
syncCommittees = new Map();
|
|
8
|
+
bestValidUpdates = new Map();
|
|
9
|
+
finalizedHeaderValue;
|
|
10
|
+
optimisticHeaderValue;
|
|
11
|
+
maxActiveParticipants = new Map();
|
|
12
|
+
constructor(config, bootstrap, events) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.events = events;
|
|
15
|
+
const bootstrapPeriod = computeSyncPeriodAtSlot(bootstrap.header.beacon.slot);
|
|
16
|
+
this.syncCommittees.set(bootstrapPeriod, deserializeSyncCommittee(bootstrap.currentSyncCommittee));
|
|
17
|
+
this.finalizedHeaderValue = bootstrap.header;
|
|
18
|
+
this.optimisticHeaderValue = bootstrap.header;
|
|
19
|
+
}
|
|
20
|
+
get finalizedHeader() {
|
|
21
|
+
return this.finalizedHeaderValue;
|
|
22
|
+
}
|
|
23
|
+
set finalizedHeader(value) {
|
|
24
|
+
this.finalizedHeaderValue = value;
|
|
25
|
+
this.events.onSetFinalizedHeader?.(value);
|
|
26
|
+
}
|
|
27
|
+
get optimisticHeader() {
|
|
28
|
+
return this.optimisticHeaderValue;
|
|
29
|
+
}
|
|
30
|
+
set optimisticHeader(value) {
|
|
31
|
+
this.optimisticHeaderValue = value;
|
|
32
|
+
this.events.onSetOptimisticHeader?.(value);
|
|
33
|
+
}
|
|
34
|
+
getMaxActiveParticipants(period) {
|
|
35
|
+
const currMaxParticipants = this.maxActiveParticipants.get(period) ?? 0;
|
|
36
|
+
const prevMaxParticipants = this.maxActiveParticipants.get(period - 1) ?? 0;
|
|
37
|
+
return Math.max(currMaxParticipants, prevMaxParticipants);
|
|
38
|
+
}
|
|
39
|
+
setActiveParticipants(period, activeParticipants) {
|
|
40
|
+
const maxActiveParticipants = this.maxActiveParticipants.get(period) ?? 0;
|
|
41
|
+
if (activeParticipants > maxActiveParticipants) {
|
|
42
|
+
this.maxActiveParticipants.set(period, activeParticipants);
|
|
43
|
+
}
|
|
44
|
+
// Prune old entries
|
|
45
|
+
for (const key of this.maxActiveParticipants.keys()) {
|
|
46
|
+
if (key < period - MAX_SYNC_PERIODS_CACHE) {
|
|
47
|
+
this.maxActiveParticipants.delete(key);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// === storePeriod ? store.currentSyncCommittee : store.nextSyncCommittee;
|
|
53
|
+
// if (!syncCommittee) {
|
|
54
|
+
// throw Error(`syncCommittee not available for signature period ${updateSignaturePeriod}`);
|
|
55
|
+
// }
|
|
56
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/lightClient/spec/store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAEpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAyBxC,MAAM,OAAO,gBAAgB;IAUhB,MAAM;IAEE,MAAM;IAXhB,cAAc,GAAG,IAAI,GAAG,EAAiC,CAAC;IAC1D,gBAAgB,GAAG,IAAI,GAAG,EAA4C,CAAC;IAExE,oBAAoB,CAAoB;IACxC,qBAAqB,CAAoB;IAEhC,qBAAqB,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEvE,YACW,MAAoB,EAC7B,SAA+B,EACd,MAA8B,EAC/C;sBAHS,MAAM;sBAEE,MAAM;QAEvB,MAAM,eAAe,GAAG,uBAAuB,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,eAAe,EAAE,wBAAwB,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACnG,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,MAAM,CAAC;QAC7C,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC,MAAM,CAAC;IAAA,CAC/C;IAED,IAAI,eAAe,GAAsB;QACvC,OAAO,IAAI,CAAC,oBAAoB,CAAC;IAAA,CAClC;IAED,IAAI,eAAe,CAAC,KAAwB,EAAE;QAC5C,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC,KAAK,CAAC,CAAC;IAAA,CAC3C;IAED,IAAI,gBAAgB,GAAsB;QACxC,OAAO,IAAI,CAAC,qBAAqB,CAAC;IAAA,CACnC;IAED,IAAI,gBAAgB,CAAC,KAAwB,EAAE;QAC7C,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC,CAAC;IAAA,CAC5C;IAED,wBAAwB,CAAC,MAAkB,EAAU;QACnD,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxE,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAE5E,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;IAAA,CAC3D;IAED,qBAAqB,CAAC,MAAkB,EAAE,kBAA0B,EAAQ;QAC1E,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1E,IAAI,kBAAkB,GAAG,qBAAqB,EAAE,CAAC;YAC/C,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QAC7D,CAAC;QAED,oBAAoB;QACpB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC;YACpD,IAAI,GAAG,GAAG,MAAM,GAAG,sBAAsB,EAAE,CAAC;gBAC1C,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IAAA,CACF;CACF;AAYD,0EAA0E;AAC1E,wBAAwB;AACxB,8FAA8F;AAC9F,IAAI"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BitArray } from "@chainsafe/ssz";
|
|
2
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
+
import { ForkName } from "@lodestar/params";
|
|
4
|
+
import { BeaconBlockHeader, LightClientFinalityUpdate, LightClientHeader, LightClientOptimisticUpdate, LightClientUpdate, Slot, SyncCommittee } from "@lodestar/types";
|
|
5
|
+
import type { LightClientStore, SyncCommitteeFast } from "./store.js";
|
|
6
|
+
export declare const GENESIS_SLOT = 0;
|
|
7
|
+
export declare const ZERO_HASH: Uint8Array<ArrayBuffer>;
|
|
8
|
+
export declare const ZERO_PUBKEY: Uint8Array<ArrayBuffer>;
|
|
9
|
+
export declare const ZERO_SYNC_COMMITTEE: import("@chainsafe/ssz").ValueOfFields<{
|
|
10
|
+
pubkeys: import("@chainsafe/ssz").VectorCompositeType<import("@chainsafe/ssz").ByteVectorType>;
|
|
11
|
+
aggregatePubkey: import("@chainsafe/ssz").ByteVectorType;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const ZERO_HEADER: import("@chainsafe/ssz").ValueOfFields<{
|
|
14
|
+
slot: import("@chainsafe/ssz").UintNumberType;
|
|
15
|
+
proposerIndex: import("@chainsafe/ssz").UintNumberType;
|
|
16
|
+
parentRoot: import("@chainsafe/ssz").ByteVectorType;
|
|
17
|
+
stateRoot: import("@chainsafe/ssz").ByteVectorType;
|
|
18
|
+
bodyRoot: import("@chainsafe/ssz").ByteVectorType;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function sumBits(bits: BitArray): number;
|
|
21
|
+
/**
|
|
22
|
+
* Util to guarantee that all bits have a corresponding pubkey.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getParticipantPubkeys<T>(pubkeys: T[], bits: BitArray): T[];
|
|
25
|
+
export declare function deserializeSyncCommittee(syncCommittee: SyncCommittee): SyncCommitteeFast;
|
|
26
|
+
export declare function serializeSyncCommittee(syncCommittee: SyncCommitteeFast): SyncCommittee;
|
|
27
|
+
export declare function getSafetyThreshold(maxActiveParticipants: number): number;
|
|
28
|
+
export declare function getZeroSyncCommitteeBranch(fork: ForkName): Uint8Array[];
|
|
29
|
+
export declare function getZeroFinalityBranch(fork: ForkName): Uint8Array[];
|
|
30
|
+
export declare function isSyncCommitteeUpdate(update: LightClientUpdate): boolean;
|
|
31
|
+
export declare function isFinalityUpdate(update: LightClientUpdate): boolean;
|
|
32
|
+
export declare function isZeroedHeader(header: BeaconBlockHeader): boolean;
|
|
33
|
+
export declare function isZeroedSyncCommittee(syncCommittee: SyncCommittee): boolean;
|
|
34
|
+
export declare function isValidMerkleBranch(leaf: Uint8Array, branch: Uint8Array[], depth: number, index: number, root: Uint8Array): boolean;
|
|
35
|
+
export declare function normalizeMerkleBranch(branch: Uint8Array[], depth: number): Uint8Array[];
|
|
36
|
+
export declare function upgradeLightClientHeader(config: ChainForkConfig, targetFork: ForkName, header: LightClientHeader): LightClientHeader;
|
|
37
|
+
export declare function isValidLightClientHeader(config: ChainForkConfig, header: LightClientHeader): boolean;
|
|
38
|
+
export declare function upgradeLightClientUpdate(config: ChainForkConfig, targetFork: ForkName, update: LightClientUpdate): LightClientUpdate;
|
|
39
|
+
export declare function upgradeLightClientFinalityUpdate(config: ChainForkConfig, targetFork: ForkName, finalityUpdate: LightClientFinalityUpdate): LightClientFinalityUpdate;
|
|
40
|
+
export declare function upgradeLightClientOptimisticUpdate(config: ChainForkConfig, targetFork: ForkName, optimisticUpdate: LightClientOptimisticUpdate): LightClientOptimisticUpdate;
|
|
41
|
+
/**
|
|
42
|
+
* Currently this upgradation is not required because all processing is done based on the
|
|
43
|
+
* summary that the store generates and maintains. In case store needs to be saved to disk,
|
|
44
|
+
* this could be required depending on the format the store is saved to the disk
|
|
45
|
+
*/
|
|
46
|
+
export declare function upgradeLightClientStore(config: ChainForkConfig, targetFork: ForkName, store: LightClientStore, signatureSlot: Slot): LightClientStore;
|
|
47
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lightClient/spec/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAKL,QAAQ,EAKT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,IAAI,EACJ,aAAa,EAGd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAC,gBAAgB,EAAE,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAEpE,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,SAAS,yBAAqB,CAAC;AAC5C,eAAO,MAAM,WAAW,yBAAqB,CAAC;AAC9C,eAAO,MAAM,mBAAmB;;;EAA0C,CAAC;AAC3E,eAAO,MAAM,WAAW;;;;;;EAA8C,CAAC;AAIvE,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,CAAC,EAAE,CAG1E;AAUD,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,aAAa,GAAG,iBAAiB,CAKxF;AAED,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,iBAAiB,GAAG,aAAa,CAKtF;AAED,wBAAgB,kBAAkB,CAAC,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,EAAE,CAMvE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,EAAE,CAIlE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAOxE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAOnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAGjE;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAG3E;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,EAAE,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,UAAU,GACf,OAAO,CAMT;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAIvF;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CAiEnB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAqCpG;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CAanB;AAED,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,QAAQ,EACpB,cAAc,EAAE,yBAAyB,GACxC,yBAAyB,CAS3B;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,QAAQ,EACpB,gBAAgB,EAAE,2BAA2B,GAC5C,2BAA2B,CAI7B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,gBAAgB,EACvB,aAAa,EAAE,IAAI,GAClB,gBAAgB,CAelB"}
|