@lodestar/state-transition 1.37.0-rc.0 → 1.38.0-dev.1ddbe5d870
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/isValidIndexedAttestation.d.ts +3 -2
- package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
- package/lib/block/isValidIndexedAttestation.js +4 -4
- package/lib/block/isValidIndexedAttestation.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 +7 -2
- 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 +47 -5
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processAttesterSlashing.d.ts +2 -1
- package/lib/block/processAttesterSlashing.d.ts.map +1 -1
- package/lib/block/processAttesterSlashing.js +5 -4
- package/lib/block/processAttesterSlashing.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 +17 -2
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processRandao.js +1 -1
- package/lib/block/processRandao.js.map +1 -1
- package/lib/block/processSyncCommittee.d.ts +2 -1
- package/lib/block/processSyncCommittee.d.ts.map +1 -1
- package/lib/block/processSyncCommittee.js +3 -4
- package/lib/block/processSyncCommittee.js.map +1 -1
- package/lib/block/processVoluntaryExit.js +2 -2
- 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/attesterSlashings.d.ts +4 -3
- package/lib/signatureSets/attesterSlashings.d.ts.map +1 -1
- package/lib/signatureSets/attesterSlashings.js +6 -6
- package/lib/signatureSets/attesterSlashings.js.map +1 -1
- package/lib/signatureSets/index.d.ts +4 -2
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +9 -8
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/indexedAttestation.d.ts +4 -3
- package/lib/signatureSets/indexedAttestation.d.ts.map +1 -1
- package/lib/signatureSets/indexedAttestation.js +9 -7
- 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/signatureSets/proposer.d.ts +5 -4
- package/lib/signatureSets/proposer.d.ts.map +1 -1
- package/lib/signatureSets/proposer.js +12 -12
- package/lib/signatureSets/proposer.js.map +1 -1
- package/lib/signatureSets/proposerSlashings.d.ts +3 -2
- package/lib/signatureSets/proposerSlashings.d.ts.map +1 -1
- package/lib/signatureSets/proposerSlashings.js +4 -5
- package/lib/signatureSets/proposerSlashings.js.map +1 -1
- package/lib/signatureSets/randao.d.ts +3 -2
- package/lib/signatureSets/randao.d.ts.map +1 -1
- package/lib/signatureSets/randao.js +4 -5
- package/lib/signatureSets/randao.js.map +1 -1
- package/lib/signatureSets/voluntaryExits.d.ts +4 -3
- package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
- package/lib/signatureSets/voluntaryExits.js +6 -7
- package/lib/signatureSets/voluntaryExits.js.map +1 -1
- 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 +5 -4
- 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/isValidIndexedAttestation.ts +5 -2
- package/src/block/isValidIndexedPayloadAttestation.ts +23 -0
- package/src/block/processAttestationPhase0.ts +13 -2
- package/src/block/processAttestationsAltair.ts +63 -6
- package/src/block/processAttesterSlashing.ts +6 -3
- 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 +25 -4
- package/src/block/processRandao.ts +1 -1
- package/src/block/processSyncCommittee.ts +4 -3
- package/src/block/processVoluntaryExit.ts +2 -2
- 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/attesterSlashings.ts +7 -3
- package/src/signatureSets/index.ts +12 -7
- package/src/signatureSets/indexedAttestation.ts +20 -9
- package/src/signatureSets/indexedPayloadAttestation.ts +24 -0
- package/src/signatureSets/proposer.ts +13 -7
- package/src/signatureSets/proposerSlashings.ts +5 -3
- package/src/signatureSets/randao.ts +13 -5
- package/src/signatureSets/voluntaryExits.ts +7 -4
- 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 +5 -5
- 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.1ddbe5d870",
|
|
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": "1.
|
|
66
|
-
"@lodestar/params": "1.
|
|
67
|
-
"@lodestar/types": "1.
|
|
68
|
-
"@lodestar/utils": "1.
|
|
65
|
+
"@lodestar/config": "1.38.0-dev.1ddbe5d870",
|
|
66
|
+
"@lodestar/params": "1.38.0-dev.1ddbe5d870",
|
|
67
|
+
"@lodestar/types": "1.38.0-dev.1ddbe5d870",
|
|
68
|
+
"@lodestar/utils": "1.38.0-dev.1ddbe5d870",
|
|
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": "6971d287b75663e80ed5f5635d26e81892a53476"
|
|
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);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {ForkSeq, MAX_COMMITTEES_PER_SLOT, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params";
|
|
2
2
|
import {IndexedAttestation, IndexedAttestationBigint} from "@lodestar/types";
|
|
3
|
+
import {Index2PubkeyCache} from "../cache/pubkeyCache.js";
|
|
3
4
|
import {getIndexedAttestationBigintSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets/index.js";
|
|
4
5
|
import {CachedBeaconStateAllForks} from "../types.js";
|
|
5
6
|
import {verifySignatureSet} from "../util/index.js";
|
|
@@ -8,6 +9,7 @@ import {verifySignatureSet} from "../util/index.js";
|
|
|
8
9
|
* Check if `indexedAttestation` has sorted and unique indices and a valid aggregate signature.
|
|
9
10
|
*/
|
|
10
11
|
export function isValidIndexedAttestation(
|
|
12
|
+
index2pubkey: Index2PubkeyCache,
|
|
11
13
|
state: CachedBeaconStateAllForks,
|
|
12
14
|
indexedAttestation: IndexedAttestation,
|
|
13
15
|
verifySignature: boolean
|
|
@@ -17,12 +19,13 @@ export function isValidIndexedAttestation(
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
if (verifySignature) {
|
|
20
|
-
return verifySignatureSet(getIndexedAttestationSignatureSet(state, indexedAttestation));
|
|
22
|
+
return verifySignatureSet(getIndexedAttestationSignatureSet(index2pubkey, state, indexedAttestation));
|
|
21
23
|
}
|
|
22
24
|
return true;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export function isValidIndexedAttestationBigint(
|
|
28
|
+
index2pubkey: Index2PubkeyCache,
|
|
26
29
|
state: CachedBeaconStateAllForks,
|
|
27
30
|
indexedAttestation: IndexedAttestationBigint,
|
|
28
31
|
verifySignature: boolean
|
|
@@ -32,7 +35,7 @@ export function isValidIndexedAttestationBigint(
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
if (verifySignature) {
|
|
35
|
-
return verifySignatureSet(getIndexedAttestationBigintSignatureSet(state, indexedAttestation));
|
|
38
|
+
return verifySignatureSet(getIndexedAttestationBigintSignatureSet(index2pubkey, state, indexedAttestation));
|
|
36
39
|
}
|
|
37
40
|
return true;
|
|
38
41
|
}
|
|
@@ -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
|
+
}
|
|
@@ -50,7 +50,14 @@ export function processAttestationPhase0(
|
|
|
50
50
|
state.previousEpochAttestations.push(pendingAttestation);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
!isValidIndexedAttestation(
|
|
55
|
+
epochCtx.index2pubkey,
|
|
56
|
+
state,
|
|
57
|
+
epochCtx.getIndexedAttestation(ForkSeq.phase0, attestation),
|
|
58
|
+
verifySignature
|
|
59
|
+
)
|
|
60
|
+
) {
|
|
54
61
|
throw new Error("Attestation is not valid");
|
|
55
62
|
}
|
|
56
63
|
}
|
|
@@ -86,7 +93,11 @@ export function validateAttestation(fork: ForkSeq, state: CachedBeaconStateAllFo
|
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
if (fork >= ForkSeq.electra) {
|
|
89
|
-
|
|
96
|
+
if (fork >= ForkSeq.gloas) {
|
|
97
|
+
assert.lt(data.index, 2, `AttestationData.index must be 0 or 1: index=${data.index}`);
|
|
98
|
+
} else {
|
|
99
|
+
assert.equal(data.index, 0, `AttestationData.index must be 0: index=${data.index}`);
|
|
100
|
+
}
|
|
90
101
|
const attestationElectra = attestation as electra.Attestation;
|
|
91
102
|
const committeeIndices = attestationElectra.committeeBits.getTrueBitIndexes();
|
|
92
103
|
|
|
@@ -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
|
|
|
@@ -58,7 +64,7 @@ export function processAttestationsAltair(
|
|
|
58
64
|
// TODO: Why should we verify an indexed attestation that we just created? If it's just for the signature
|
|
59
65
|
// we can verify only that and nothing else.
|
|
60
66
|
if (verifySignature) {
|
|
61
|
-
const sigSet = getAttestationWithIndicesSignatureSet(state, attestation, attestingIndices);
|
|
67
|
+
const sigSet = getAttestationWithIndicesSignatureSet(epochCtx.index2pubkey, state, attestation, attestingIndices);
|
|
62
68
|
if (!verifySignatureSet(sigSet)) {
|
|
63
69
|
throw new Error("Attestation signature is not valid");
|
|
64
70
|
}
|
|
@@ -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,5 +1,6 @@
|
|
|
1
1
|
import {ForkSeq} from "@lodestar/params";
|
|
2
2
|
import {AttesterSlashing} from "@lodestar/types";
|
|
3
|
+
import {Index2PubkeyCache} from "../cache/pubkeyCache.js";
|
|
3
4
|
import {CachedBeaconStateAllForks} from "../types.js";
|
|
4
5
|
import {getAttesterSlashableIndices, isSlashableAttestationData, isSlashableValidator} from "../util/index.js";
|
|
5
6
|
import {isValidIndexedAttestationBigint} from "./isValidIndexedAttestation.js";
|
|
@@ -17,7 +18,8 @@ export function processAttesterSlashing(
|
|
|
17
18
|
attesterSlashing: AttesterSlashing,
|
|
18
19
|
verifySignatures = true
|
|
19
20
|
): void {
|
|
20
|
-
|
|
21
|
+
const {epochCtx} = state;
|
|
22
|
+
assertValidAttesterSlashing(epochCtx.index2pubkey, state, attesterSlashing, verifySignatures);
|
|
21
23
|
|
|
22
24
|
const intersectingIndices = getAttesterSlashableIndices(attesterSlashing);
|
|
23
25
|
|
|
@@ -25,7 +27,7 @@ export function processAttesterSlashing(
|
|
|
25
27
|
const validators = state.validators; // Get the validators sub tree once for all indices
|
|
26
28
|
// Spec requires to sort indexes beforehand
|
|
27
29
|
for (const index of intersectingIndices.sort((a, b) => a - b)) {
|
|
28
|
-
if (isSlashableValidator(validators.getReadonly(index),
|
|
30
|
+
if (isSlashableValidator(validators.getReadonly(index), epochCtx.epoch)) {
|
|
29
31
|
slashValidator(fork, state, index);
|
|
30
32
|
slashedAny = true;
|
|
31
33
|
}
|
|
@@ -37,6 +39,7 @@ export function processAttesterSlashing(
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
export function assertValidAttesterSlashing(
|
|
42
|
+
index2pubkey: Index2PubkeyCache,
|
|
40
43
|
state: CachedBeaconStateAllForks,
|
|
41
44
|
attesterSlashing: AttesterSlashing,
|
|
42
45
|
verifySignatures = true
|
|
@@ -52,7 +55,7 @@ export function assertValidAttesterSlashing(
|
|
|
52
55
|
// be higher than the clock and the slashing would still be valid. Same applies to attestation data index, which
|
|
53
56
|
// can be any arbitrary value. Must use bigint variants to hash correctly to all possible values
|
|
54
57
|
for (const [i, attestation] of [attestation1, attestation2].entries()) {
|
|
55
|
-
if (!isValidIndexedAttestationBigint(state, attestation, verifySignatures)) {
|
|
58
|
+
if (!isValidIndexedAttestationBigint(index2pubkey, state, attestation, verifySignatures)) {
|
|
56
59
|
throw new Error(`AttesterSlashing attestation${i} is invalid`);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
@@ -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
|
+
}
|