Skip to content

Commit

Permalink
feat: send and use validators fee recipient for engine block producti…
Browse files Browse the repository at this point in the history
…on (#5831)

* feat: send and use validators fee recipient for block production

* fix tests

* mock tests that fee recipients are correctly passed

* improve logging

* add more info

* add more info
  • Loading branch information
g11tech authored Aug 14, 2023
1 parent 97502c7 commit fa5c6cf
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 25 deletions.
26 changes: 17 additions & 9 deletions packages/api/src/beacon/routes/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ export type Api = {
produceBlock(
slot: Slot,
randaoReveal: BLSSignature,
graffiti: string
graffiti: string,
feeRecipient?: string
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: allForks.BeaconBlock; blockValue: Wei}},
Expand All @@ -222,7 +223,8 @@ export type Api = {
produceBlockV2(
slot: Slot,
randaoReveal: BLSSignature,
graffiti: string
graffiti: string,
feeRecipient?: string
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: allForks.BeaconBlock | BlockContents; version: ForkName; blockValue: Wei}},
Expand All @@ -233,7 +235,8 @@ export type Api = {
produceBlindedBlock(
slot: Slot,
randaoReveal: BLSSignature,
graffiti: string
graffiti: string,
feeRecipient?: string
): Promise<
ApiClientResponse<
{
Expand Down Expand Up @@ -428,7 +431,7 @@ export type ReqTypes = {
getProposerDuties: {params: {epoch: Epoch}};
getSyncCommitteeDuties: {params: {epoch: Epoch}; body: U64Str[]};
produceBlock: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceBlockV2: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceBlockV2: {params: {slot: number}; query: {randao_reveal: string; graffiti: string; fee_recipient?: string}};
produceBlindedBlock: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceAttestationData: {query: {slot: number; committee_index: number}};
produceSyncCommitteeContribution: {query: {slot: number; subcommittee_index: number; beacon_block_root: string}};
Expand Down Expand Up @@ -484,15 +487,20 @@ export function getReqSerializers(): ReqSerializers<Api, ReqTypes> {
{jsonCase: "eth2"}
);

const produceBlock: ReqSerializers<Api, ReqTypes>["produceBlock"] = {
writeReq: (slot, randaoReveal, graffiti) => ({
const produceBlock: ReqSerializers<Api, ReqTypes>["produceBlockV2"] = {
writeReq: (slot, randaoReveal, graffiti, feeRecipient) => ({
params: {slot},
query: {randao_reveal: toHexString(randaoReveal), graffiti: toGraffitiHex(graffiti)},
query: {randao_reveal: toHexString(randaoReveal), graffiti: toGraffitiHex(graffiti), fee_recipient: feeRecipient},
}),
parseReq: ({params, query}) => [params.slot, fromHexString(query.randao_reveal), fromGraffitiHex(query.graffiti)],
parseReq: ({params, query}) => [
params.slot,
fromHexString(query.randao_reveal),
fromGraffitiHex(query.graffiti),
query.fee_recipient,
],
schema: {
params: {slot: Schema.UintRequired},
query: {randao_reveal: Schema.StringRequired, graffiti: Schema.String},
query: {randao_reveal: Schema.StringRequired, graffiti: Schema.String, fee_recipient: Schema.String},
},
};

Expand Down
7 changes: 4 additions & 3 deletions packages/api/test/unit/beacon/testData/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ZERO_HASH_HEX = "0x" + ZERO_HASH.toString("hex");
const randaoReveal = Buffer.alloc(96, 1);
const selectionProof = Buffer.alloc(96, 1);
const graffiti = "a".repeat(32);
const feeRecipient = "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";

export const testData: GenericServerTestCases<Api> = {
getAttesterDuties: {
Expand Down Expand Up @@ -44,15 +45,15 @@ export const testData: GenericServerTestCases<Api> = {
},
},
produceBlock: {
args: [32000, randaoReveal, graffiti],
args: [32000, randaoReveal, graffiti, feeRecipient],
res: {data: ssz.phase0.BeaconBlock.defaultValue(), blockValue: ssz.Wei.defaultValue()},
},
produceBlockV2: {
args: [32000, randaoReveal, graffiti],
args: [32000, randaoReveal, graffiti, feeRecipient],
res: {data: ssz.altair.BeaconBlock.defaultValue(), version: ForkName.altair, blockValue: ssz.Wei.defaultValue()},
},
produceBlindedBlock: {
args: [32000, randaoReveal, graffiti],
args: [32000, randaoReveal, graffiti, feeRecipient],
res: {
data: ssz.bellatrix.BlindedBeaconBlock.defaultValue(),
version: ForkName.bellatrix,
Expand Down
6 changes: 4 additions & 2 deletions packages/beacon-node/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ export function getValidatorApi({
const produceBlockV2: ServerApi<routes.validator.Api>["produceBlockV2"] = async function produceBlockV2(
slot,
randaoReveal,
graffiti
graffiti,
feeRecipient
) {
const source = ProducedBlockSource.engine;
let timer;
Expand All @@ -297,6 +298,7 @@ export function getValidatorApi({
slot,
randaoReveal,
graffiti: toGraffitiBuffer(graffiti || ""),
feeRecipient,
});
metrics?.blockProductionSuccess.inc({source});
metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length);
Expand Down Expand Up @@ -326,7 +328,7 @@ export function getValidatorApi({
randaoReveal,
graffiti
) {
const {data, version, blockValue} = await produceBlockV2(slot, randaoReveal, graffiti);
const {data, version, blockValue} = await produceBlockV2(slot, randaoReveal, graffiti, undefined);
if ((data as BlockContents).block !== undefined) {
throw Error(`Invalid block contents for produceBlock at fork=${version}`);
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ export class BeaconChain implements IBeaconChain {

async produceBlockWrapper<T extends BlockType>(
blockType: T,
{randaoReveal, graffiti, slot}: BlockAttributes
{randaoReveal, graffiti, slot, feeRecipient}: BlockAttributes
): Promise<{block: AssembledBlockType<T>; blockValue: Wei}> {
const head = this.forkChoice.getHead();
const state = await this.regen.getBlockSlotState(
Expand All @@ -491,6 +491,7 @@ export class BeaconChain implements IBeaconChain {
randaoReveal,
graffiti,
slot,
feeRecipient,
parentSlot: slot - 1,
parentBlockRoot,
proposerIndex,
Expand Down
47 changes: 41 additions & 6 deletions packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ export type BlockAttributes = {
randaoReveal: BLSSignature;
graffiti: Bytes32;
slot: Slot;
feeRecipient?: string;
};

export enum BlockType {
Full,
Blinded,
Full = "Full",
Blinded = "Blinded",
}
export type AssembledBodyType<T extends BlockType> = T extends BlockType.Full
? allForks.BeaconBlockBody
Expand All @@ -80,6 +81,7 @@ export async function produceBlockBody<T extends BlockType>(
randaoReveal,
graffiti,
slot: blockSlot,
feeRecipient: requestedFeeRecipient,
parentSlot,
parentBlockRoot,
proposerIndex,
Expand All @@ -96,6 +98,14 @@ export async function produceBlockBody<T extends BlockType>(
// TODO: Does not guarantee that preDeneb enum goes with a preDeneb block
let blobsResult: BlobsResult;
let blockValue: Wei;
const fork = currentState.config.getForkName(blockSlot);

const logMeta: Record<string, string | number | bigint> = {
fork,
blockType,
slot: blockSlot,
};
this.logger.verbose("Producing beacon block body", logMeta);

// TODO:
// Iterate through the naive aggregation pool and ensure all the attestations from there
Expand Down Expand Up @@ -125,8 +135,6 @@ export async function produceBlockBody<T extends BlockType>(
voluntaryExits,
};

this.logger.verbose("Produced phase0 beacon block body", {slot: blockSlot, numAttestations: attestations.length});

const blockEpoch = computeEpochAtSlot(blockSlot);

if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) {
Expand All @@ -137,12 +145,25 @@ export async function produceBlockBody<T extends BlockType>(
(blockBody as altair.BeaconBlockBody).syncAggregate = syncAggregate;
}

const fork = currentState.config.getForkName(blockSlot);
Object.assign(logMeta, {
attestations: attestations.length,
deposits: deposits.length,
voluntaryExits: voluntaryExits.length,
attesterSlashings: attesterSlashings.length,
proposerSlashings: proposerSlashings.length,
});

if (isForkExecution(fork)) {
const safeBlockHash = this.forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
const feeRecipient = this.beaconProposerCache.getOrDefault(proposerIndex);
const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
const feeRecipientType = requestedFeeRecipient
? "requested"
: this.beaconProposerCache.get(proposerIndex)
? "cached"
: "default";

Object.assign(logMeta, {feeRecipientType, feeRecipient});

if (blockType === BlockType.Blinded) {
if (!this.executionBuilder) throw Error("Execution Builder not available");
Expand Down Expand Up @@ -182,6 +203,8 @@ export async function produceBlockBody<T extends BlockType>(
}
(blockBody as deneb.BlindedBeaconBlockBody).blobKzgCommitments = blobKzgCommitments;
blobsResult = {type: BlobsResultType.blinded};

Object.assign(logMeta, {blobs: blobKzgCommitments.length});
} else {
blobsResult = {type: BlobsResultType.preDeneb};
}
Expand Down Expand Up @@ -212,6 +235,8 @@ export async function produceBlockBody<T extends BlockType>(
blockValue = BigInt(0);
} else {
const {prepType, payloadId} = prepareRes;
Object.assign(logMeta, {executionPayloadPrepType: prepType});

if (prepType !== PayloadPreparationType.Cached) {
// Wait for 500ms to allow EL to add some txs to the payload
// the pitfalls of this have been put forward here, but 500ms delay for block proposal
Expand All @@ -225,6 +250,7 @@ export async function produceBlockBody<T extends BlockType>(
const {executionPayload, blobsBundle} = engineRes;
(blockBody as allForks.ExecutionBlockBody).executionPayload = executionPayload;
blockValue = engineRes.blockValue;
Object.assign(logMeta, {transactions: executionPayload.transactions.length});

const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime);
this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime);
Expand Down Expand Up @@ -265,6 +291,8 @@ export async function produceBlockBody<T extends BlockType>(
return blobSidecar;
}) as deneb.BlobSidecars;
blobsResult = {type: BlobsResultType.produced, blobSidecars, blockHash};

Object.assign(logMeta, {blobs: blobSidecars.length});
} else {
blobsResult = {type: BlobsResultType.preDeneb};
}
Expand Down Expand Up @@ -299,8 +327,15 @@ export async function produceBlockBody<T extends BlockType>(
if (ForkSeq[fork] >= ForkSeq.capella) {
// TODO: blsToExecutionChanges should be passed in the produceBlock call
(blockBody as capella.BeaconBlockBody).blsToExecutionChanges = blsToExecutionChanges;
Object.assign(logMeta, {
blsToExecutionChanges: blsToExecutionChanges.length,
withdrawals: (blockBody as capella.BeaconBlockBody).executionPayload.withdrawals.length,
});
}

Object.assign(logMeta, {blockValue});
this.logger.verbose("Produced beacon block body", logMeta);

return {body: blockBody as AssembledBodyType<T>, blobs: blobsResult, blockValue};
}

Expand Down
Loading

0 comments on commit fa5c6cf

Please sign in to comment.