@lodestar/beacon-node 1.43.0 → 1.44.0-dev.08d94fd9e2
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/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +30 -0
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +46 -5
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +105 -53
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +5 -2
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +5 -3
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +5 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +29 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +5 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +14 -4
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -1
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +4 -4
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +6 -4
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/opPools/index.d.ts +1 -0
- package/lib/chain/opPools/index.d.ts.map +1 -1
- package/lib/chain/opPools/index.js +1 -0
- package/lib/chain/opPools/index.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +30 -10
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +29 -0
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -0
- package/lib/chain/opPools/proposerPreferencesPool.js +56 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -0
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +2 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +7 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +107 -18
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +2 -0
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +2 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +7 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +97 -23
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +20 -8
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +1 -0
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +16 -0
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/builder/index.d.ts +1 -2
- package/lib/execution/builder/index.d.ts.map +1 -1
- package/lib/execution/builder/index.js +0 -1
- package/lib/execution/builder/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/types.d.ts +2 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +2 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -1
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -3
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +20 -767
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/interface.d.ts +2 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +2 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +10 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +19 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/util/dependentRoot.d.ts +6 -2
- package/lib/util/dependentRoot.d.ts.map +1 -1
- package/lib/util/dependentRoot.js +20 -16
- package/lib/util/dependentRoot.js.map +1 -1
- package/package.json +14 -15
- package/src/api/impl/beacon/blocks/index.ts +36 -0
- package/src/api/impl/beacon/pool/index.ts +59 -4
- package/src/api/impl/validator/index.ts +120 -54
- package/src/chain/blocks/importBlock.ts +10 -2
- package/src/chain/blocks/importExecutionPayload.ts +8 -2
- package/src/chain/chain.ts +5 -0
- package/src/chain/errors/executionPayloadBid.ts +27 -1
- package/src/chain/forkChoice/index.ts +14 -4
- package/src/chain/interface.ts +2 -0
- package/src/chain/lightClient/index.ts +6 -6
- package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
- package/src/chain/opPools/index.ts +1 -0
- package/src/chain/opPools/payloadAttestationPool.ts +34 -10
- package/src/chain/opPools/proposerPreferencesPool.ts +59 -0
- package/src/chain/prepareNextSlot.ts +2 -1
- package/src/chain/produceBlock/produceBlockBody.ts +158 -25
- package/src/chain/regen/interface.ts +2 -0
- package/src/chain/validation/executionPayloadBid.ts +107 -28
- package/src/chain/validation/payloadAttestationMessage.ts +23 -10
- package/src/chain/validatorMonitor.ts +18 -0
- package/src/execution/builder/index.ts +1 -4
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/types.ts +4 -0
- package/src/metrics/metrics/lodestar.ts +4 -3
- package/src/network/interface.ts +2 -0
- package/src/network/network.ts +22 -0
- package/src/network/processor/gossipHandlers.ts +25 -6
- package/src/util/dependentRoot.ts +22 -18
- package/lib/execution/builder/utils.d.ts +0 -5
- package/lib/execution/builder/utils.d.ts.map +0 -1
- package/lib/execution/builder/utils.js +0 -17
- package/lib/execution/builder/utils.js.map +0 -1
- package/src/execution/builder/utils.ts +0 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependentRoot.js","sourceRoot":"","sources":["../../src/util/dependentRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAA0B,MAAM,uBAAuB,CAAC;AAG/E
|
|
1
|
+
{"version":3,"file":"dependentRoot.js","sourceRoot":"","sources":["../../src/util/dependentRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAA0B,MAAM,uBAAuB,CAAC;AAG/E;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAuB,EACvB,QAAe,EACf,eAAsB,EACtB,UAAsB,EACb;IACT,IAAI,sBAA+B,CAAC;IACpC,IAAI,eAAe,KAAK,QAAQ,EAAE,CAAC;QACjC,wEAAwE;QACxE,uCAAuC;QACvC,oDAAoD;QACpD,kDAAkD;QAClD,6CAA6C;QAC7C,iCAAiC;QACjC,sBAAsB,GAAG,UAAU,CAAC,gBAAgB,CAAC,UAAU,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC7F,CAAC;SAAM,IAAI,eAAe,KAAK,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC5C,kEAAkE;QAClE,4CAA4C;QAC5C,oDAAoD;QACpD,kDAAkD;QAClD,wCAAwC;QACxC,iCAAiC;QACjC,sBAAsB,GAAG,UAAU,CAAC,gBAAgB,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5F,CAAC;SAAM,IAAI,eAAe,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC1C,wGAAwG;QACxG,0DAA0D;QAC1D,4CAA4C;QAC5C,oDAAoD;QACpD,kDAAkD;QAClD,gCAAgC;QAChC,gCAAgC;QAChC,sBAAsB,GAAG,UAAU,CAAC,SAAS,CAAC;QAC9C,0FAA0F;IAC5F,CAAC;SAAM,CAAC;QACN,6BAA6B;QAC7B,4DAA4D;QAC5D,MAAM,KAAK,CAAC,iBAAiB,QAAQ,gCAAgC,eAAe,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,OAAO,sBAAsB,CAAC;AAAA,CAC/B"}
|
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.44.0-dev.08d94fd9e2",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -135,18 +135,17 @@
|
|
|
135
135
|
"@libp2p/peer-id": "^6.0.4",
|
|
136
136
|
"@libp2p/prometheus-metrics": "^5.0.14",
|
|
137
137
|
"@libp2p/tcp": "^11.0.13",
|
|
138
|
-
"@lodestar/api": "^1.
|
|
139
|
-
"@lodestar/config": "^1.
|
|
140
|
-
"@lodestar/db": "^1.
|
|
141
|
-
"@lodestar/fork-choice": "^1.
|
|
142
|
-
"@lodestar/
|
|
143
|
-
"@lodestar/
|
|
144
|
-
"@lodestar/
|
|
145
|
-
"@lodestar/
|
|
146
|
-
"@lodestar/
|
|
147
|
-
"@lodestar/
|
|
148
|
-
"@lodestar/
|
|
149
|
-
"@lodestar/validator": "^1.43.0",
|
|
138
|
+
"@lodestar/api": "^1.44.0-dev.08d94fd9e2",
|
|
139
|
+
"@lodestar/config": "^1.44.0-dev.08d94fd9e2",
|
|
140
|
+
"@lodestar/db": "^1.44.0-dev.08d94fd9e2",
|
|
141
|
+
"@lodestar/fork-choice": "^1.44.0-dev.08d94fd9e2",
|
|
142
|
+
"@lodestar/logger": "^1.44.0-dev.08d94fd9e2",
|
|
143
|
+
"@lodestar/params": "^1.44.0-dev.08d94fd9e2",
|
|
144
|
+
"@lodestar/reqresp": "^1.44.0-dev.08d94fd9e2",
|
|
145
|
+
"@lodestar/state-transition": "^1.44.0-dev.08d94fd9e2",
|
|
146
|
+
"@lodestar/types": "^1.44.0-dev.08d94fd9e2",
|
|
147
|
+
"@lodestar/utils": "^1.44.0-dev.08d94fd9e2",
|
|
148
|
+
"@lodestar/validator": "^1.44.0-dev.08d94fd9e2",
|
|
150
149
|
"@multiformats/multiaddr": "^13.0.1",
|
|
151
150
|
"datastore-core": "^11.0.2",
|
|
152
151
|
"datastore-fs": "^11.0.2",
|
|
@@ -169,7 +168,7 @@
|
|
|
169
168
|
"@libp2p/interface-internal": "^3.0.13",
|
|
170
169
|
"@libp2p/logger": "^6.2.2",
|
|
171
170
|
"@libp2p/utils": "^7.0.13",
|
|
172
|
-
"@lodestar/spec-test-util": "^1.
|
|
171
|
+
"@lodestar/spec-test-util": "^1.44.0-dev.08d94fd9e2",
|
|
173
172
|
"@types/js-yaml": "^4.0.5",
|
|
174
173
|
"@types/qs": "^6.9.7",
|
|
175
174
|
"@types/tmp": "^0.2.3",
|
|
@@ -187,5 +186,5 @@
|
|
|
187
186
|
"beacon",
|
|
188
187
|
"blockchain"
|
|
189
188
|
],
|
|
190
|
-
"gitHead": "
|
|
189
|
+
"gitHead": "bf86a3e22778fda46412554c54a65fb694e6f846"
|
|
191
190
|
}
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
ProduceFullGloas,
|
|
51
51
|
} from "../../../../chain/produceBlock/index.js";
|
|
52
52
|
import {validateGossipBlock} from "../../../../chain/validation/block.js";
|
|
53
|
+
import {validateApiExecutionPayloadBid} from "../../../../chain/validation/executionPayloadBid.js";
|
|
53
54
|
import {validateApiExecutionPayloadEnvelope} from "../../../../chain/validation/executionPayloadEnvelope.js";
|
|
54
55
|
import {OpSource} from "../../../../chain/validatorMonitor.js";
|
|
55
56
|
import {
|
|
@@ -825,6 +826,41 @@ export function getBeaconBlockApi({
|
|
|
825
826
|
});
|
|
826
827
|
},
|
|
827
828
|
|
|
829
|
+
async publishExecutionPayloadBid({signedExecutionPayloadBid}) {
|
|
830
|
+
const bid = signedExecutionPayloadBid.message;
|
|
831
|
+
const slot = bid.slot;
|
|
832
|
+
const fork = config.getForkName(slot);
|
|
833
|
+
|
|
834
|
+
if (!isForkPostGloas(fork)) {
|
|
835
|
+
throw new ApiError(400, `publishExecutionPayloadBid not supported for pre-gloas fork=${fork}`);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
await validateApiExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
839
|
+
|
|
840
|
+
try {
|
|
841
|
+
const insertOutcome = chain.executionPayloadBidPool.add(signedExecutionPayloadBid);
|
|
842
|
+
metrics?.opPool.executionPayloadBidPool.apiInsertOutcome.inc({insertOutcome});
|
|
843
|
+
} catch (e) {
|
|
844
|
+
chain.logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const sentPeers = await network.publishSignedExecutionPayloadBid(signedExecutionPayloadBid);
|
|
848
|
+
|
|
849
|
+
chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
|
|
850
|
+
version: fork,
|
|
851
|
+
data: signedExecutionPayloadBid,
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
chain.logger.info("Published execution payload bid", {
|
|
855
|
+
slot,
|
|
856
|
+
builderIndex: bid.builderIndex,
|
|
857
|
+
blockHash: toRootHex(bid.blockHash),
|
|
858
|
+
parentBlockHash: toRootHex(bid.parentBlockHash),
|
|
859
|
+
value: bid.value,
|
|
860
|
+
sentPeers,
|
|
861
|
+
});
|
|
862
|
+
},
|
|
863
|
+
|
|
828
864
|
async getSignedExecutionPayloadEnvelope({blockId}, context) {
|
|
829
865
|
const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
|
|
830
866
|
const slot = block.message.slot;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ApplicationMethods} from "@lodestar/api/server";
|
|
3
3
|
import {
|
|
4
|
+
ForkName,
|
|
4
5
|
ForkPostElectra,
|
|
5
6
|
ForkPreElectra,
|
|
6
7
|
SYNC_COMMITTEE_SUBNET_SIZE,
|
|
@@ -16,12 +17,15 @@ import {
|
|
|
16
17
|
GossipAction,
|
|
17
18
|
PayloadAttestationError,
|
|
18
19
|
PayloadAttestationErrorCode,
|
|
20
|
+
ProposerPreferencesError,
|
|
21
|
+
ProposerPreferencesErrorCode,
|
|
19
22
|
SyncCommitteeError,
|
|
20
23
|
} from "../../../../chain/errors/index.js";
|
|
21
24
|
import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js";
|
|
22
25
|
import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js";
|
|
23
26
|
import {toElectraSingleAttestation, validateApiAttestation} from "../../../../chain/validation/index.js";
|
|
24
27
|
import {validateApiPayloadAttestationMessage} from "../../../../chain/validation/payloadAttestationMessage.js";
|
|
28
|
+
import {validateGossipProposerPreferences} from "../../../../chain/validation/proposerPreferences.js";
|
|
25
29
|
import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js";
|
|
26
30
|
import {validateApiSyncCommittee} from "../../../../chain/validation/syncCommittee.js";
|
|
27
31
|
import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryExit.js";
|
|
@@ -81,6 +85,55 @@ export function getBeaconPoolApi({
|
|
|
81
85
|
return {data: chain.payloadAttestationPool.getAll(slot), meta: {version: fork}};
|
|
82
86
|
},
|
|
83
87
|
|
|
88
|
+
async getPoolProposerPreferences({slot}) {
|
|
89
|
+
const fork = chain.config.getForkName(slot ?? chain.clock.currentSlot);
|
|
90
|
+
if (!isForkPostGloas(fork)) {
|
|
91
|
+
throw new ApiError(400, `Proposer preferences pool is not supported before Gloas fork=${fork}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {data: chain.proposerPreferencesPool.getAll(slot), meta: {version: fork}};
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
async submitSignedProposerPreferences({signedProposerPreferences}) {
|
|
98
|
+
const failures: FailureList = [];
|
|
99
|
+
|
|
100
|
+
await Promise.all(
|
|
101
|
+
signedProposerPreferences.map(async (signed, i) => {
|
|
102
|
+
try {
|
|
103
|
+
await validateGossipProposerPreferences(chain, signed);
|
|
104
|
+
|
|
105
|
+
chain.proposerPreferencesPool.add(signed);
|
|
106
|
+
await network.publishProposerPreferences(signed);
|
|
107
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
108
|
+
version: ForkName.gloas,
|
|
109
|
+
data: signed,
|
|
110
|
+
});
|
|
111
|
+
} catch (e) {
|
|
112
|
+
const logCtx = {
|
|
113
|
+
slot: signed.message.proposalSlot,
|
|
114
|
+
validatorIndex: signed.message.validatorIndex,
|
|
115
|
+
dependentRoot: toRootHex(signed.message.dependentRoot),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
|
|
119
|
+
logger.debug("Ignoring known signed proposer preferences", logCtx);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
failures.push({index: i, message: (e as Error).message});
|
|
124
|
+
logger.verbose(`Error on submitSignedProposerPreferences [${i}]`, logCtx, e as Error);
|
|
125
|
+
if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
|
|
126
|
+
chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (failures.length > 0) {
|
|
133
|
+
throw new IndexedError("Error processing signed proposer preferences", failures);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
84
137
|
async getPoolAttesterSlashings() {
|
|
85
138
|
const fork = chain.config.getForkName(chain.clock.currentSlot);
|
|
86
139
|
|
|
@@ -258,7 +311,7 @@ export function getBeaconPoolApi({
|
|
|
258
311
|
try {
|
|
259
312
|
const validateFn = () => validateApiPayloadAttestationMessage(chain, payloadAttestationMessage);
|
|
260
313
|
const {slot, beaconBlockRoot} = payloadAttestationMessage.data;
|
|
261
|
-
const {attDataRootHex,
|
|
314
|
+
const {attDataRootHex, validatorCommitteeIndices} = await validateGossipFnRetryUnknownRoot(
|
|
262
315
|
validateFn,
|
|
263
316
|
network,
|
|
264
317
|
chain,
|
|
@@ -269,14 +322,16 @@ export function getBeaconPoolApi({
|
|
|
269
322
|
const insertOutcome = chain.payloadAttestationPool.add(
|
|
270
323
|
payloadAttestationMessage,
|
|
271
324
|
attDataRootHex,
|
|
272
|
-
|
|
325
|
+
validatorCommitteeIndices
|
|
273
326
|
);
|
|
274
327
|
metrics?.opPool.payloadAttestationPool.apiInsertOutcome.inc({insertOutcome});
|
|
275
328
|
|
|
276
329
|
chain.forkChoice.notifyPtcMessages(
|
|
277
330
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
278
|
-
|
|
279
|
-
|
|
331
|
+
payloadAttestationMessage.data.slot,
|
|
332
|
+
validatorCommitteeIndices,
|
|
333
|
+
payloadAttestationMessage.data.payloadPresent,
|
|
334
|
+
payloadAttestationMessage.data.blobDataAvailable
|
|
280
335
|
);
|
|
281
336
|
|
|
282
337
|
await network.publishPayloadAttestationMessage(payloadAttestationMessage);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
isForkPostBellatrix,
|
|
15
15
|
isForkPostDeneb,
|
|
16
16
|
isForkPostElectra,
|
|
17
|
+
isForkPostFulu,
|
|
17
18
|
isForkPostGloas,
|
|
18
19
|
} from "@lodestar/params";
|
|
19
20
|
import {
|
|
@@ -913,20 +914,40 @@ export function getValidatorApi(
|
|
|
913
914
|
notWhileSyncing();
|
|
914
915
|
await waitForSlot(slot);
|
|
915
916
|
|
|
916
|
-
// TODO GLOAS: support producing blocks from builder bids
|
|
917
|
-
const source = ProducedBlockSource.engine;
|
|
918
|
-
|
|
919
|
-
// TODO GLOAS: needs to be updated after fork choice changes are merged
|
|
920
917
|
const parentBlock = chain.getProposerHead(slot);
|
|
921
918
|
const {blockRoot: parentBlockRootHex, slot: parentSlot} = parentBlock;
|
|
922
919
|
const parentBlockRoot = fromHex(parentBlockRootHex);
|
|
923
920
|
notOnOutOfRangeData(parentBlockRoot);
|
|
924
921
|
metrics?.blockProductionSlotDelta.set(slot - parentSlot);
|
|
925
|
-
metrics?.blockProductionRequests.inc({source});
|
|
926
922
|
|
|
927
923
|
const graffitiBytes = toGraffitiBytes(
|
|
928
|
-
graffiti ?? getDefaultGraffiti(getLodestarClientVersion(), chain.executionEngine.clientVersion,
|
|
924
|
+
graffiti ?? getDefaultGraffiti(getLodestarClientVersion(opts), chain.executionEngine.clientVersion, opts)
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
// TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
|
|
928
|
+
// the user control bid source preferences and value comparison. Also add external builder api
|
|
929
|
+
// support when it is implemented.
|
|
930
|
+
const builderBid = chain.executionPayloadBidPool.getBestBid(
|
|
931
|
+
slot,
|
|
932
|
+
parentBlock.executionPayloadBlockHash,
|
|
933
|
+
parentBlockRootHex
|
|
929
934
|
);
|
|
935
|
+
|
|
936
|
+
const logCtx = {
|
|
937
|
+
slot,
|
|
938
|
+
parentSlot,
|
|
939
|
+
parentBlockRoot: parentBlockRootHex,
|
|
940
|
+
parentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
941
|
+
fork,
|
|
942
|
+
...(builderBid !== null
|
|
943
|
+
? {
|
|
944
|
+
bidValue: builderBid.message.value,
|
|
945
|
+
builderIndex: builderBid.message.builderIndex,
|
|
946
|
+
bidBlockHash: toRootHex(builderBid.message.blockHash),
|
|
947
|
+
}
|
|
948
|
+
: {}),
|
|
949
|
+
};
|
|
950
|
+
|
|
930
951
|
const commonBlockBodyPromise = chain.produceCommonBlockBody({
|
|
931
952
|
slot,
|
|
932
953
|
parentBlock,
|
|
@@ -934,44 +955,76 @@ export function getValidatorApi(
|
|
|
934
955
|
graffiti: graffitiBytes,
|
|
935
956
|
});
|
|
936
957
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
feeRecipient,
|
|
946
|
-
commonBlockBodyPromise,
|
|
947
|
-
});
|
|
958
|
+
const baseAttrs = {
|
|
959
|
+
slot,
|
|
960
|
+
parentBlock,
|
|
961
|
+
randaoReveal,
|
|
962
|
+
graffiti: graffitiBytes,
|
|
963
|
+
feeRecipient,
|
|
964
|
+
commonBlockBodyPromise,
|
|
965
|
+
};
|
|
948
966
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
metrics?.
|
|
952
|
-
|
|
967
|
+
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
|
|
968
|
+
if (builderBid !== null) {
|
|
969
|
+
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
|
|
970
|
+
}
|
|
953
971
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
972
|
+
const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
|
|
973
|
+
const t = metrics?.blockProductionTime.startTimer();
|
|
974
|
+
return fn().finally(() => t?.({source}));
|
|
975
|
+
};
|
|
976
|
+
|
|
977
|
+
// Always build local block. If builder bid available, also build with it in parallel and prefer it.
|
|
978
|
+
const [engineResult, bidResult] = await Promise.allSettled([
|
|
979
|
+
timed(ProducedBlockSource.engine, () => chain.produceBlock(baseAttrs)),
|
|
980
|
+
builderBid !== null
|
|
981
|
+
? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
|
|
982
|
+
: Promise.reject(),
|
|
983
|
+
]);
|
|
984
|
+
|
|
985
|
+
let bestResult: typeof engineResult | null = null;
|
|
986
|
+
let source: ProducedBlockSource = ProducedBlockSource.engine;
|
|
987
|
+
if (builderBid !== null && bidResult.status === "fulfilled") {
|
|
988
|
+
source = ProducedBlockSource.builder;
|
|
989
|
+
bestResult = bidResult;
|
|
990
|
+
logger.info("Selected builder bid block", logCtx);
|
|
991
|
+
} else if (engineResult.status === "fulfilled") {
|
|
992
|
+
source = ProducedBlockSource.engine;
|
|
993
|
+
bestResult = engineResult;
|
|
994
|
+
if (builderBid !== null) {
|
|
995
|
+
logger.warn("Builder bid block production failed, using local block", logCtx);
|
|
963
996
|
}
|
|
997
|
+
}
|
|
964
998
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}
|
|
973
|
-
|
|
999
|
+
if (bestResult === null || bestResult.status !== "fulfilled") {
|
|
1000
|
+
const engineReason = engineResult.status === "rejected" ? engineResult.reason : undefined;
|
|
1001
|
+
const bidReason = builderBid !== null && bidResult.status === "rejected" ? bidResult.reason : undefined;
|
|
1002
|
+
logger.error("Block production failed", {...logCtx, engineReason, bidReason});
|
|
1003
|
+
throw Error(`Block production failed: engine=${engineReason ?? "n/a"} builder=${bidReason ?? "n/a"}`);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
const {block, executionPayloadValue, consensusBlockValue} = bestResult.value;
|
|
1007
|
+
|
|
1008
|
+
metrics?.blockProductionSuccess.inc({source});
|
|
1009
|
+
metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length);
|
|
1010
|
+
metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue)));
|
|
1011
|
+
metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue)));
|
|
1012
|
+
|
|
1013
|
+
const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block));
|
|
1014
|
+
logger.verbose("Produced block", {
|
|
1015
|
+
...logCtx,
|
|
1016
|
+
executionPayloadValue,
|
|
1017
|
+
consensusBlockValue,
|
|
1018
|
+
root: blockRoot,
|
|
1019
|
+
});
|
|
1020
|
+
if (chain.opts.persistProducedBlocks) {
|
|
1021
|
+
void chain.persistBlock(block, "produced_engine_block");
|
|
974
1022
|
}
|
|
1023
|
+
|
|
1024
|
+
return {
|
|
1025
|
+
data: block as gloas.BeaconBlock,
|
|
1026
|
+
meta: {version: fork, consensusBlockValue},
|
|
1027
|
+
};
|
|
975
1028
|
},
|
|
976
1029
|
|
|
977
1030
|
async produceAttestationData({committeeIndex, slot}) {
|
|
@@ -1059,15 +1112,21 @@ export function getValidatorApi(
|
|
|
1059
1112
|
notWhileSyncing();
|
|
1060
1113
|
await waitForSlot(slot);
|
|
1061
1114
|
|
|
1062
|
-
const block = chain.forkChoice.
|
|
1115
|
+
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
1063
1116
|
if (!block) {
|
|
1064
|
-
|
|
1117
|
+
// No block is seen at slot. Return 404 so vc can skip casting payload attestation.
|
|
1118
|
+
throw new ApiError(404, `No canonical block found at slot=${slot}`);
|
|
1065
1119
|
}
|
|
1066
1120
|
|
|
1067
|
-
const blockIsForSlot = block.slot === slot;
|
|
1068
1121
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
1069
|
-
|
|
1070
|
-
|
|
1122
|
+
// Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
|
|
1123
|
+
// into the slot. Use the envelope's own arrival time (getPayloadEnvelopeSource), not
|
|
1124
|
+
// the input's creation time.
|
|
1125
|
+
const payloadDueSec = config.getPayloadDueMs() / 1000;
|
|
1126
|
+
const payloadPresent =
|
|
1127
|
+
payloadInput?.hasPayloadEnvelope() === true &&
|
|
1128
|
+
chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec) < payloadDueSec;
|
|
1129
|
+
const blobDataAvailable = payloadInput?.hasAllData() === true;
|
|
1071
1130
|
|
|
1072
1131
|
return {
|
|
1073
1132
|
data: {
|
|
@@ -1124,26 +1183,33 @@ export function getValidatorApi(
|
|
|
1124
1183
|
async getProposerDuties({epoch}, _context, opts?: {v2?: boolean}) {
|
|
1125
1184
|
notWhileSyncing();
|
|
1126
1185
|
|
|
1127
|
-
// Early check that epoch is no more than current_epoch + 1, or allow for pre-genesis
|
|
1128
1186
|
const currentEpoch = currentEpochWithDisparity();
|
|
1129
1187
|
const nextEpoch = currentEpoch + 1;
|
|
1130
|
-
|
|
1188
|
+
const startSlot = computeStartSlotAtEpoch(epoch);
|
|
1189
|
+
const prepareNextSlotLookAheadMs =
|
|
1190
|
+
config.SLOT_DURATION_MS - config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS);
|
|
1191
|
+
const toNextEpochMs = msToNextEpoch();
|
|
1192
|
+
const nearNextEpoch = toNextEpochMs < prepareNextSlotLookAheadMs;
|
|
1193
|
+
// Post-Fulu the proposer lookahead is deterministic and known a full epoch ahead, so
|
|
1194
|
+
// close to the boundary `currentEpoch + 2` is serveable from the upcoming-epoch
|
|
1195
|
+
// checkpoint state (its `nextProposers`). Pre-Fulu / mid-epoch: `currentEpoch + 1` max.
|
|
1196
|
+
const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
|
|
1197
|
+
const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
|
|
1198
|
+
if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
|
|
1131
1199
|
throw new ApiError(400, `Requested epoch ${epoch} must not be more than one epoch in the future`);
|
|
1132
1200
|
}
|
|
1133
1201
|
|
|
1134
1202
|
const head = chain.forkChoice.getHead();
|
|
1135
1203
|
let state: IBeaconStateView | undefined = undefined;
|
|
1136
|
-
const startSlot = computeStartSlotAtEpoch(epoch);
|
|
1137
|
-
const prepareNextSlotLookAheadMs =
|
|
1138
|
-
config.SLOT_DURATION_MS - config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS);
|
|
1139
|
-
const toNextEpochMs = msToNextEpoch();
|
|
1140
1204
|
// validators may request next epoch's duties when it's close to next epoch
|
|
1141
|
-
// this is to avoid missed block proposal due to 0 epoch look ahead
|
|
1142
|
-
|
|
1205
|
+
// this is to avoid missed block proposal due to 0 epoch look ahead.
|
|
1206
|
+
// Post-Fulu, `nextEpoch + 1` is served from the same upcoming-epoch (`nextEpoch`)
|
|
1207
|
+
// checkpoint state via its `nextProposers` (deterministic proposer lookahead).
|
|
1208
|
+
if (nearNextEpoch && (epoch === nextEpoch || (isPostFulu && epoch === nextEpoch + 1))) {
|
|
1143
1209
|
// wait for maximum 1 slot for cp state which is the timeout of validator api
|
|
1144
1210
|
const cpState = await waitForCheckpointState({
|
|
1145
1211
|
rootHex: head.blockRoot,
|
|
1146
|
-
epoch,
|
|
1212
|
+
epoch: nextEpoch,
|
|
1147
1213
|
});
|
|
1148
1214
|
if (cpState) {
|
|
1149
1215
|
state = cpState;
|
|
@@ -1218,7 +1284,7 @@ export function getValidatorApi(
|
|
|
1218
1284
|
// It should be set to the latest block applied to `self` or the genesis block root.
|
|
1219
1285
|
const dependentRoot =
|
|
1220
1286
|
// In v2 the dependent root is different after fulu due to deterministic proposer lookahead
|
|
1221
|
-
proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state) ||
|
|
1287
|
+
proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state, epoch) ||
|
|
1222
1288
|
(await getGenesisBlockRoot(state));
|
|
1223
1289
|
|
|
1224
1290
|
return {
|
|
@@ -116,13 +116,19 @@ export async function importBlock(
|
|
|
116
116
|
}
|
|
117
117
|
executionStatus = parentBlock.executionStatus;
|
|
118
118
|
}
|
|
119
|
+
|
|
120
|
+
// getBeaconProposerOrNull will return null if head state is more than one epoch away
|
|
121
|
+
// from block slot. We skip proposer boost canonical check as we cannot determine the canonical proposer
|
|
122
|
+
const expectedProposerIndex: number | null = this.getHeadState().getBeaconProposerOrNull(blockSlot);
|
|
123
|
+
|
|
119
124
|
const blockSummary = this.forkChoice.onBlock(
|
|
120
125
|
block.message,
|
|
121
126
|
postState,
|
|
122
127
|
blockDelaySec,
|
|
123
128
|
currentSlot,
|
|
124
129
|
executionStatus,
|
|
125
|
-
dataAvailabilityStatus
|
|
130
|
+
dataAvailabilityStatus,
|
|
131
|
+
expectedProposerIndex
|
|
126
132
|
);
|
|
127
133
|
|
|
128
134
|
// This adds the state necessary to process the next block
|
|
@@ -257,8 +263,10 @@ export async function importBlock(
|
|
|
257
263
|
if (ptcIndices.length > 0) {
|
|
258
264
|
this.forkChoice.notifyPtcMessages(
|
|
259
265
|
toRootHex(payloadAttestation.data.beaconBlockRoot),
|
|
266
|
+
payloadAttestation.data.slot,
|
|
260
267
|
ptcIndices,
|
|
261
|
-
payloadAttestation.data.payloadPresent
|
|
268
|
+
payloadAttestation.data.payloadPresent,
|
|
269
|
+
payloadAttestation.data.blobDataAvailable
|
|
262
270
|
);
|
|
263
271
|
}
|
|
264
272
|
} catch (e) {
|
|
@@ -129,7 +129,7 @@ export async function importExecutionPayload(
|
|
|
129
129
|
|
|
130
130
|
// 3. Regenerate state for envelope verification
|
|
131
131
|
const blockState = await this.regen
|
|
132
|
-
.getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.
|
|
132
|
+
.getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.importExecutionPayload)
|
|
133
133
|
.catch(() =>
|
|
134
134
|
// only happen at the 1st batch of skipped slot checkpoint sync
|
|
135
135
|
this.regen.getClosestHeadState(protoBlock)
|
|
@@ -237,6 +237,7 @@ export async function importExecutionPayload(
|
|
|
237
237
|
blockRootHex,
|
|
238
238
|
blockHashHex,
|
|
239
239
|
envelope.payload.blockNumber,
|
|
240
|
+
envelope.payload.gasLimit,
|
|
240
241
|
execStatus,
|
|
241
242
|
dataAvailabilityStatus
|
|
242
243
|
);
|
|
@@ -254,7 +255,11 @@ export async function importExecutionPayload(
|
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
// 8. Record metrics for payload envelope and column sources
|
|
257
|
-
this.
|
|
258
|
+
const delaySec = this.clock.secFromSlot(slot);
|
|
259
|
+
this.metrics?.importPayload.elapsedTimeTillImported.observe(
|
|
260
|
+
{source: payloadInput.getPayloadEnvelopeSource().source},
|
|
261
|
+
delaySec
|
|
262
|
+
);
|
|
258
263
|
for (const {source} of payloadInput.getSampledColumnsWithSource()) {
|
|
259
264
|
this.metrics?.importPayload.columnsBySource.inc({source});
|
|
260
265
|
}
|
|
@@ -275,6 +280,7 @@ export async function importExecutionPayload(
|
|
|
275
280
|
builderIndex: envelope.builderIndex,
|
|
276
281
|
blockRoot: blockRootHex,
|
|
277
282
|
blockHash: blockHashHex,
|
|
283
|
+
delaySec,
|
|
278
284
|
});
|
|
279
285
|
}
|
|
280
286
|
|
package/src/chain/chain.ts
CHANGED
|
@@ -88,6 +88,7 @@ import {
|
|
|
88
88
|
ExecutionPayloadBidPool,
|
|
89
89
|
OpPool,
|
|
90
90
|
PayloadAttestationPool,
|
|
91
|
+
ProposerPreferencesPool,
|
|
91
92
|
SyncCommitteeMessagePool,
|
|
92
93
|
SyncContributionAndProofPool,
|
|
93
94
|
} from "./opPools/index.js";
|
|
@@ -180,6 +181,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
180
181
|
readonly syncContributionAndProofPool;
|
|
181
182
|
readonly executionPayloadBidPool: ExecutionPayloadBidPool;
|
|
182
183
|
readonly payloadAttestationPool: PayloadAttestationPool;
|
|
184
|
+
readonly proposerPreferencesPool = new ProposerPreferencesPool();
|
|
183
185
|
readonly opPool: OpPool;
|
|
184
186
|
|
|
185
187
|
// Gossip seen cache
|
|
@@ -1047,6 +1049,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1047
1049
|
feeRecipient,
|
|
1048
1050
|
commonBlockBodyPromise,
|
|
1049
1051
|
parentBlock,
|
|
1052
|
+
builderBid,
|
|
1050
1053
|
}: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}
|
|
1051
1054
|
): Promise<{
|
|
1052
1055
|
block: AssembledBlockType<T>;
|
|
@@ -1076,6 +1079,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1076
1079
|
proposerIndex,
|
|
1077
1080
|
proposerPubKey,
|
|
1078
1081
|
commonBlockBodyPromise,
|
|
1082
|
+
builderBid,
|
|
1079
1083
|
}
|
|
1080
1084
|
);
|
|
1081
1085
|
|
|
@@ -1462,6 +1466,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1462
1466
|
this.executionPayloadBidPool.prune(slot);
|
|
1463
1467
|
this.seenExecutionPayloadBids.prune(slot);
|
|
1464
1468
|
this.seenProposerPreferences.prune(slot);
|
|
1469
|
+
this.proposerPreferencesPool.prune(slot);
|
|
1465
1470
|
this.seenAttestationDatas.onSlot(slot);
|
|
1466
1471
|
this.reprocessController.onSlot(slot);
|
|
1467
1472
|
|
|
@@ -9,8 +9,13 @@ export enum ExecutionPayloadBidErrorCode {
|
|
|
9
9
|
BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
|
|
10
10
|
TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
11
11
|
UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
|
|
12
|
+
UNKNOWN_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_PARENT_BLOCK_HASH",
|
|
12
13
|
INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
|
|
14
|
+
NOT_LATER_THAN_PARENT = "EXECUTION_PAYLOAD_BID_ERROR_NOT_LATER_THAN_PARENT",
|
|
13
15
|
INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
|
|
16
|
+
NO_MATCHING_PROPOSER_PREFERENCES = "EXECUTION_PAYLOAD_BID_ERROR_NO_MATCHING_PROPOSER_PREFERENCES",
|
|
17
|
+
PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH",
|
|
18
|
+
PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH",
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export type ExecutionPayloadBidErrorType =
|
|
@@ -35,7 +40,28 @@ export type ExecutionPayloadBidErrorType =
|
|
|
35
40
|
commitmentLimit: number;
|
|
36
41
|
}
|
|
37
42
|
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
|
|
43
|
+
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
|
|
38
44
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
|
|
39
|
-
| {code: ExecutionPayloadBidErrorCode.
|
|
45
|
+
| {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
|
|
46
|
+
| {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot}
|
|
47
|
+
| {
|
|
48
|
+
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES;
|
|
49
|
+
slot: Slot;
|
|
50
|
+
parentBlockRoot: RootHex;
|
|
51
|
+
dependentRoot: RootHex;
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH;
|
|
55
|
+
builderIndex: BuilderIndex;
|
|
56
|
+
bidFeeRecipient: string;
|
|
57
|
+
expectedFeeRecipient: string;
|
|
58
|
+
}
|
|
59
|
+
| {
|
|
60
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH;
|
|
61
|
+
builderIndex: BuilderIndex;
|
|
62
|
+
bidGasLimit: number;
|
|
63
|
+
parentGasLimit: number;
|
|
64
|
+
targetGasLimit: number;
|
|
65
|
+
};
|
|
40
66
|
|
|
41
67
|
export class ExecutionPayloadBidError extends GossipActionError<ExecutionPayloadBidErrorType> {}
|
|
@@ -140,9 +140,11 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
140
140
|
executionPayloadBlockHash: isStatePostGloas(state)
|
|
141
141
|
? toRootHex(state.latestBlockHash)
|
|
142
142
|
: toRootHex(state.latestExecutionPayloadHeader.blockHash),
|
|
143
|
-
// TODO GLOAS: executionPayloadNumber
|
|
144
|
-
// latestExecutionPayloadHeader). Using 0 as unavailable fallback
|
|
143
|
+
// TODO GLOAS: executionPayloadNumber/GasLimit are not tracked in BeaconState post-gloas
|
|
144
|
+
// (EIP-7732 removed latestExecutionPayloadHeader). Using 0 as unavailable fallback —
|
|
145
|
+
// see initializeForkChoiceFromUnfinalizedState for the same caveat on validation.
|
|
145
146
|
executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber,
|
|
147
|
+
executionPayloadGasLimit: isStatePostGloas(state) ? 0 : state.latestExecutionPayloadHeader.gasLimit,
|
|
146
148
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
147
149
|
}
|
|
148
150
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
@@ -232,9 +234,17 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
232
234
|
executionPayloadBlockHash: isStatePostGloas(unfinalizedState)
|
|
233
235
|
? toRootHex(unfinalizedState.latestBlockHash)
|
|
234
236
|
: toRootHex(unfinalizedState.latestExecutionPayloadHeader.blockHash),
|
|
235
|
-
// TODO GLOAS: executionPayloadNumber
|
|
236
|
-
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until
|
|
237
|
+
// TODO GLOAS: executionPayloadNumber/GasLimit are not tracked in BeaconState post-gloas
|
|
238
|
+
// (EIP-7732 removed latestExecutionPayloadHeader). Using 0 as unavailable fallback until
|
|
239
|
+
// a solution is found. The 0 doesn't gate validation in practice: at boot the head's
|
|
240
|
+
// PENDING variant's `executionPayloadBlockHash` is the *parent's* payload hash (per the
|
|
241
|
+
// PENDING/EMPTY convention), so gossip bids that reference the head's *own* payload
|
|
242
|
+
// hash won't match this variant anyway and will IGNORE until `onExecutionPayload`
|
|
243
|
+
// upgrades the head to FULL with real values.
|
|
237
244
|
executionPayloadNumber: isStatePostGloas(unfinalizedState) ? 0 : unfinalizedState.payloadBlockNumber,
|
|
245
|
+
executionPayloadGasLimit: isStatePostGloas(unfinalizedState)
|
|
246
|
+
? 0
|
|
247
|
+
: unfinalizedState.latestExecutionPayloadHeader.gasLimit,
|
|
238
248
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
239
249
|
}
|
|
240
250
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|