Skip to content

Commit dc288bc

Browse files
authored
feat: score attestations for block by profitability (#8016)
Updates scoring / sorting of consolidated attestations during block packing to follow `processAttestation` reward computation to maximize profitability of block. https://github.com/ChainSafe/lodestar/blob/2fdd3fa446964d8f1f5c88c822cdbb88920090ca/packages/state-transition/src/block/processAttestationsAltair.ts#L33 Closes #8019
1 parent afdf325 commit dc288bc

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import {
1010
MAX_COMMITTEES_PER_SLOT,
1111
MIN_ATTESTATION_INCLUSION_DELAY,
1212
SLOTS_PER_EPOCH,
13+
TIMELY_HEAD_FLAG_INDEX,
14+
TIMELY_HEAD_WEIGHT,
15+
TIMELY_SOURCE_FLAG_INDEX,
16+
TIMELY_SOURCE_WEIGHT,
17+
TIMELY_TARGET_FLAG_INDEX,
18+
TIMELY_TARGET_WEIGHT,
1319
isForkPostDeneb,
1420
isForkPostElectra,
1521
} from "@lodestar/params";
@@ -18,9 +24,11 @@ import {
1824
CachedBeaconStateAltair,
1925
CachedBeaconStatePhase0,
2026
EffectiveBalanceIncrements,
27+
RootCache,
2128
computeEpochAtSlot,
2229
computeSlotsSinceEpochStart,
2330
computeStartSlotAtEpoch,
31+
getAttestationParticipationStatus,
2432
getBlockRootAtSlot,
2533
} from "@lodestar/state-transition";
2634
import {
@@ -123,6 +131,11 @@ const MAX_ATTESTATIONS_PER_GROUP_ELECTRA = Math.min(
123131
MAX_ATTESTATIONS_ELECTRA
124132
);
125133

134+
/** Same to https://github.com/ethereum/consensus-specs/blob/v1.5.0/specs/altair/beacon-chain.md#has_flag */
135+
const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX;
136+
const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;
137+
const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX;
138+
126139
export enum ScannedSlotsTerminationReason {
127140
MaxConsolidationReached = "max_consolidation_reached",
128141
ScannedAllSlots = "scanned_all_slots",
@@ -346,6 +359,7 @@ export class AggregatedAttestationPool {
346359
const stateSlot = state.slot;
347360
const stateEpoch = state.epochCtx.epoch;
348361
const statePrevEpoch = stateEpoch - 1;
362+
const rootCache = new RootCache(state);
349363

350364
const notSeenValidatorsFn = getNotSeenValidatorsFn(state);
351365
const validateAttestationDataFn = getValidateAttestationDataFn(forkChoice, state);
@@ -466,7 +480,22 @@ export class AggregatedAttestationPool {
466480

467481
// after all committees are processed, we have a list of sameAttDataCons
468482
for (const consolidation of sameAttDataCons) {
469-
const score = consolidation.totalNewSeenEffectiveBalance / inclusionDistance;
483+
// Score attestations by profitability to maximize proposer reward
484+
const flags = getAttestationParticipationStatus(
485+
ForkSeq[fork],
486+
consolidation.attData,
487+
inclusionDistance,
488+
stateEpoch,
489+
rootCache
490+
);
491+
492+
const weight =
493+
((flags & TIMELY_SOURCE) === TIMELY_SOURCE ? TIMELY_SOURCE_WEIGHT : 0) +
494+
((flags & TIMELY_TARGET) === TIMELY_TARGET ? TIMELY_TARGET_WEIGHT : 0) +
495+
((flags & TIMELY_HEAD) === TIMELY_HEAD ? TIMELY_HEAD_WEIGHT : 0);
496+
497+
const score = consolidation.totalNewSeenEffectiveBalance * weight;
498+
470499
consolidations.set(consolidation, score);
471500
// Stop accumulating attestations there are enough that may have good scoring
472501
if (consolidations.size >= MAX_ATTESTATIONS_ELECTRA * 2) {

0 commit comments

Comments
 (0)