@lodestar/state-transition 1.37.0 → 1.38.0-dev.255e56fb68
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/index.d.ts +4 -1
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +19 -8
- package/lib/block/index.js.map +1 -1
- package/lib/block/isValidIndexedPayloadAttestation.d.ts +4 -0
- package/lib/block/isValidIndexedPayloadAttestation.d.ts.map +1 -0
- package/lib/block/isValidIndexedPayloadAttestation.js +14 -0
- package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -0
- package/lib/block/processAttestationPhase0.d.ts.map +1 -1
- package/lib/block/processAttestationPhase0.js +6 -1
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttestationsAltair.d.ts +3 -3
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +46 -4
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processConsolidationRequest.d.ts +3 -2
- package/lib/block/processConsolidationRequest.d.ts.map +1 -1
- package/lib/block/processConsolidationRequest.js +2 -2
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDepositRequest.d.ts +2 -2
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts +5 -0
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -0
- package/lib/block/processExecutionPayloadBid.js +89 -0
- package/lib/block/processExecutionPayloadBid.js.map +1 -0
- package/lib/block/processExecutionPayloadEnvelope.d.ts +4 -0
- package/lib/block/processExecutionPayloadEnvelope.d.ts.map +1 -0
- package/lib/block/processExecutionPayloadEnvelope.js +118 -0
- package/lib/block/processExecutionPayloadEnvelope.js.map +1 -0
- package/lib/block/processOperations.d.ts.map +1 -1
- package/lib/block/processOperations.js +8 -2
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processPayloadAttestation.d.ts +4 -0
- package/lib/block/processPayloadAttestation.d.ts.map +1 -0
- package/lib/block/processPayloadAttestation.js +16 -0
- package/lib/block/processPayloadAttestation.js.map +1 -0
- package/lib/block/processProposerSlashing.d.ts.map +1 -1
- package/lib/block/processProposerSlashing.js +16 -1
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processVoluntaryExit.js +1 -1
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/block/processWithdrawalRequest.d.ts +2 -2
- package/lib/block/processWithdrawalRequest.d.ts.map +1 -1
- package/lib/block/processWithdrawalRequest.js +1 -1
- package/lib/block/processWithdrawalRequest.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts +4 -3
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +89 -19
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.d.ts +5 -1
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +34 -1
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/epoch/index.d.ts +4 -2
- package/lib/epoch/index.d.ts.map +1 -1
- package/lib/epoch/index.js +10 -1
- package/lib/epoch/index.js.map +1 -1
- package/lib/epoch/processBuilderPendingPayments.d.ts +6 -0
- package/lib/epoch/processBuilderPendingPayments.d.ts.map +1 -0
- package/lib/epoch/processBuilderPendingPayments.js +28 -0
- package/lib/epoch/processBuilderPendingPayments.js.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/signatureSets/index.d.ts +3 -2
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +3 -2
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/indexedAttestation.d.ts +1 -1
- package/lib/signatureSets/indexedAttestation.d.ts.map +1 -1
- package/lib/signatureSets/indexedAttestation.js +5 -3
- package/lib/signatureSets/indexedAttestation.js.map +1 -1
- package/lib/signatureSets/indexedPayloadAttestation.d.ts +6 -0
- package/lib/signatureSets/indexedPayloadAttestation.d.ts.map +1 -0
- package/lib/signatureSets/indexedPayloadAttestation.js +11 -0
- package/lib/signatureSets/indexedPayloadAttestation.js.map +1 -0
- package/lib/slot/index.d.ts +2 -1
- package/lib/slot/index.d.ts.map +1 -1
- package/lib/slot/index.js +6 -2
- package/lib/slot/index.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts +0 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +47 -5
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateTransition.js +4 -3
- package/lib/stateTransition.js.map +1 -1
- package/lib/util/electra.d.ts +5 -5
- package/lib/util/electra.d.ts.map +1 -1
- package/lib/util/electra.js +2 -1
- package/lib/util/electra.js.map +1 -1
- package/lib/util/epoch.d.ts +3 -3
- package/lib/util/epoch.d.ts.map +1 -1
- package/lib/util/epoch.js.map +1 -1
- package/lib/util/gloas.d.ts +11 -0
- package/lib/util/gloas.d.ts.map +1 -0
- package/lib/util/gloas.js +35 -0
- package/lib/util/gloas.js.map +1 -0
- package/lib/util/seed.d.ts +5 -1
- package/lib/util/seed.d.ts.map +1 -1
- package/lib/util/seed.js +33 -1
- package/lib/util/seed.js.map +1 -1
- package/lib/util/validator.d.ts +2 -2
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +14 -1
- package/lib/util/validator.js.map +1 -1
- package/package.json +6 -6
- package/src/block/index.ts +35 -14
- package/src/block/isValidIndexedPayloadAttestation.ts +23 -0
- package/src/block/processAttestationPhase0.ts +5 -1
- package/src/block/processAttestationsAltair.ts +62 -5
- package/src/block/processConsolidationRequest.ts +6 -5
- package/src/block/processDepositRequest.ts +5 -2
- package/src/block/processExecutionPayloadBid.ts +120 -0
- package/src/block/processExecutionPayloadEnvelope.ts +181 -0
- package/src/block/processOperations.ts +16 -4
- package/src/block/processPayloadAttestation.ts +25 -0
- package/src/block/processProposerSlashing.ts +24 -3
- package/src/block/processVoluntaryExit.ts +1 -1
- package/src/block/processWithdrawalRequest.ts +4 -4
- package/src/block/processWithdrawals.ts +118 -27
- package/src/cache/epochCache.ts +58 -1
- package/src/epoch/index.ts +12 -0
- package/src/epoch/processBuilderPendingPayments.ts +31 -0
- package/src/index.ts +2 -0
- package/src/signatureSets/index.ts +4 -2
- package/src/signatureSets/indexedAttestation.ts +8 -8
- package/src/signatureSets/indexedPayloadAttestation.ts +24 -0
- package/src/slot/index.ts +11 -3
- package/src/slot/upgradeStateToAltair.ts +2 -1
- package/src/slot/upgradeStateToGloas.ts +49 -5
- package/src/stateTransition.ts +4 -4
- package/src/util/electra.ts +15 -6
- package/src/util/epoch.ts +6 -3
- package/src/util/gloas.ts +58 -0
- package/src/util/seed.ts +57 -1
- package/src/util/validator.ts +21 -2
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.
|
|
14
|
+
"version": "1.38.0-dev.255e56fb68",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"@chainsafe/pubkey-index-map": "^3.0.0",
|
|
63
63
|
"@chainsafe/ssz": "^1.2.2",
|
|
64
64
|
"@chainsafe/swap-or-not-shuffle": "^1.2.1",
|
|
65
|
-
"@lodestar/config": "
|
|
66
|
-
"@lodestar/params": "
|
|
67
|
-
"@lodestar/types": "
|
|
68
|
-
"@lodestar/utils": "
|
|
65
|
+
"@lodestar/config": "1.38.0-dev.255e56fb68",
|
|
66
|
+
"@lodestar/params": "1.38.0-dev.255e56fb68",
|
|
67
|
+
"@lodestar/types": "1.38.0-dev.255e56fb68",
|
|
68
|
+
"@lodestar/utils": "1.38.0-dev.255e56fb68",
|
|
69
69
|
"bigint-buffer": "^1.1.5"
|
|
70
70
|
},
|
|
71
71
|
"keywords": [
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"beacon",
|
|
75
75
|
"blockchain"
|
|
76
76
|
],
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "a6f5bc4398f508565cd5cf856c0d6946571d5465"
|
|
78
78
|
}
|
package/src/block/index.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import {ForkSeq} from "@lodestar/params";
|
|
1
|
+
import {ForkPostGloas, ForkSeq} from "@lodestar/params";
|
|
2
2
|
import {BeaconBlock, BlindedBeaconBlock, altair, capella} from "@lodestar/types";
|
|
3
3
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CachedBeaconStateAllForks,
|
|
6
|
+
CachedBeaconStateBellatrix,
|
|
7
|
+
CachedBeaconStateCapella,
|
|
8
|
+
CachedBeaconStateGloas,
|
|
9
|
+
} from "../types.js";
|
|
5
10
|
import {getFullOrBlindedPayload, isExecutionEnabled} from "../util/execution.js";
|
|
6
11
|
import {BlockExternalData, DataAvailabilityStatus} from "./externalData.js";
|
|
7
12
|
import {processBlobKzgCommitments} from "./processBlobKzgCommitments.js";
|
|
8
13
|
import {processBlockHeader} from "./processBlockHeader.js";
|
|
9
14
|
import {processEth1Data} from "./processEth1Data.js";
|
|
10
15
|
import {processExecutionPayload} from "./processExecutionPayload.js";
|
|
16
|
+
import {processExecutionPayloadBid} from "./processExecutionPayloadBid.ts";
|
|
17
|
+
import {processExecutionPayloadEnvelope} from "./processExecutionPayloadEnvelope.ts";
|
|
11
18
|
import {processOperations} from "./processOperations.js";
|
|
19
|
+
import {processPayloadAttestation} from "./processPayloadAttestation.ts";
|
|
12
20
|
import {processRandao} from "./processRandao.js";
|
|
13
21
|
import {processSyncAggregate} from "./processSyncCommittee.js";
|
|
14
22
|
import {processWithdrawals} from "./processWithdrawals.js";
|
|
@@ -22,6 +30,9 @@ export {
|
|
|
22
30
|
processEth1Data,
|
|
23
31
|
processSyncAggregate,
|
|
24
32
|
processWithdrawals,
|
|
33
|
+
processExecutionPayloadBid,
|
|
34
|
+
processPayloadAttestation,
|
|
35
|
+
processExecutionPayloadEnvelope,
|
|
25
36
|
};
|
|
26
37
|
|
|
27
38
|
export * from "./externalData.js";
|
|
@@ -41,23 +52,33 @@ export function processBlock(
|
|
|
41
52
|
|
|
42
53
|
processBlockHeader(state, block);
|
|
43
54
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
if (fork >= ForkSeq.gloas) {
|
|
56
|
+
// After gloas, processWithdrawals does not take a payload parameter
|
|
57
|
+
processWithdrawals(fork, state as CachedBeaconStateGloas);
|
|
58
|
+
} else if (fork >= ForkSeq.capella) {
|
|
47
59
|
const fullOrBlindedPayload = getFullOrBlindedPayload(block);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
fullOrBlindedPayload as capella.FullOrBlindedExecutionPayload
|
|
55
|
-
);
|
|
56
|
-
}
|
|
60
|
+
processWithdrawals(
|
|
61
|
+
fork,
|
|
62
|
+
state as CachedBeaconStateCapella,
|
|
63
|
+
fullOrBlindedPayload as capella.FullOrBlindedExecutionPayload
|
|
64
|
+
);
|
|
65
|
+
}
|
|
57
66
|
|
|
67
|
+
// The call to the process_execution_payload must happen before the call to the process_randao as the former depends
|
|
68
|
+
// on the randao_mix computed with the reveal of the previous block.
|
|
69
|
+
// TODO GLOAS: We call processExecutionPayload somewhere else post-gloas
|
|
70
|
+
if (
|
|
71
|
+
fork >= ForkSeq.bellatrix &&
|
|
72
|
+
fork < ForkSeq.gloas &&
|
|
73
|
+
isExecutionEnabled(state as CachedBeaconStateBellatrix, block)
|
|
74
|
+
) {
|
|
58
75
|
processExecutionPayload(fork, state as CachedBeaconStateBellatrix, block.body, externalData);
|
|
59
76
|
}
|
|
60
77
|
|
|
78
|
+
if (fork >= ForkSeq.gloas) {
|
|
79
|
+
processExecutionPayloadBid(state as CachedBeaconStateGloas, block as BeaconBlock<ForkPostGloas>);
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
processRandao(state, block, verifySignatures);
|
|
62
83
|
processEth1Data(state, block.body.eth1Data);
|
|
63
84
|
processOperations(fork, state, block.body, opts, metrics);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {gloas} from "@lodestar/types";
|
|
2
|
+
import {getIndexedPayloadAttestationSignatureSet} from "../signatureSets/index.ts";
|
|
3
|
+
import {CachedBeaconStateGloas} from "../types.js";
|
|
4
|
+
import {verifySignatureSet} from "../util/index.ts";
|
|
5
|
+
|
|
6
|
+
export function isValidIndexedPayloadAttestation(
|
|
7
|
+
state: CachedBeaconStateGloas,
|
|
8
|
+
indexedPayloadAttestation: gloas.IndexedPayloadAttestation,
|
|
9
|
+
verifySignature: boolean
|
|
10
|
+
): boolean {
|
|
11
|
+
const indices = indexedPayloadAttestation.attestingIndices;
|
|
12
|
+
const isSorted = indices.every((val, i, arr) => i === 0 || arr[i - 1] <= val);
|
|
13
|
+
|
|
14
|
+
if (indices.length === 0 || !isSorted) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (verifySignature) {
|
|
19
|
+
return verifySignatureSet(getIndexedPayloadAttestationSignatureSet(state, indexedPayloadAttestation));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
@@ -86,7 +86,11 @@ export function validateAttestation(fork: ForkSeq, state: CachedBeaconStateAllFo
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (fork >= ForkSeq.electra) {
|
|
89
|
-
|
|
89
|
+
if (fork >= ForkSeq.gloas) {
|
|
90
|
+
assert.lt(data.index, 2, `AttestationData.index must be 0 or 1: index=${data.index}`);
|
|
91
|
+
} else {
|
|
92
|
+
assert.equal(data.index, 0, `AttestationData.index must be 0: index=${data.index}`);
|
|
93
|
+
}
|
|
90
94
|
const attestationElectra = attestation as electra.Attestation;
|
|
91
95
|
const committeeIndices = attestationElectra.committeeBits.getTrueBitIndexes();
|
|
92
96
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {byteArrayEquals} from "@chainsafe/ssz";
|
|
2
2
|
import {
|
|
3
|
+
EFFECTIVE_BALANCE_INCREMENT,
|
|
3
4
|
ForkSeq,
|
|
4
5
|
MIN_ATTESTATION_INCLUSION_DELAY,
|
|
5
6
|
PROPOSER_WEIGHT,
|
|
6
7
|
SLOTS_PER_EPOCH,
|
|
8
|
+
SLOTS_PER_HISTORICAL_ROOT,
|
|
7
9
|
TIMELY_HEAD_FLAG_INDEX,
|
|
8
10
|
TIMELY_HEAD_WEIGHT,
|
|
9
11
|
TIMELY_SOURCE_FLAG_INDEX,
|
|
@@ -16,7 +18,8 @@ import {Attestation, Epoch, phase0} from "@lodestar/types";
|
|
|
16
18
|
import {intSqrt} from "@lodestar/utils";
|
|
17
19
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
18
20
|
import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js";
|
|
19
|
-
import {CachedBeaconStateAltair} from "../types.js";
|
|
21
|
+
import {CachedBeaconStateAltair, CachedBeaconStateGloas} from "../types.js";
|
|
22
|
+
import {isAttestationSameSlot, isAttestationSameSlotRootCache} from "../util/gloas.ts";
|
|
20
23
|
import {increaseBalance, verifySignatureSet} from "../util/index.js";
|
|
21
24
|
import {RootCache} from "../util/rootCache.js";
|
|
22
25
|
import {checkpointToStr, isTimelyTarget, validateAttestation} from "./processAttestationPhase0.js";
|
|
@@ -31,7 +34,7 @@ const SLOTS_PER_EPOCH_SQRT = intSqrt(SLOTS_PER_EPOCH);
|
|
|
31
34
|
|
|
32
35
|
export function processAttestationsAltair(
|
|
33
36
|
fork: ForkSeq,
|
|
34
|
-
state: CachedBeaconStateAltair,
|
|
37
|
+
state: CachedBeaconStateAltair | CachedBeaconStateGloas,
|
|
35
38
|
attestations: Attestation[],
|
|
36
39
|
verifySignature = true,
|
|
37
40
|
metrics?: BeaconStateTransitionMetrics | null
|
|
@@ -46,6 +49,9 @@ export function processAttestationsAltair(
|
|
|
46
49
|
let proposerReward = 0;
|
|
47
50
|
let newSeenAttesters = 0;
|
|
48
51
|
let newSeenAttestersEffectiveBalance = 0;
|
|
52
|
+
|
|
53
|
+
const builderWeightMap: Map<number, number> = new Map();
|
|
54
|
+
|
|
49
55
|
for (const attestation of attestations) {
|
|
50
56
|
const data = attestation.data;
|
|
51
57
|
|
|
@@ -66,13 +72,16 @@ export function processAttestationsAltair(
|
|
|
66
72
|
|
|
67
73
|
const inCurrentEpoch = data.target.epoch === currentEpoch;
|
|
68
74
|
const epochParticipation = inCurrentEpoch ? state.currentEpochParticipation : state.previousEpochParticipation;
|
|
75
|
+
// Count how much additional weight added to current or previous epoch's builder pending payment (in ETH increment)
|
|
76
|
+
let paymentWeightToAdd = 0;
|
|
69
77
|
|
|
70
78
|
const flagsAttestation = getAttestationParticipationStatus(
|
|
71
79
|
fork,
|
|
72
80
|
data,
|
|
73
81
|
stateSlot - data.slot,
|
|
74
82
|
epochCtx.epoch,
|
|
75
|
-
rootCache
|
|
83
|
+
rootCache,
|
|
84
|
+
fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).executionPayloadAvailability.toBoolArray() : null
|
|
76
85
|
);
|
|
77
86
|
|
|
78
87
|
// For each participant, update their participation
|
|
@@ -121,12 +130,35 @@ export function processAttestationsAltair(
|
|
|
121
130
|
}
|
|
122
131
|
}
|
|
123
132
|
}
|
|
133
|
+
|
|
134
|
+
if (fork >= ForkSeq.gloas && flagsNewSet !== 0 && isAttestationSameSlot(state as CachedBeaconStateGloas, data)) {
|
|
135
|
+
paymentWeightToAdd += effectiveBalanceIncrements[validatorIndex];
|
|
136
|
+
}
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
// Do the discrete math inside the loop to ensure a deterministic result
|
|
127
140
|
const totalIncrements = totalBalanceIncrementsWithWeight;
|
|
128
141
|
const proposerRewardNumerator = totalIncrements * state.epochCtx.baseRewardPerIncrement;
|
|
129
142
|
proposerReward += Math.floor(proposerRewardNumerator / PROPOSER_REWARD_DOMINATOR);
|
|
143
|
+
|
|
144
|
+
if (fork >= ForkSeq.gloas) {
|
|
145
|
+
const builderPendingPaymentIndex = inCurrentEpoch
|
|
146
|
+
? SLOTS_PER_EPOCH + (data.slot % SLOTS_PER_EPOCH)
|
|
147
|
+
: data.slot % SLOTS_PER_EPOCH;
|
|
148
|
+
|
|
149
|
+
const existingWeight =
|
|
150
|
+
builderWeightMap.get(builderPendingPaymentIndex) ??
|
|
151
|
+
(state as CachedBeaconStateGloas).builderPendingPayments.get(builderPendingPaymentIndex).weight;
|
|
152
|
+
const updatedWeight = existingWeight + paymentWeightToAdd * EFFECTIVE_BALANCE_INCREMENT;
|
|
153
|
+
builderWeightMap.set(builderPendingPaymentIndex, updatedWeight);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const [index, weight] of builderWeightMap) {
|
|
158
|
+
const payment = (state as CachedBeaconStateGloas).builderPendingPayments.get(index);
|
|
159
|
+
if (payment.withdrawal.amount > 0) {
|
|
160
|
+
payment.weight = weight;
|
|
161
|
+
}
|
|
130
162
|
}
|
|
131
163
|
|
|
132
164
|
metrics?.newSeenAttestersPerBlock.set(newSeenAttesters);
|
|
@@ -145,7 +177,8 @@ export function getAttestationParticipationStatus(
|
|
|
145
177
|
data: phase0.AttestationData,
|
|
146
178
|
inclusionDelay: number,
|
|
147
179
|
currentEpoch: Epoch,
|
|
148
|
-
rootCache: RootCache
|
|
180
|
+
rootCache: RootCache,
|
|
181
|
+
executionPayloadAvailability: boolean[] | null
|
|
149
182
|
): number {
|
|
150
183
|
const justifiedCheckpoint =
|
|
151
184
|
data.target.epoch === currentEpoch ? rootCache.currentJustifiedCheckpoint : rootCache.previousJustifiedCheckpoint;
|
|
@@ -168,9 +201,33 @@ export function getAttestationParticipationStatus(
|
|
|
168
201
|
const isMatchingTarget = byteArrayEquals(data.target.root, rootCache.getBlockRoot(data.target.epoch));
|
|
169
202
|
|
|
170
203
|
// a timely head is only be set if the target is _also_ matching
|
|
171
|
-
|
|
204
|
+
// In gloas, this is called `head_root_matches`
|
|
205
|
+
let isMatchingHead =
|
|
172
206
|
isMatchingTarget && byteArrayEquals(data.beaconBlockRoot, rootCache.getBlockRootAtSlot(data.slot));
|
|
173
207
|
|
|
208
|
+
if (fork >= ForkSeq.gloas) {
|
|
209
|
+
let isMatchingPayload = false;
|
|
210
|
+
|
|
211
|
+
if (isAttestationSameSlotRootCache(rootCache, data)) {
|
|
212
|
+
if (data.index !== 0) {
|
|
213
|
+
throw new Error("Attesting same slot must indicate empty payload");
|
|
214
|
+
}
|
|
215
|
+
isMatchingPayload = true;
|
|
216
|
+
} else {
|
|
217
|
+
if (executionPayloadAvailability === null) {
|
|
218
|
+
throw new Error("Must supply executionPayloadAvailability post-gloas");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (data.index !== 0 && data.index !== 1) {
|
|
222
|
+
throw new Error(`data index must be 0 or 1 index=${data.index}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
isMatchingPayload = Boolean(data.index) === executionPayloadAvailability[data.slot % SLOTS_PER_HISTORICAL_ROOT];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
isMatchingHead = isMatchingHead && isMatchingPayload;
|
|
229
|
+
}
|
|
230
|
+
|
|
174
231
|
let flags = 0;
|
|
175
232
|
if (isMatchingSource && inclusionDelay <= SLOTS_PER_EPOCH_SQRT) flags |= TIMELY_SOURCE;
|
|
176
233
|
if (isMatchingTarget && isTimelyTarget(fork, inclusionDelay)) flags |= TIMELY_TARGET;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params";
|
|
1
|
+
import {FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params";
|
|
2
2
|
import {electra, ssz} from "@lodestar/types";
|
|
3
|
-
import {CachedBeaconStateElectra} from "../types.js";
|
|
3
|
+
import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
|
|
4
4
|
import {hasEth1WithdrawalCredential} from "../util/capella.js";
|
|
5
5
|
import {
|
|
6
6
|
hasCompoundingWithdrawalCredential,
|
|
@@ -13,7 +13,8 @@ import {getConsolidationChurnLimit, getPendingBalanceToWithdraw, isActiveValidat
|
|
|
13
13
|
|
|
14
14
|
// TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest
|
|
15
15
|
export function processConsolidationRequest(
|
|
16
|
-
|
|
16
|
+
fork: ForkSeq,
|
|
17
|
+
state: CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
17
18
|
consolidationRequest: electra.ConsolidationRequest
|
|
18
19
|
): void {
|
|
19
20
|
const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest;
|
|
@@ -82,7 +83,7 @@ export function processConsolidationRequest(
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
// Verify the source has no pending withdrawals in the queue
|
|
85
|
-
if (getPendingBalanceToWithdraw(state, sourceIndex) > 0) {
|
|
86
|
+
if (getPendingBalanceToWithdraw(fork, state, sourceIndex) > 0) {
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -103,7 +104,7 @@ export function processConsolidationRequest(
|
|
|
103
104
|
* Determine if we should set consolidation target validator to compounding credential
|
|
104
105
|
*/
|
|
105
106
|
function isValidSwitchToCompoundRequest(
|
|
106
|
-
state: CachedBeaconStateElectra,
|
|
107
|
+
state: CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
107
108
|
consolidationRequest: electra.ConsolidationRequest
|
|
108
109
|
): boolean {
|
|
109
110
|
const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
|
|
2
2
|
import {electra, ssz} from "@lodestar/types";
|
|
3
|
-
import {CachedBeaconStateElectra} from "../types.js";
|
|
3
|
+
import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
|
|
4
4
|
|
|
5
|
-
export function processDepositRequest(
|
|
5
|
+
export function processDepositRequest(
|
|
6
|
+
state: CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
7
|
+
depositRequest: electra.DepositRequest
|
|
8
|
+
): void {
|
|
6
9
|
if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
|
|
7
10
|
state.depositRequestsStartIndex = depositRequest.index;
|
|
8
11
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
|
+
import {byteArrayEquals} from "@chainsafe/ssz";
|
|
3
|
+
import {
|
|
4
|
+
DOMAIN_BEACON_BUILDER,
|
|
5
|
+
FAR_FUTURE_EPOCH,
|
|
6
|
+
ForkPostGloas,
|
|
7
|
+
MIN_ACTIVATION_BALANCE,
|
|
8
|
+
SLOTS_PER_EPOCH,
|
|
9
|
+
} from "@lodestar/params";
|
|
10
|
+
import {BeaconBlock, gloas, ssz} from "@lodestar/types";
|
|
11
|
+
import {toHex, toRootHex} from "@lodestar/utils";
|
|
12
|
+
import {G2_POINT_AT_INFINITY} from "../constants/constants.ts";
|
|
13
|
+
import {CachedBeaconStateGloas} from "../types.ts";
|
|
14
|
+
import {hasBuilderWithdrawalCredential} from "../util/gloas.ts";
|
|
15
|
+
import {computeSigningRoot, getCurrentEpoch, getRandaoMix, isActiveValidator} from "../util/index.ts";
|
|
16
|
+
|
|
17
|
+
export function processExecutionPayloadBid(state: CachedBeaconStateGloas, block: BeaconBlock<ForkPostGloas>): void {
|
|
18
|
+
const signedBid = block.body.signedExecutionPayloadBid;
|
|
19
|
+
const bid = signedBid.message;
|
|
20
|
+
const {builderIndex, value: amount} = bid;
|
|
21
|
+
const builder = state.validators.getReadonly(builderIndex);
|
|
22
|
+
|
|
23
|
+
// For self-builds, amount must be zero regardless of withdrawal credential prefix
|
|
24
|
+
if (builderIndex === block.proposerIndex) {
|
|
25
|
+
if (amount !== 0) {
|
|
26
|
+
throw Error(`Invalid execution payload bid: self-build with non-zero amount ${amount}`);
|
|
27
|
+
}
|
|
28
|
+
if (!byteArrayEquals(signedBid.signature, G2_POINT_AT_INFINITY)) {
|
|
29
|
+
throw Error("Invalid execution payload bid: self-build with non-zero signature");
|
|
30
|
+
}
|
|
31
|
+
// Non-self builds require builder withdrawal credential
|
|
32
|
+
} else {
|
|
33
|
+
if (!hasBuilderWithdrawalCredential(builder.withdrawalCredentials)) {
|
|
34
|
+
throw Error(`Invalid execution payload bid: builder ${builderIndex} does not have builder withdrawal credential`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!verifyExecutionPayloadBidSignature(state, builder.pubkey, signedBid)) {
|
|
38
|
+
throw Error(`Invalid execution payload bid: invalid signature for builder ${builderIndex}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!isActiveValidator(builder, getCurrentEpoch(state))) {
|
|
43
|
+
throw Error(`Invalid execution payload bid: builder ${builderIndex} is not active`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (builder.slashed) {
|
|
47
|
+
throw Error(`Invalid execution payload bid: builder ${builderIndex} is slashed`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const pendingPayments = state.builderPendingPayments
|
|
51
|
+
.getAllReadonly()
|
|
52
|
+
.filter((payment) => payment.withdrawal.builderIndex === builderIndex)
|
|
53
|
+
.reduce((acc, payment) => acc + payment.withdrawal.amount, 0);
|
|
54
|
+
const pendingWithdrawals = state.builderPendingWithdrawals
|
|
55
|
+
.getAllReadonly()
|
|
56
|
+
.filter((withdrawal) => withdrawal.builderIndex === builderIndex)
|
|
57
|
+
.reduce((acc, withdrawal) => acc + withdrawal.amount, 0);
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
amount !== 0 &&
|
|
61
|
+
state.balances.get(builderIndex) < amount + pendingPayments + pendingWithdrawals + MIN_ACTIVATION_BALANCE
|
|
62
|
+
) {
|
|
63
|
+
throw Error("Insufficient builder balance");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (bid.slot !== block.slot) {
|
|
67
|
+
throw Error(`Bid slot ${bid.slot} does not match block slot ${block.slot}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!byteArrayEquals(bid.parentBlockHash, state.latestBlockHash)) {
|
|
71
|
+
throw Error(
|
|
72
|
+
`Parent block hash ${toRootHex(bid.parentBlockHash)} of bid does not match state's latest block hash ${toRootHex(state.latestBlockHash)}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!byteArrayEquals(bid.parentBlockRoot, block.parentRoot)) {
|
|
77
|
+
throw Error(
|
|
78
|
+
`Parent block root ${toRootHex(bid.parentBlockRoot)} of bid does not match block's parent root ${toRootHex(block.parentRoot)}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const stateRandao = getRandaoMix(state, getCurrentEpoch(state));
|
|
83
|
+
if (!byteArrayEquals(bid.prevRandao, stateRandao)) {
|
|
84
|
+
throw Error(`Prev randao ${toHex(bid.prevRandao)} of bid does not match state's randao mix ${toHex(stateRandao)}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (amount > 0) {
|
|
88
|
+
const pendingPaymentView = ssz.gloas.BuilderPendingPayment.toViewDU({
|
|
89
|
+
weight: 0,
|
|
90
|
+
withdrawal: ssz.gloas.BuilderPendingWithdrawal.toViewDU({
|
|
91
|
+
feeRecipient: bid.feeRecipient,
|
|
92
|
+
amount,
|
|
93
|
+
builderIndex,
|
|
94
|
+
withdrawableEpoch: FAR_FUTURE_EPOCH,
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function verifyExecutionPayloadBidSignature(
|
|
105
|
+
state: CachedBeaconStateGloas,
|
|
106
|
+
pubkey: Uint8Array,
|
|
107
|
+
signedBid: gloas.SignedExecutionPayloadBid
|
|
108
|
+
): boolean {
|
|
109
|
+
const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_BUILDER);
|
|
110
|
+
const signingRoot = computeSigningRoot(ssz.gloas.ExecutionPayloadBid, signedBid.message, domain);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const publicKey = PublicKey.fromBytes(pubkey);
|
|
114
|
+
const signature = Signature.fromBytes(signedBid.signature, true);
|
|
115
|
+
|
|
116
|
+
return verify(signingRoot, publicKey, signature);
|
|
117
|
+
} catch (_e) {
|
|
118
|
+
return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
|
+
import {byteArrayEquals} from "@chainsafe/ssz";
|
|
3
|
+
import {DOMAIN_BEACON_BUILDER, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
4
|
+
import {gloas, ssz} from "@lodestar/types";
|
|
5
|
+
import {toHex, toRootHex} from "@lodestar/utils";
|
|
6
|
+
import {CachedBeaconStateGloas} from "../types.ts";
|
|
7
|
+
import {computeExitEpochAndUpdateChurn, computeSigningRoot, computeTimeAtSlot} from "../util/index.ts";
|
|
8
|
+
import {processConsolidationRequest} from "./processConsolidationRequest.ts";
|
|
9
|
+
import {processDepositRequest} from "./processDepositRequest.ts";
|
|
10
|
+
import {processWithdrawalRequest} from "./processWithdrawalRequest.ts";
|
|
11
|
+
|
|
12
|
+
// This function does not call execution engine to verify payload. Need to call it from other place
|
|
13
|
+
export function processExecutionPayloadEnvelope(
|
|
14
|
+
state: CachedBeaconStateGloas,
|
|
15
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
16
|
+
verify: boolean
|
|
17
|
+
): void {
|
|
18
|
+
const envelope = signedEnvelope.message;
|
|
19
|
+
const payload = envelope.payload;
|
|
20
|
+
const fork = state.config.getForkSeq(envelope.slot);
|
|
21
|
+
|
|
22
|
+
if (verify) {
|
|
23
|
+
const builderIndex = envelope.builderIndex;
|
|
24
|
+
const pubkey = state.validators.getReadonly(builderIndex).pubkey;
|
|
25
|
+
|
|
26
|
+
if (!verifyExecutionPayloadEnvelopeSignature(state, pubkey, signedEnvelope)) {
|
|
27
|
+
throw new Error("Payload Envelope has invalid signature");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
validateExecutionPayloadEnvelope(state, envelope);
|
|
32
|
+
|
|
33
|
+
const requests = envelope.executionRequests;
|
|
34
|
+
|
|
35
|
+
for (const deposit of requests.deposits) {
|
|
36
|
+
processDepositRequest(state, deposit);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const withdrawal of requests.withdrawals) {
|
|
40
|
+
processWithdrawalRequest(fork, state, withdrawal);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const consolidation of requests.consolidations) {
|
|
44
|
+
processConsolidationRequest(fork, state, consolidation);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Queue the builder payment
|
|
48
|
+
const paymentIndex = SLOTS_PER_EPOCH + (state.slot % SLOTS_PER_EPOCH);
|
|
49
|
+
const payment = state.builderPendingPayments.get(paymentIndex).clone();
|
|
50
|
+
const amount = payment.withdrawal.amount;
|
|
51
|
+
|
|
52
|
+
if (amount > 0) {
|
|
53
|
+
const exitQueueEpoch = computeExitEpochAndUpdateChurn(state, BigInt(amount));
|
|
54
|
+
|
|
55
|
+
payment.withdrawal.withdrawableEpoch = exitQueueEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY;
|
|
56
|
+
state.builderPendingWithdrawals.push(payment.withdrawal);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
state.builderPendingPayments.set(paymentIndex, ssz.gloas.BuilderPendingPayment.defaultViewDU());
|
|
60
|
+
|
|
61
|
+
// Cache the execution payload hash
|
|
62
|
+
state.executionPayloadAvailability.set(state.slot % SLOTS_PER_HISTORICAL_ROOT, true);
|
|
63
|
+
state.latestBlockHash = payload.blockHash;
|
|
64
|
+
|
|
65
|
+
if (verify && !byteArrayEquals(envelope.stateRoot, state.hashTreeRoot())) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Envelope's state root does not match state envelope=${toRootHex(envelope.stateRoot)} state=${toRootHex(state.hashTreeRoot())}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function validateExecutionPayloadEnvelope(
|
|
73
|
+
state: CachedBeaconStateGloas,
|
|
74
|
+
envelope: gloas.ExecutionPayloadEnvelope
|
|
75
|
+
): void {
|
|
76
|
+
const payload = envelope.payload;
|
|
77
|
+
|
|
78
|
+
if (byteArrayEquals(state.latestBlockHeader.stateRoot, ssz.Root.defaultValue())) {
|
|
79
|
+
const previousStateRoot = state.hashTreeRoot();
|
|
80
|
+
state.latestBlockHeader.stateRoot = previousStateRoot;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Verify consistency with the beacon block
|
|
84
|
+
if (!byteArrayEquals(envelope.beaconBlockRoot, state.latestBlockHeader.hashTreeRoot())) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Envelope's block is not the latest block header envelope=${toRootHex(envelope.beaconBlockRoot)} latestBlockHeader=${toRootHex(state.latestBlockHeader.hashTreeRoot())}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Verify consistency with the beacon block
|
|
91
|
+
if (envelope.slot !== state.slot) {
|
|
92
|
+
throw new Error(`Slot mismatch between envelope and state envelope=${envelope.slot} state=${state.slot}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const committedBid = state.latestExecutionPayloadBid;
|
|
96
|
+
// Verify consistency with the committed bid
|
|
97
|
+
if (envelope.builderIndex !== committedBid.builderIndex) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Builder index mismatch between envelope and committed bid envelope=${envelope.builderIndex} committedBid=${committedBid.builderIndex}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Verify consistency with the committed bid
|
|
104
|
+
const envelopeKzgRoot = ssz.deneb.BlobKzgCommitments.hashTreeRoot(envelope.blobKzgCommitments);
|
|
105
|
+
if (!byteArrayEquals(committedBid.blobKzgCommitmentsRoot, envelopeKzgRoot)) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Kzg commitment root mismatch between envelope and committed bid envelope=${toRootHex(envelopeKzgRoot)} committedBid=${toRootHex(committedBid.blobKzgCommitmentsRoot)}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Verify the withdrawals root
|
|
112
|
+
const envelopeWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(envelope.payload.withdrawals);
|
|
113
|
+
if (!byteArrayEquals(state.latestWithdrawalsRoot, envelopeWithdrawalsRoot)) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Withdrawals root mismatch between envelope and latest withdrawals root envelope=${toRootHex(envelopeWithdrawalsRoot)} latestWithdrawalRoot=${toRootHex(state.latestWithdrawalsRoot)}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Verify the gas_limit
|
|
120
|
+
if (Number(committedBid.gasLimit) !== payload.gasLimit) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Gas limit mismatch between envelope's payload and committed bid envelope=${payload.gasLimit} committedBid=${Number(committedBid.gasLimit)}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Verify the block hash
|
|
127
|
+
if (!byteArrayEquals(committedBid.blockHash, payload.blockHash)) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Block hash mismatch between envelope's payload and committed bid envelope=${toRootHex(payload.blockHash)} committedBid=${toRootHex(committedBid.blockHash)}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Verify consistency of the parent hash with respect to the previous execution payload
|
|
134
|
+
if (!byteArrayEquals(payload.parentHash, state.latestBlockHash)) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Parent hash mismatch between envelope's payload and state envelope=${toRootHex(payload.parentHash)} state=${toRootHex(state.latestBlockHash)}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Verify prev_randao matches committed bid
|
|
141
|
+
if (!byteArrayEquals(committedBid.prevRandao, payload.prevRandao)) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`Prev randao mismatch between committed bid and payload committedBid=${toHex(committedBid.prevRandao)} payload=${toHex(payload.prevRandao)}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Verify timestamp
|
|
148
|
+
if (payload.timestamp !== computeTimeAtSlot(state.config, state.slot, state.genesisTime)) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Timestamp mismatch between envelope's payload and state envelope=${payload.timestamp} state=${computeTimeAtSlot(state.config, state.slot, state.genesisTime)}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Verify commitments are under limit
|
|
155
|
+
const maxBlobsPerBlock = state.config.getMaxBlobsPerBlock(state.epochCtx.epoch);
|
|
156
|
+
if (envelope.blobKzgCommitments.length > maxBlobsPerBlock) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Kzg commitments exceed limit commitment.length=${envelope.blobKzgCommitments.length} limit=${maxBlobsPerBlock}`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Skipped: Verify the execution payload is valid
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function verifyExecutionPayloadEnvelopeSignature(
|
|
166
|
+
state: CachedBeaconStateGloas,
|
|
167
|
+
pubkey: Uint8Array,
|
|
168
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope
|
|
169
|
+
): boolean {
|
|
170
|
+
const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_BUILDER);
|
|
171
|
+
const signingRoot = computeSigningRoot(ssz.gloas.ExecutionPayloadEnvelope, signedEnvelope.message, domain);
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const publicKey = PublicKey.fromBytes(pubkey);
|
|
175
|
+
const signature = Signature.fromBytes(signedEnvelope.signature, true);
|
|
176
|
+
|
|
177
|
+
return verify(signingRoot, publicKey, signature);
|
|
178
|
+
} catch (_e) {
|
|
179
|
+
return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
|
|
180
|
+
}
|
|
181
|
+
}
|