@lodestar/beacon-node 1.44.0-dev.1d0e0b9081 → 1.44.0-dev.2defe36dd3
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 +1 -1
- 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 +82 -44
- 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 +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +2 -1
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +11 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +2 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/payloadAttestation.d.ts +6 -0
- package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
- package/lib/chain/errors/payloadAttestation.js +1 -0
- package/lib/chain/errors/payloadAttestation.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/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/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 +3 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +78 -24
- 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 +58 -15
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +24 -4
- 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/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/interface.d.ts +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +5 -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 +12 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/blocks/index.ts +36 -0
- package/src/api/impl/beacon/pool/index.ts +3 -1
- package/src/api/impl/validator/index.ts +95 -45
- package/src/chain/blocks/importBlock.ts +10 -2
- package/src/chain/blocks/importExecutionPayload.ts +8 -2
- package/src/chain/chain.ts +2 -0
- package/src/chain/errors/executionPayloadBid.ts +6 -1
- package/src/chain/errors/payloadAttestation.ts +2 -0
- package/src/chain/forkChoice/index.ts +14 -4
- package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
- package/src/chain/prepareNextSlot.ts +2 -1
- package/src/chain/produceBlock/produceBlockBody.ts +108 -34
- package/src/chain/regen/interface.ts +2 -0
- package/src/chain/validation/executionPayloadBid.ts +66 -19
- package/src/chain/validation/payloadAttestationMessage.ts +26 -4
- package/src/chain/validatorMonitor.ts +18 -0
- package/src/execution/builder/index.ts +1 -4
- package/src/metrics/metrics/lodestar.ts +4 -3
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +17 -4
- 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
|
@@ -18,9 +18,9 @@ import {
|
|
|
18
18
|
G2_POINT_AT_INFINITY,
|
|
19
19
|
IBeaconStateView,
|
|
20
20
|
type IBeaconStateViewBellatrix,
|
|
21
|
-
type IBeaconStateViewGloas,
|
|
22
21
|
computeEpochAtSlot,
|
|
23
22
|
computeTimeAtSlot,
|
|
23
|
+
getExpectedGasLimit,
|
|
24
24
|
isStatePostBellatrix,
|
|
25
25
|
isStatePostCapella,
|
|
26
26
|
isStatePostGloas,
|
|
@@ -50,16 +50,10 @@ import {
|
|
|
50
50
|
gloas,
|
|
51
51
|
ssz,
|
|
52
52
|
} from "@lodestar/types";
|
|
53
|
-
import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
53
|
+
import {GWEI_TO_WEI, Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
54
54
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
55
55
|
import {numToQuantity} from "../../execution/engine/utils.js";
|
|
56
|
-
import {
|
|
57
|
-
IExecutionBuilder,
|
|
58
|
-
IExecutionEngine,
|
|
59
|
-
PayloadAttributes,
|
|
60
|
-
PayloadId,
|
|
61
|
-
getExpectedGasLimit,
|
|
62
|
-
} from "../../execution/index.js";
|
|
56
|
+
import {IExecutionBuilder, IExecutionEngine, PayloadAttributes, PayloadId} from "../../execution/index.js";
|
|
63
57
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
64
58
|
import {fromGraffitiBytes} from "../../util/graffiti.js";
|
|
65
59
|
import {kzg} from "../../util/kzg.js";
|
|
@@ -97,6 +91,8 @@ export type BlockAttributes = {
|
|
|
97
91
|
slot: Slot;
|
|
98
92
|
parentBlock: ProtoBlock;
|
|
99
93
|
feeRecipient?: string;
|
|
94
|
+
/** When provided, build block with this builder bid instead of a self-build bid */
|
|
95
|
+
builderBid?: gloas.SignedExecutionPayloadBid;
|
|
100
96
|
};
|
|
101
97
|
|
|
102
98
|
export enum BlockType {
|
|
@@ -156,6 +152,28 @@ export type ProduceResult =
|
|
|
156
152
|
| ProduceFullPhase0
|
|
157
153
|
| ProduceBlinded;
|
|
158
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Drop voluntary exits that `parent_execution_requests` have invalidated (e.g. a withdrawal
|
|
157
|
+
* request initiating an exit on the same validator). Op pool selected against the unapplied
|
|
158
|
+
* state, so re-validate against the post-apply state to avoid producing an invalid block.
|
|
159
|
+
*
|
|
160
|
+
* `getStateAfterParentPayload` is a thunk so the post-apply state is only materialized when
|
|
161
|
+
* actually needed (i.e. when extending the parent payload and there are exits to filter).
|
|
162
|
+
*/
|
|
163
|
+
function maybeFilterInvalidatedVoluntaryExits(
|
|
164
|
+
commonBlockBody: CommonBlockBody,
|
|
165
|
+
isExtendingPayload: boolean,
|
|
166
|
+
getStateAfterParentPayload: () => IBeaconStateViewBellatrix
|
|
167
|
+
): CommonBlockBody["voluntaryExits"] {
|
|
168
|
+
if (!isExtendingPayload || commonBlockBody.voluntaryExits.length === 0) {
|
|
169
|
+
return commonBlockBody.voluntaryExits;
|
|
170
|
+
}
|
|
171
|
+
const state = getStateAfterParentPayload();
|
|
172
|
+
return commonBlockBody.voluntaryExits.filter((signedVoluntaryExit) =>
|
|
173
|
+
state.isValidVoluntaryExit(signedVoluntaryExit, false)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
159
177
|
export async function produceBlockBody<T extends BlockType>(
|
|
160
178
|
this: BeaconChain,
|
|
161
179
|
blockType: T,
|
|
@@ -178,6 +196,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
178
196
|
proposerIndex,
|
|
179
197
|
proposerPubKey,
|
|
180
198
|
commonBlockBodyPromise,
|
|
199
|
+
builderBid,
|
|
181
200
|
} = blockAttr;
|
|
182
201
|
let executionPayloadValue: Wei;
|
|
183
202
|
let blockBody: AssembledBodyType<T>;
|
|
@@ -198,7 +217,43 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
198
217
|
};
|
|
199
218
|
this.logger.verbose("Producing beacon block body", logMeta);
|
|
200
219
|
|
|
201
|
-
if (
|
|
220
|
+
if (builderBid !== undefined) {
|
|
221
|
+
if (!isStatePostGloas(currentState)) {
|
|
222
|
+
throw new Error("Expected Gloas state for builder bid block production");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const isExtendingPayload = byteArrayEquals(
|
|
226
|
+
builderBid.message.parentBlockHash,
|
|
227
|
+
currentState.latestExecutionPayloadBid.blockHash
|
|
228
|
+
);
|
|
229
|
+
const parentExecutionRequests = isExtendingPayload
|
|
230
|
+
? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
|
|
231
|
+
: ssz.electra.ExecutionRequests.defaultValue();
|
|
232
|
+
executionPayloadValue = BigInt(builderBid.message.value) * GWEI_TO_WEI;
|
|
233
|
+
|
|
234
|
+
const commonBlockBody = await commonBlockBodyPromise;
|
|
235
|
+
const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
|
|
236
|
+
gloasBody.signedExecutionPayloadBid = builderBid;
|
|
237
|
+
gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
|
|
238
|
+
parentBlock.blockRoot,
|
|
239
|
+
blockSlot - 1
|
|
240
|
+
);
|
|
241
|
+
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
242
|
+
gloasBody.voluntaryExits = maybeFilterInvalidatedVoluntaryExits(commonBlockBody, isExtendingPayload, () =>
|
|
243
|
+
currentState.withParentPayloadApplied(parentExecutionRequests)
|
|
244
|
+
);
|
|
245
|
+
blockBody = gloasBody as AssembledBodyType<T>;
|
|
246
|
+
|
|
247
|
+
this.logger.verbose("Produced block with builder bid", {
|
|
248
|
+
slot: blockSlot,
|
|
249
|
+
builderIndex: builderBid.message.builderIndex,
|
|
250
|
+
bidValue: builderBid.message.value,
|
|
251
|
+
parentBlockHash: toRootHex(builderBid.message.parentBlockHash),
|
|
252
|
+
parentBlockRoot: toRootHex(builderBid.message.parentBlockRoot),
|
|
253
|
+
blockHash: toRootHex(builderBid.message.blockHash),
|
|
254
|
+
isExtendingPayload,
|
|
255
|
+
});
|
|
256
|
+
} else if (isForkPostGloas(fork)) {
|
|
202
257
|
if (!isStatePostGloas(currentState)) {
|
|
203
258
|
throw new Error("Expected Gloas state for Gloas block production");
|
|
204
259
|
}
|
|
@@ -215,19 +270,16 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
215
270
|
|
|
216
271
|
const endExecutionPayload = this.metrics?.executionBlockProductionTimeSteps.startTimer();
|
|
217
272
|
|
|
218
|
-
this.logger.verbose("Preparing execution payload from engine", {
|
|
219
|
-
slot: blockSlot,
|
|
220
|
-
parentBlockRoot: toRootHex(parentBlockRoot),
|
|
221
|
-
feeRecipient,
|
|
222
|
-
});
|
|
223
|
-
|
|
224
273
|
// Get execution payload from EL
|
|
225
274
|
let parentBlockHash: Bytes32;
|
|
226
275
|
let parentExecutionRequests: electra.ExecutionRequests;
|
|
227
276
|
// Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
|
|
228
277
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
|
|
229
|
-
|
|
230
|
-
|
|
278
|
+
// Spec: should_build_on_full(store, head). `parentBlock` is the proposer's head
|
|
279
|
+
// (set by chain.getProposerHead(slot)). Returns false when the PTC majority
|
|
280
|
+
// signalled the blob data is not available, forcing a build on EMPTY (reorg).
|
|
281
|
+
const isBuildingOnFull = this.forkChoice.shouldBuildOnFull(parentBlock, blockSlot);
|
|
282
|
+
if (isBuildingOnFull) {
|
|
231
283
|
parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
|
|
232
284
|
parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
|
|
233
285
|
stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
|
|
@@ -250,6 +302,16 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
250
302
|
const {prepType, payloadId} = prepareRes;
|
|
251
303
|
Object.assign(logMeta, {executionPayloadPrepType: prepType});
|
|
252
304
|
|
|
305
|
+
this.logger.verbose("Prepared execution payload from engine", {
|
|
306
|
+
slot: blockSlot,
|
|
307
|
+
parentBlockRoot: toRootHex(parentBlockRoot),
|
|
308
|
+
parentBlockHash: toRootHex(parentBlockHash),
|
|
309
|
+
feeRecipient,
|
|
310
|
+
prepType,
|
|
311
|
+
payloadId,
|
|
312
|
+
isBuildingOnFull,
|
|
313
|
+
});
|
|
314
|
+
|
|
253
315
|
if (prepType !== PayloadPreparationType.Cached) {
|
|
254
316
|
await sleep(PAYLOAD_GENERATION_TIME_MS);
|
|
255
317
|
}
|
|
@@ -303,14 +365,11 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
303
365
|
blockSlot - 1
|
|
304
366
|
);
|
|
305
367
|
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
stateAfterParentPayload.isValidVoluntaryExit(signedVoluntaryExit, false)
|
|
312
|
-
);
|
|
313
|
-
}
|
|
368
|
+
gloasBody.voluntaryExits = maybeFilterInvalidatedVoluntaryExits(
|
|
369
|
+
commonBlockBody,
|
|
370
|
+
isBuildingOnFull,
|
|
371
|
+
() => stateAfterParentPayload
|
|
372
|
+
);
|
|
314
373
|
blockBody = gloasBody as AssembledBodyType<T>;
|
|
315
374
|
|
|
316
375
|
// Store execution payload data required to construct execution payload envelope later
|
|
@@ -331,6 +390,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
331
390
|
fetchedTime,
|
|
332
391
|
executionBlockHash: toRootHex(executionPayload.blockHash),
|
|
333
392
|
blobs: blobsBundle.commitments.length,
|
|
393
|
+
gasLimit: executionPayload.gasLimit,
|
|
334
394
|
});
|
|
335
395
|
|
|
336
396
|
Object.assign(logMeta, {
|
|
@@ -869,9 +929,9 @@ function preparePayloadAttributes(
|
|
|
869
929
|
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
870
930
|
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).targetGasLimit = getProposerTargetGasLimit(
|
|
871
931
|
chain,
|
|
872
|
-
prepareState,
|
|
873
932
|
prepareSlot,
|
|
874
|
-
parentBlockRoot
|
|
933
|
+
parentBlockRoot,
|
|
934
|
+
parentBlockHash
|
|
875
935
|
);
|
|
876
936
|
}
|
|
877
937
|
|
|
@@ -886,14 +946,20 @@ function preparePayloadAttributes(
|
|
|
886
946
|
* (same `(slot, dependent_root)` lookup as gossip bid validation). When no matching
|
|
887
947
|
* preferences are pooled, target the parent payload's gas limit so the gas limit stays
|
|
888
948
|
* unchanged (`is_gas_limit_target_compatible` then requires `gas_limit == parent_gas_limit`).
|
|
949
|
+
*
|
|
950
|
+
* The parent payload's gas_limit is read from fork choice — the variant matching
|
|
951
|
+
* `(parentBlockRoot, parentBlockHash)` carries the correct value for both FULL parents
|
|
952
|
+
* (FULL.executionPayloadGasLimit = delivered payload's gas_limit) and EMPTY parents
|
|
953
|
+
* (EMPTY.executionPayloadGasLimit = inherited grandparent's gas_limit).
|
|
889
954
|
*/
|
|
890
955
|
function getProposerTargetGasLimit(
|
|
891
956
|
chain: {forkChoice: IForkChoice; proposerPreferencesPool: ProposerPreferencesPool},
|
|
892
|
-
state: IBeaconStateViewGloas,
|
|
893
957
|
prepareSlot: Slot,
|
|
894
|
-
parentBlockRoot: Root
|
|
958
|
+
parentBlockRoot: Root,
|
|
959
|
+
parentBlockHash: Bytes32
|
|
895
960
|
): number {
|
|
896
|
-
const
|
|
961
|
+
const parentBlockRootHex = toRootHex(parentBlockRoot);
|
|
962
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
|
|
897
963
|
const dependentRootHex = (() => {
|
|
898
964
|
if (parentBlock === null) {
|
|
899
965
|
return null;
|
|
@@ -911,9 +977,17 @@ function getProposerTargetGasLimit(
|
|
|
911
977
|
})();
|
|
912
978
|
|
|
913
979
|
const pref = dependentRootHex !== null ? chain.proposerPreferencesPool.get(prepareSlot, dependentRootHex) : null;
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
980
|
+
if (pref !== null) {
|
|
981
|
+
return pref.message.targetGasLimit;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, toRootHex(parentBlockHash));
|
|
985
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
986
|
+
throw new Error(
|
|
987
|
+
`Cannot resolve parent payload gas_limit for proposer targetGasLimit fallback parentBlockRoot=${parentBlockRootHex} parentBlockHash=${toRootHex(parentBlockHash)}`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
return parentPayloadVariant.executionPayloadGasLimit;
|
|
917
991
|
}
|
|
918
992
|
|
|
919
993
|
export async function produceCommonBlockBody<T extends BlockType>(
|
|
@@ -17,10 +17,12 @@ export enum RegenCaller {
|
|
|
17
17
|
predictProposerHead = "predictProposerHead",
|
|
18
18
|
produceAttestationData = "produceAttestationData",
|
|
19
19
|
processBlocksInEpoch = "processBlocksInEpoch",
|
|
20
|
+
importExecutionPayload = "importExecutionPayload",
|
|
20
21
|
validateGossipAggregateAndProof = "validateGossipAggregateAndProof",
|
|
21
22
|
validateGossipAttestation = "validateGossipAttestation",
|
|
22
23
|
validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
|
|
23
24
|
validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
|
|
25
|
+
validateGossipPayloadAttestationMessage = "validateGossipPayloadAttestationMessage",
|
|
24
26
|
validateGossipProposerPreferences = "validateGossipProposerPreferences",
|
|
25
27
|
onForkChoiceFinalized = "onForkChoiceFinalized",
|
|
26
28
|
restApi = "restApi",
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
createSingleSignatureSetFromComponents,
|
|
5
5
|
getExecutionPayloadBidSigningRoot,
|
|
6
6
|
isActiveBuilder,
|
|
7
|
+
isGasLimitTargetCompatible,
|
|
7
8
|
isStatePostGloas,
|
|
8
9
|
} from "@lodestar/state-transition";
|
|
9
|
-
import {gloas} from "@lodestar/types";
|
|
10
|
+
import {ValidatorIndex, gloas} from "@lodestar/types";
|
|
10
11
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
11
12
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
12
13
|
import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
|
|
@@ -16,28 +17,24 @@ import {RegenCaller} from "../regen/index.js";
|
|
|
16
17
|
export async function validateApiExecutionPayloadBid(
|
|
17
18
|
chain: IBeaconChain,
|
|
18
19
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
19
|
-
): Promise<
|
|
20
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
20
21
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export async function validateGossipExecutionPayloadBid(
|
|
24
25
|
chain: IBeaconChain,
|
|
25
26
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
26
|
-
): Promise<
|
|
27
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
27
28
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
async function validateExecutionPayloadBid(
|
|
31
32
|
chain: IBeaconChain,
|
|
32
33
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
33
|
-
): Promise<
|
|
34
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
34
35
|
const bid = signedExecutionPayloadBid.message;
|
|
35
36
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
36
37
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
37
|
-
const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.validateGossipExecutionPayloadBid);
|
|
38
|
-
if (!isStatePostGloas(state)) {
|
|
39
|
-
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
40
|
-
}
|
|
41
38
|
|
|
42
39
|
// [IGNORE] `bid.slot` is the current slot or the next slot.
|
|
43
40
|
const currentSlot = chain.clock.currentSlot;
|
|
@@ -60,6 +57,17 @@ async function validateExecutionPayloadBid(
|
|
|
60
57
|
});
|
|
61
58
|
}
|
|
62
59
|
|
|
60
|
+
// [REJECT] The bid is for a higher slot than its parent block -- i.e.
|
|
61
|
+
// validate that `bid.slot` is greater than the slot of the block with root
|
|
62
|
+
// `bid.parent_block_root`.
|
|
63
|
+
if (bid.slot <= parentBlock.slot) {
|
|
64
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
65
|
+
code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT,
|
|
66
|
+
parentSlot: parentBlock.slot,
|
|
67
|
+
slot: bid.slot,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
// [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
|
|
64
72
|
// seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
|
|
65
73
|
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`.
|
|
@@ -99,9 +107,31 @@ async function validateExecutionPayloadBid(
|
|
|
99
107
|
});
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
// Use the bid's parent branch state for builder checks
|
|
111
|
+
const state = await chain.regen
|
|
112
|
+
.getBlockSlotState(parentBlock, bid.slot, {dontTransferCache: true}, RegenCaller.validateGossipExecutionPayloadBid)
|
|
113
|
+
.catch(() => {
|
|
114
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
115
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
116
|
+
parentBlockRoot: parentBlockRootHex,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!isStatePostGloas(state)) {
|
|
121
|
+
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
102
124
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
103
125
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
104
|
-
|
|
126
|
+
let builder: gloas.Builder;
|
|
127
|
+
try {
|
|
128
|
+
builder = state.getBuilder(bid.builderIndex);
|
|
129
|
+
} catch {
|
|
130
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
131
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
132
|
+
builderIndex: bid.builderIndex,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
105
135
|
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
106
136
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
107
137
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
@@ -128,14 +158,33 @@ async function validateExecutionPayloadBid(
|
|
|
128
158
|
});
|
|
129
159
|
}
|
|
130
160
|
|
|
131
|
-
// [
|
|
161
|
+
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution payload in fork
|
|
162
|
+
// choice. Looks up the variant of `bid.parent_block_root` whose payload hash matches
|
|
163
|
+
// `bid.parent_block_hash` — works for both FULL parents (FULL variant carries the delivered
|
|
164
|
+
// payload's hash) and EMPTY parents (EMPTY/PENDING variants carry the inherited parent
|
|
165
|
+
// payload's hash, since the new block doesn't have its own payload). Variant carries the
|
|
166
|
+
// executed payload's gas_limit, which we use as `parent_gas_limit` below.
|
|
167
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, parentBlockHashHex);
|
|
168
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
169
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
170
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH,
|
|
171
|
+
parentBlockHash: parentBlockHashHex,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
|
|
176
|
+
// where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
|
|
177
|
+
// `target_gas_limit` is `proposer_preferences.target_gas_limit`.
|
|
132
178
|
const bidGasLimit = Number(bid.gasLimit);
|
|
133
|
-
|
|
134
|
-
|
|
179
|
+
const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
|
|
180
|
+
const targetGasLimit = proposerPreferences.message.targetGasLimit;
|
|
181
|
+
if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
|
|
182
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
135
183
|
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
|
|
136
184
|
builderIndex: bid.builderIndex,
|
|
137
185
|
bidGasLimit,
|
|
138
|
-
|
|
186
|
+
parentGasLimit,
|
|
187
|
+
targetGasLimit,
|
|
139
188
|
});
|
|
140
189
|
}
|
|
141
190
|
|
|
@@ -166,11 +215,11 @@ async function validateExecutionPayloadBid(
|
|
|
166
215
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
167
216
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
168
217
|
const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, parentBlockHashHex, parentBlockRootHex);
|
|
169
|
-
if (bestBid !== null && bestBid.value >= bid.value) {
|
|
218
|
+
if (bestBid !== null && bestBid.message.value >= bid.value) {
|
|
170
219
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
171
220
|
code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
|
|
172
221
|
bidValue: bid.value,
|
|
173
|
-
currentHighestBid: bestBid.value,
|
|
222
|
+
currentHighestBid: bestBid.message.value,
|
|
174
223
|
});
|
|
175
224
|
}
|
|
176
225
|
// [IGNORE] `bid.value` is less or equal than the builder's excess balance --
|
|
@@ -183,10 +232,6 @@ async function validateExecutionPayloadBid(
|
|
|
183
232
|
});
|
|
184
233
|
}
|
|
185
234
|
|
|
186
|
-
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution
|
|
187
|
-
// payload in fork choice.
|
|
188
|
-
// TODO GLOAS: implement this
|
|
189
|
-
|
|
190
235
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
191
236
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
192
237
|
PublicKey.fromBytes(builder.pubkey),
|
|
@@ -204,4 +249,6 @@ async function validateExecutionPayloadBid(
|
|
|
204
249
|
|
|
205
250
|
// Valid
|
|
206
251
|
chain.seenExecutionPayloadBids.add(bid.slot, bid.builderIndex);
|
|
252
|
+
|
|
253
|
+
return {proposerIndex: proposerPreferences.message.validatorIndex};
|
|
207
254
|
}
|
|
@@ -8,6 +8,7 @@ import {RootHex, gloas, ssz} from "@lodestar/types";
|
|
|
8
8
|
import {toRootHex} from "@lodestar/utils";
|
|
9
9
|
import {GossipAction, PayloadAttestationError, PayloadAttestationErrorCode} from "../errors/index.js";
|
|
10
10
|
import {IBeaconChain} from "../index.js";
|
|
11
|
+
import {RegenCaller} from "../regen/index.js";
|
|
11
12
|
|
|
12
13
|
export type PayloadAttestationValidationResult = {
|
|
13
14
|
attDataRootHex: RootHex;
|
|
@@ -61,22 +62,43 @@ async function validatePayloadAttestationMessage(
|
|
|
61
62
|
// [IGNORE] The message's block `data.beacon_block_root` has been seen (via
|
|
62
63
|
// gossip or non-gossip sources) (a client MAY queue attestation for processing
|
|
63
64
|
// once the block is retrieved. Note a client might want to request payload after).
|
|
64
|
-
|
|
65
|
+
const block = chain.forkChoice.getBlockDefaultStatus(data.beaconBlockRoot);
|
|
66
|
+
if (!block) {
|
|
65
67
|
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
66
68
|
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
67
69
|
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
68
70
|
});
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
// [IGNORE] The block referenced by `data.beacon_block_root` is at slot `data.slot`,
|
|
74
|
+
// i.e. the block has `block.slot == data.slot`.
|
|
75
|
+
if (block.slot !== data.slot) {
|
|
76
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
77
|
+
code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT,
|
|
78
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
79
|
+
blockSlot: block.slot,
|
|
80
|
+
slot: data.slot,
|
|
81
|
+
});
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
// [REJECT] The message's block `data.beacon_block_root` passes validation.
|
|
77
85
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
78
86
|
// it is possible that the block didn't pass the validation
|
|
79
87
|
|
|
88
|
+
// Use the referenced block's branch state for the PTC committee check
|
|
89
|
+
const state = await chain.regen
|
|
90
|
+
.getBlockSlotState(block, data.slot, {dontTransferCache: true}, RegenCaller.validateGossipPayloadAttestationMessage)
|
|
91
|
+
.catch(() => {
|
|
92
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
93
|
+
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
94
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!isStatePostGloas(state)) {
|
|
99
|
+
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
80
102
|
// [REJECT] The message's validator index is within the payload committee in
|
|
81
103
|
// `get_ptc(state, data.slot)`. The `state` is the head state corresponding to
|
|
82
104
|
// processing the block up to the current slot as determined by the fork choice.
|
|
@@ -66,6 +66,7 @@ export type ValidatorMonitor = {
|
|
|
66
66
|
delaySec: Seconds,
|
|
67
67
|
envelope: gloas.SignedExecutionPayloadEnvelope
|
|
68
68
|
): void;
|
|
69
|
+
registerExecutionPayloadBid(src: OpSource, proposerIndex: ValidatorIndex, bid: gloas.ExecutionPayloadBid): void;
|
|
69
70
|
registerImportedBlock(block: BeaconBlock, data: {proposerBalanceDelta: number}): void;
|
|
70
71
|
onPoolSubmitUnaggregatedAttestation(
|
|
71
72
|
seenTimestampSec: number,
|
|
@@ -459,6 +460,23 @@ export function createValidatorMonitor(
|
|
|
459
460
|
// TODO GLOAS: implement execution payload envelope monitoring
|
|
460
461
|
},
|
|
461
462
|
|
|
463
|
+
registerExecutionPayloadBid(src, proposerIndex, bid) {
|
|
464
|
+
if (!validators.has(proposerIndex)) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
log("Received an execution payload bid for monitored proposer", {
|
|
468
|
+
slot: bid.slot,
|
|
469
|
+
proposerIndex,
|
|
470
|
+
src,
|
|
471
|
+
builderIndex: bid.builderIndex,
|
|
472
|
+
gasLimit: bid.gasLimit,
|
|
473
|
+
value: bid.value.toString(),
|
|
474
|
+
parentBlockRoot: toRootHex(bid.parentBlockRoot),
|
|
475
|
+
parentBlockHash: toRootHex(bid.parentBlockHash),
|
|
476
|
+
blockHash: toRootHex(bid.blockHash),
|
|
477
|
+
});
|
|
478
|
+
},
|
|
479
|
+
|
|
462
480
|
registerImportedBlock(block, {proposerBalanceDelta}) {
|
|
463
481
|
const validator = validators.get(block.proposerIndex);
|
|
464
482
|
if (validator) {
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {Logger} from "@lodestar/logger";
|
|
3
3
|
import {Metrics} from "../../metrics/metrics.js";
|
|
4
|
-
import {IExecutionBuilder} from "./interface.js";
|
|
5
|
-
|
|
6
|
-
export {getExpectedGasLimit} from "./utils.js";
|
|
7
|
-
|
|
8
4
|
import {ExecutionBuilderHttp, ExecutionBuilderHttpOpts, defaultExecutionBuilderHttpOpts} from "./http.js";
|
|
5
|
+
import {IExecutionBuilder} from "./interface.js";
|
|
9
6
|
|
|
10
7
|
export {ExecutionBuilderHttp, defaultExecutionBuilderHttpOpts};
|
|
11
8
|
|
|
@@ -987,10 +987,11 @@ export function createLodestarMetrics(
|
|
|
987
987
|
}),
|
|
988
988
|
},
|
|
989
989
|
importPayload: {
|
|
990
|
-
|
|
991
|
-
name: "
|
|
992
|
-
help: "
|
|
990
|
+
elapsedTimeTillImported: register.histogram<{source: PayloadEnvelopeInputSource}>({
|
|
991
|
+
name: "lodestar_import_payload_elapsed_time_till_imported_seconds",
|
|
992
|
+
help: "Time elapsed between slot time and the time execution payload envelope is imported (added to fork choice)",
|
|
993
993
|
labelNames: ["source"],
|
|
994
|
+
buckets: [1, 2, 3, 6, 9, 12],
|
|
994
995
|
}),
|
|
995
996
|
columnsBySource: register.gauge<{source: PayloadEnvelopeInputSource}>({
|
|
996
997
|
name: "lodestar_import_payload_columns_by_source_total",
|
package/src/network/interface.ts
CHANGED
|
@@ -113,6 +113,7 @@ export interface INetwork extends INetworkCorePublic {
|
|
|
113
113
|
publishLightClientFinalityUpdate(update: LightClientFinalityUpdate): Promise<number>;
|
|
114
114
|
publishLightClientOptimisticUpdate(update: LightClientOptimisticUpdate): Promise<number>;
|
|
115
115
|
publishSignedExecutionPayloadEnvelope(signedEnvelope: gloas.SignedExecutionPayloadEnvelope): Promise<number>;
|
|
116
|
+
publishSignedExecutionPayloadBid(signedBid: gloas.SignedExecutionPayloadBid): Promise<number>;
|
|
116
117
|
publishPayloadAttestationMessage(payloadAttestationMessage: gloas.PayloadAttestationMessage): Promise<number>;
|
|
117
118
|
publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number>;
|
|
118
119
|
|
package/src/network/network.ts
CHANGED
|
@@ -515,6 +515,17 @@ export class Network implements INetwork {
|
|
|
515
515
|
);
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
+
async publishSignedExecutionPayloadBid(signedBid: gloas.SignedExecutionPayloadBid): Promise<number> {
|
|
519
|
+
const epoch = computeEpochAtSlot(signedBid.message.slot);
|
|
520
|
+
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
521
|
+
|
|
522
|
+
return this.publishGossip<GossipType.execution_payload_bid>(
|
|
523
|
+
{type: GossipType.execution_payload_bid, boundary},
|
|
524
|
+
signedBid,
|
|
525
|
+
{ignoreDuplicatePublishError: true}
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
|
|
518
529
|
async publishPayloadAttestationMessage(payloadAttestationMessage: gloas.PayloadAttestationMessage): Promise<number> {
|
|
519
530
|
const epoch = computeEpochAtSlot(payloadAttestationMessage.data.slot);
|
|
520
531
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
@@ -1117,7 +1117,16 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
1119
|
const slot = envelope.payload.slotNumber;
|
|
1120
|
-
const delaySec =
|
|
1120
|
+
const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
|
|
1121
|
+
|
|
1122
|
+
logger.debug("Received gossip payload envelope", {
|
|
1123
|
+
currentSlot: chain.clock.currentSlot,
|
|
1124
|
+
peerId: peerIdStr,
|
|
1125
|
+
slot,
|
|
1126
|
+
blockRoot: toRootHex(envelope.beaconBlockRoot),
|
|
1127
|
+
delaySec,
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1121
1130
|
metrics?.gossipExecutionPayloadEnvelope.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
1122
1131
|
chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.gossip, delaySec, signedEnvelope);
|
|
1123
1132
|
|
|
@@ -1205,8 +1214,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1205
1214
|
}
|
|
1206
1215
|
chain.forkChoice.notifyPtcMessages(
|
|
1207
1216
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1217
|
+
payloadAttestationMessage.data.slot,
|
|
1208
1218
|
validationResult.validatorCommitteeIndices,
|
|
1209
|
-
payloadAttestationMessage.data.payloadPresent
|
|
1219
|
+
payloadAttestationMessage.data.payloadPresent,
|
|
1220
|
+
payloadAttestationMessage.data.blobDataAvailable
|
|
1210
1221
|
);
|
|
1211
1222
|
},
|
|
1212
1223
|
[GossipType.execution_payload_bid]: async ({
|
|
@@ -1215,16 +1226,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1215
1226
|
}: GossipHandlerParamGeneric<GossipType.execution_payload_bid>) => {
|
|
1216
1227
|
const {serializedData} = gossipData;
|
|
1217
1228
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
1218
|
-
await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1229
|
+
const {proposerIndex} = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1219
1230
|
|
|
1220
1231
|
// Handle valid payload bid by storing in a bid pool
|
|
1221
1232
|
try {
|
|
1222
|
-
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid
|
|
1233
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
1223
1234
|
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1224
1235
|
} catch (e) {
|
|
1225
1236
|
logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
|
|
1226
1237
|
}
|
|
1227
1238
|
|
|
1239
|
+
chain.validatorMonitor?.registerExecutionPayloadBid(OpSource.gossip, proposerIndex, executionPayloadBid.message);
|
|
1240
|
+
|
|
1228
1241
|
chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
|
|
1229
1242
|
version: config.getForkName(executionPayloadBid.message.slot),
|
|
1230
1243
|
data: executionPayloadBid,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/execution/builder/utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAU1F"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
|
|
3
|
-
*/
|
|
4
|
-
const gasLimitAdjustmentFactor = 1024;
|
|
5
|
-
/**
|
|
6
|
-
* Calculates expected gas limit based on parent gas limit and target gas limit
|
|
7
|
-
*/
|
|
8
|
-
export function getExpectedGasLimit(parentGasLimit, targetGasLimit) {
|
|
9
|
-
const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / gasLimitAdjustmentFactor) - 1, 0);
|
|
10
|
-
if (targetGasLimit > parentGasLimit) {
|
|
11
|
-
const gasDiff = targetGasLimit - parentGasLimit;
|
|
12
|
-
return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference);
|
|
13
|
-
}
|
|
14
|
-
const gasDiff = parentGasLimit - targetGasLimit;
|
|
15
|
-
return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference);
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/execution/builder/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,cAAsB,EAAE,cAAsB,EAAU;IAC1F,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAErG,IAAI,cAAc,GAAG,cAAc,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;QAChD,OAAO,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;IAChD,OAAO,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAAA,CAClE"}
|