@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
|
@@ -4,10 +4,12 @@ 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 {toRootHex} from "@lodestar/utils";
|
|
10
|
+
import {ValidatorIndex, gloas} from "@lodestar/types";
|
|
11
|
+
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
12
|
+
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
11
13
|
import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
|
|
12
14
|
import {IBeaconChain} from "../index.js";
|
|
13
15
|
import {RegenCaller} from "../regen/index.js";
|
|
@@ -15,21 +17,21 @@ import {RegenCaller} from "../regen/index.js";
|
|
|
15
17
|
export async function validateApiExecutionPayloadBid(
|
|
16
18
|
chain: IBeaconChain,
|
|
17
19
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
18
|
-
): Promise<
|
|
20
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
19
21
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export async function validateGossipExecutionPayloadBid(
|
|
23
25
|
chain: IBeaconChain,
|
|
24
26
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
25
|
-
): Promise<
|
|
27
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
26
28
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async function validateExecutionPayloadBid(
|
|
30
32
|
chain: IBeaconChain,
|
|
31
33
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
32
|
-
): Promise<
|
|
34
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
33
35
|
const bid = signedExecutionPayloadBid.message;
|
|
34
36
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
35
37
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
@@ -48,12 +50,66 @@ async function validateExecutionPayloadBid(
|
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
// [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon block in fork choice.
|
|
54
|
+
// Moved earlier than the spec ordering so we can derive the proposer dependent root for the
|
|
55
|
+
// proposer-preferences lookup below from a known fork-choice block.
|
|
56
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
|
|
57
|
+
if (parentBlock === null) {
|
|
58
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
59
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
60
|
+
parentBlockRoot: parentBlockRootHex,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// [REJECT] The bid is for a higher slot than its parent block -- i.e.
|
|
65
|
+
// validate that `bid.slot` is greater than the slot of the block with root
|
|
66
|
+
// `bid.parent_block_root`.
|
|
67
|
+
if (bid.slot <= parentBlock.slot) {
|
|
68
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
69
|
+
code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT,
|
|
70
|
+
parentSlot: parentBlock.slot,
|
|
71
|
+
slot: bid.slot,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
51
75
|
// [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
|
|
52
76
|
// seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
|
|
53
|
-
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
//
|
|
77
|
+
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`.
|
|
78
|
+
const bidEpoch = computeEpochAtSlot(bid.slot);
|
|
79
|
+
// gloas is always post-Fulu, so `get_proposer_dependent_root` is the post-Fulu (deterministic
|
|
80
|
+
// proposer lookahead) form `block_root_at(start_slot(epoch - MIN_SEED_LOOKAHEAD) - 1)` with
|
|
81
|
+
// `MIN_SEED_LOOKAHEAD == 1` — identical to the attester-shuffling dependent root for the same
|
|
82
|
+
// epoch (both 1-epoch lookahead), hence `getShufflingDependentRoot`. `null` on a
|
|
83
|
+
// unknown/finalized-pruned ancestor or genesis edge → degrade to IGNORE below instead of
|
|
84
|
+
// letting a raw `ForkChoiceError` escape the `GossipActionError` contract.
|
|
85
|
+
const dependentRootHex = (() => {
|
|
86
|
+
try {
|
|
87
|
+
return getShufflingDependentRoot(chain.forkChoice, bidEpoch, computeEpochAtSlot(parentBlock.slot), parentBlock);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
92
|
+
|
|
93
|
+
if (dependentRootHex === null) {
|
|
94
|
+
// Could not derive the dependent root for this branch (unknown/finalized-pruned ancestor,
|
|
95
|
+
// genesis edge, etc.) → definitionally no matching `SignedProposerPreferences`.
|
|
96
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
97
|
+
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
|
|
98
|
+
slot: bid.slot,
|
|
99
|
+
parentBlockRoot: parentBlockRootHex,
|
|
100
|
+
dependentRoot: "unknown",
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const proposerPreferences = chain.proposerPreferencesPool.get(bid.slot, dependentRootHex);
|
|
105
|
+
if (proposerPreferences === null) {
|
|
106
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
107
|
+
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
|
|
108
|
+
slot: bid.slot,
|
|
109
|
+
parentBlockRoot: parentBlockRootHex,
|
|
110
|
+
dependentRoot: dependentRootHex,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
57
113
|
|
|
58
114
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
59
115
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
@@ -75,10 +131,44 @@ async function validateExecutionPayloadBid(
|
|
|
75
131
|
}
|
|
76
132
|
|
|
77
133
|
// [REJECT] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
134
|
+
if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
|
|
135
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
136
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH,
|
|
137
|
+
builderIndex: bid.builderIndex,
|
|
138
|
+
bidFeeRecipient: toHex(bid.feeRecipient),
|
|
139
|
+
expectedFeeRecipient: toHex(proposerPreferences.message.feeRecipient),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution payload in fork
|
|
144
|
+
// choice. Looks up the variant of `bid.parent_block_root` whose payload hash matches
|
|
145
|
+
// `bid.parent_block_hash` — works for both FULL parents (FULL variant carries the delivered
|
|
146
|
+
// payload's hash) and EMPTY parents (EMPTY/PENDING variants carry the inherited parent
|
|
147
|
+
// payload's hash, since the new block doesn't have its own payload). Variant carries the
|
|
148
|
+
// executed payload's gas_limit, which we use as `parent_gas_limit` below.
|
|
149
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, parentBlockHashHex);
|
|
150
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
151
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
152
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH,
|
|
153
|
+
parentBlockHash: parentBlockHashHex,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
|
|
158
|
+
// where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
|
|
159
|
+
// `target_gas_limit` is `proposer_preferences.target_gas_limit`.
|
|
160
|
+
const bidGasLimit = Number(bid.gasLimit);
|
|
161
|
+
const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
|
|
162
|
+
const targetGasLimit = proposerPreferences.message.targetGasLimit;
|
|
163
|
+
if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
|
|
164
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
165
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
|
|
166
|
+
builderIndex: bid.builderIndex,
|
|
167
|
+
bidGasLimit,
|
|
168
|
+
parentGasLimit,
|
|
169
|
+
targetGasLimit,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
82
172
|
|
|
83
173
|
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
84
174
|
// consensus layer -- i.e. validate that
|
|
@@ -107,11 +197,11 @@ async function validateExecutionPayloadBid(
|
|
|
107
197
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
108
198
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
109
199
|
const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, parentBlockHashHex, parentBlockRootHex);
|
|
110
|
-
if (bestBid !== null && bestBid.value >= bid.value) {
|
|
200
|
+
if (bestBid !== null && bestBid.message.value >= bid.value) {
|
|
111
201
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
112
202
|
code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
|
|
113
203
|
bidValue: bid.value,
|
|
114
|
-
currentHighestBid: bestBid.value,
|
|
204
|
+
currentHighestBid: bestBid.message.value,
|
|
115
205
|
});
|
|
116
206
|
}
|
|
117
207
|
// [IGNORE] `bid.value` is less or equal than the builder's excess balance --
|
|
@@ -124,19 +214,6 @@ async function validateExecutionPayloadBid(
|
|
|
124
214
|
});
|
|
125
215
|
}
|
|
126
216
|
|
|
127
|
-
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution
|
|
128
|
-
// payload in fork choice.
|
|
129
|
-
// TODO GLOAS: implement this
|
|
130
|
-
|
|
131
|
-
// [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon
|
|
132
|
-
// block in fork choice.
|
|
133
|
-
if (!chain.forkChoice.hasBlock(bid.parentBlockRoot)) {
|
|
134
|
-
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
135
|
-
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
136
|
-
parentBlockRoot: parentBlockRootHex,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
217
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
141
218
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
142
219
|
PublicKey.fromBytes(builder.pubkey),
|
|
@@ -154,4 +231,6 @@ async function validateExecutionPayloadBid(
|
|
|
154
231
|
|
|
155
232
|
// Valid
|
|
156
233
|
chain.seenExecutionPayloadBids.add(bid.slot, bid.builderIndex);
|
|
234
|
+
|
|
235
|
+
return {proposerIndex: proposerPreferences.message.validatorIndex};
|
|
157
236
|
}
|
|
@@ -8,10 +8,11 @@ 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;
|
|
14
|
-
|
|
15
|
+
validatorCommitteeIndices: number[];
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export async function validateApiPayloadAttestationMessage(
|
|
@@ -61,28 +62,40 @@ 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
|
-
const state = chain.getHeadState();
|
|
72
|
-
if (!isStatePostGloas(state)) {
|
|
73
|
-
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
73
|
// [REJECT] The message's block `data.beacon_block_root` passes validation.
|
|
77
74
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
78
75
|
// it is possible that the block didn't pass the validation
|
|
79
76
|
|
|
77
|
+
// Use the referenced block's branch state for the PTC committee check
|
|
78
|
+
const state = await chain.regen
|
|
79
|
+
.getBlockSlotState(block, data.slot, {dontTransferCache: true}, RegenCaller.validateGossipPayloadAttestationMessage)
|
|
80
|
+
.catch(() => {
|
|
81
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
82
|
+
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
83
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (!isStatePostGloas(state)) {
|
|
88
|
+
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
// [REJECT] The message's validator index is within the payload committee in
|
|
81
92
|
// `get_ptc(state, data.slot)`. The `state` is the head state corresponding to
|
|
82
93
|
// processing the block up to the current slot as determined by the fork choice.
|
|
83
|
-
|
|
94
|
+
// The validator may occupy multiple PTC positions because `compute_ptc` samples
|
|
95
|
+
// by effective balance — collect all of them so duplicate votes are counted.
|
|
96
|
+
const validatorCommitteeIndices = state.getIndicesInPayloadTimelinessCommittee(validatorIndex, data.slot);
|
|
84
97
|
|
|
85
|
-
if (
|
|
98
|
+
if (validatorCommitteeIndices.length === 0) {
|
|
86
99
|
throw new PayloadAttestationError(GossipAction.REJECT, {
|
|
87
100
|
code: PayloadAttestationErrorCode.INVALID_ATTESTER,
|
|
88
101
|
attesterIndex: validatorIndex,
|
|
@@ -115,6 +128,6 @@ async function validatePayloadAttestationMessage(
|
|
|
115
128
|
|
|
116
129
|
return {
|
|
117
130
|
attDataRootHex: toRootHex(ssz.gloas.PayloadAttestationData.hashTreeRoot(data)),
|
|
118
|
-
|
|
131
|
+
validatorCommitteeIndices,
|
|
119
132
|
};
|
|
120
133
|
}
|
|
@@ -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
|
|
|
@@ -88,6 +88,7 @@ export type PayloadAttributes = {
|
|
|
88
88
|
withdrawals?: capella.Withdrawal[];
|
|
89
89
|
parentBeaconBlockRoot?: Uint8Array;
|
|
90
90
|
slotNumber?: number; // EIP-7843
|
|
91
|
+
targetGasLimit?: number; // GLOAS (PayloadAttributesV4, execution-apis#796)
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
export type VersionedHashes = Uint8Array[];
|
|
@@ -245,6 +245,8 @@ export type PayloadAttributesRpc = {
|
|
|
245
245
|
parentBeaconBlockRoot?: DATA;
|
|
246
246
|
/** QUANTITY, 64 Bits - value for the slot number field of the new payload (EIP-7843) */
|
|
247
247
|
slotNumber?: QUANTITY;
|
|
248
|
+
/** QUANTITY, 64 Bits - target value for the gasLimit field of the new payload (GLOAS, execution-apis#796) */
|
|
249
|
+
targetGasLimit?: QUANTITY;
|
|
248
250
|
};
|
|
249
251
|
|
|
250
252
|
export type ClientVersionRpc = {
|
|
@@ -425,6 +427,7 @@ export function serializePayloadAttributes(data: PayloadAttributes): PayloadAttr
|
|
|
425
427
|
withdrawals: data.withdrawals?.map(serializeWithdrawal),
|
|
426
428
|
parentBeaconBlockRoot: data.parentBeaconBlockRoot ? bytesToData(data.parentBeaconBlockRoot) : undefined,
|
|
427
429
|
slotNumber: data.slotNumber !== undefined ? numToQuantity(data.slotNumber) : undefined,
|
|
430
|
+
targetGasLimit: data.targetGasLimit !== undefined ? numToQuantity(data.targetGasLimit) : undefined,
|
|
428
431
|
};
|
|
429
432
|
}
|
|
430
433
|
|
|
@@ -442,6 +445,7 @@ export function deserializePayloadAttributes(data: PayloadAttributesRpc): Payloa
|
|
|
442
445
|
withdrawals: data.withdrawals?.map((withdrawal) => deserializeWithdrawal(withdrawal)),
|
|
443
446
|
parentBeaconBlockRoot: data.parentBeaconBlockRoot ? dataToBytes(data.parentBeaconBlockRoot, 32) : undefined,
|
|
444
447
|
slotNumber: data.slotNumber !== undefined ? quantityToNum(data.slotNumber) : undefined,
|
|
448
|
+
targetGasLimit: data.targetGasLimit !== undefined ? quantityToNum(data.targetGasLimit) : undefined,
|
|
445
449
|
};
|
|
446
450
|
}
|
|
447
451
|
|
|
@@ -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,7 +113,9 @@ 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>;
|
|
118
|
+
publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number>;
|
|
117
119
|
|
|
118
120
|
// Debug
|
|
119
121
|
dumpGossipQueue(gossipType: GossipType): Promise<PendingGossipsubMessage[]>;
|
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);
|
|
@@ -526,6 +537,17 @@ export class Network implements INetwork {
|
|
|
526
537
|
);
|
|
527
538
|
}
|
|
528
539
|
|
|
540
|
+
async publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number> {
|
|
541
|
+
const epoch = computeEpochAtSlot(signedProposerPreferences.message.proposalSlot);
|
|
542
|
+
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
543
|
+
|
|
544
|
+
return this.publishGossip<GossipType.proposer_preferences>(
|
|
545
|
+
{type: GossipType.proposer_preferences, boundary},
|
|
546
|
+
signedProposerPreferences,
|
|
547
|
+
{ignoreDuplicatePublishError: true}
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
529
551
|
private async publishGossip<K extends GossipType>(
|
|
530
552
|
topic: GossipTopicMap[K],
|
|
531
553
|
object: GossipTypeMap[K],
|
|
@@ -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
|
|
|
@@ -1197,7 +1206,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1197
1206
|
const insertOutcome = chain.payloadAttestationPool.add(
|
|
1198
1207
|
payloadAttestationMessage,
|
|
1199
1208
|
validationResult.attDataRootHex,
|
|
1200
|
-
validationResult.
|
|
1209
|
+
validationResult.validatorCommitteeIndices
|
|
1201
1210
|
);
|
|
1202
1211
|
metrics?.opPool.payloadAttestationPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1203
1212
|
} catch (e) {
|
|
@@ -1205,8 +1214,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1205
1214
|
}
|
|
1206
1215
|
chain.forkChoice.notifyPtcMessages(
|
|
1207
1216
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1208
|
-
|
|
1209
|
-
|
|
1217
|
+
payloadAttestationMessage.data.slot,
|
|
1218
|
+
validationResult.validatorCommitteeIndices,
|
|
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,
|
|
@@ -1237,6 +1250,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1237
1250
|
const {serializedData} = gossipData;
|
|
1238
1251
|
const signedProposerPreferences = sszDeserialize(topic, serializedData);
|
|
1239
1252
|
await validateGossipProposerPreferences(chain, signedProposerPreferences);
|
|
1253
|
+
|
|
1254
|
+
chain.proposerPreferencesPool.add(signedProposerPreferences);
|
|
1255
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1256
|
+
version: ForkName.gloas,
|
|
1257
|
+
data: signedProposerPreferences,
|
|
1258
|
+
});
|
|
1240
1259
|
},
|
|
1241
1260
|
};
|
|
1242
1261
|
}
|
|
@@ -2,45 +2,49 @@ import {EpochDifference, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
|
2
2
|
import {Epoch, RootHex} from "@lodestar/types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Get dependent root of a shuffling given
|
|
5
|
+
* Get dependent root of a shuffling given a message epoch and a proto block.
|
|
6
|
+
*
|
|
7
|
+
* Pre-gloas, this is used for attestation validation
|
|
8
|
+
* Post-gloas, this is also used for execution_payload_bid validation because post-fulu,
|
|
9
|
+
* a dependent root of a proposal duties is 1-epoch look ahead (instead of 0 as of pre-fulu)
|
|
6
10
|
*/
|
|
7
11
|
export function getShufflingDependentRoot(
|
|
8
12
|
forkChoice: IForkChoice,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
msgEpoch: Epoch,
|
|
14
|
+
protoBlockEpoch: Epoch,
|
|
15
|
+
protoBlock: ProtoBlock
|
|
12
16
|
): RootHex {
|
|
13
17
|
let shufflingDependentRoot: RootHex;
|
|
14
|
-
if (
|
|
18
|
+
if (protoBlockEpoch === msgEpoch) {
|
|
15
19
|
// current shuffling, this is equivalent to `headState.currentShuffling`
|
|
16
|
-
// given
|
|
20
|
+
// given protoBlockEpoch = msgEpoch = n
|
|
17
21
|
// epoch: (n-2) (n-1) n (n+1)
|
|
18
22
|
// |-------|-------|-------|-------|
|
|
19
|
-
//
|
|
23
|
+
// protoBlock ------------------------^
|
|
20
24
|
// shufflingDependentRoot ------^
|
|
21
|
-
shufflingDependentRoot = forkChoice.getDependentRoot(
|
|
22
|
-
} else if (
|
|
25
|
+
shufflingDependentRoot = forkChoice.getDependentRoot(protoBlock, EpochDifference.previous);
|
|
26
|
+
} else if (protoBlockEpoch === msgEpoch - 1) {
|
|
23
27
|
// next shuffling, this is equivalent to `headState.nextShuffling`
|
|
24
|
-
// given
|
|
28
|
+
// given protoBlockEpoch = n-1, msgEpoch = n
|
|
25
29
|
// epoch: (n-2) (n-1) n (n+1)
|
|
26
30
|
// |-------|-------|-------|-------|
|
|
27
|
-
//
|
|
31
|
+
// protoBlock -------------------^
|
|
28
32
|
// shufflingDependentRoot ------^
|
|
29
|
-
shufflingDependentRoot = forkChoice.getDependentRoot(
|
|
30
|
-
} else if (
|
|
33
|
+
shufflingDependentRoot = forkChoice.getDependentRoot(protoBlock, EpochDifference.current);
|
|
34
|
+
} else if (protoBlockEpoch < msgEpoch - 1) {
|
|
31
35
|
// this never happens with default chain option of maxSkipSlots = 32, however we still need to handle it
|
|
32
36
|
// check the verifyHeadBlockAndTargetRoot() function above
|
|
33
|
-
// given
|
|
37
|
+
// given protoBlockEpoch = n-2, msgEpoch = n
|
|
34
38
|
// epoch: (n-2) (n-1) n (n+1)
|
|
35
39
|
// |-------|-------|-------|-------|
|
|
36
|
-
//
|
|
40
|
+
// protoBlock -----------^
|
|
37
41
|
// shufflingDependentRoot -----^
|
|
38
|
-
shufflingDependentRoot =
|
|
42
|
+
shufflingDependentRoot = protoBlock.blockRoot;
|
|
39
43
|
// use lodestar_gossip_attestation_head_slot_to_attestation_slot metric to track this case
|
|
40
44
|
} else {
|
|
41
|
-
//
|
|
45
|
+
// protoBlockEpoch > msgEpoch
|
|
42
46
|
// should not happen, handled in verifyAttestationTargetRoot
|
|
43
|
-
throw Error(`
|
|
47
|
+
throw Error(`message epoch ${msgEpoch} is before proto block epoch ${protoBlockEpoch}`);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
return shufflingDependentRoot;
|
|
@@ -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"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
|
|
3
|
-
*/
|
|
4
|
-
const gasLimitAdjustmentFactor = 1024;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Calculates expected gas limit based on parent gas limit and target gas limit
|
|
8
|
-
*/
|
|
9
|
-
export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: number): number {
|
|
10
|
-
const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / gasLimitAdjustmentFactor) - 1, 0);
|
|
11
|
-
|
|
12
|
-
if (targetGasLimit > parentGasLimit) {
|
|
13
|
-
const gasDiff = targetGasLimit - parentGasLimit;
|
|
14
|
-
return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const gasDiff = parentGasLimit - targetGasLimit;
|
|
18
|
-
return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference);
|
|
19
|
-
}
|