Skip to content

feat: add block_hash and builder_index to block event - #9854

Draft
markolazic01 wants to merge 9 commits into
ChainSafe:unstablefrom
markolazic01:feat/block-event-new-fields
Draft

feat: add block_hash and builder_index to block event#9854
markolazic01 wants to merge 9 commits into
ChainSafe:unstablefrom
markolazic01:feat/block-event-new-fields

Conversation

@markolazic01

@markolazic01 markolazic01 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Motivation

Adapting block event for Gloas PoC.

Description

Introduces 2 new fields, block_hash and builder_index to the block event.
Related wiring and test adaptation.
Skipping oapi spec test for block event until spec tests are updated with new event fields.

AI Assistance Disclosure

Used Claude to audit the changes.

Comment on lines 532 to 543
const gloasFields = isGloasBeaconBlock(block.message)
? {
blockHash: toRootHex(block.message.body.signedExecutionPayloadBid.message.blockHash),
builderIndex: block.message.body.signedExecutionPayloadBid.message.builderIndex,
}
: {};
this.emitter.emit(routes.events.EventType.block, {
block: blockRootHex,
slot: blockSlot,
executionOptimistic: blockSummary != null && isOptimisticBlock(blockSummary),
...gloasFields,
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be made type safe somehow?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah it probably is fine either way, I don't think there is a good way to enforce the event itself to require blockhash and builderindex after gloas

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found a better solution than this so far

Comment on lines +85 to +86
blockHash: stringType,
builderIndex: ssz.BuilderIndex,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would like these fields after block and before executionOptimistic

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some quick drive-by comments 😄

@markolazic01

Copy link
Copy Markdown
Contributor Author

thank you very much @nflaig 😃

@markolazic01
markolazic01 marked this pull request as ready for review August 19, 2026 17:15
@markolazic01
markolazic01 requested a review from a team as a code owner August 19, 2026 17:15
@markolazic01

Copy link
Copy Markdown
Contributor Author

There was e2e action fail which seems to be fixable with a re-run.
Unit tests pass now, oapi spec block test is skipped until the spec is updated.
Description updated.

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @markolazic01 for looking into this, I am a bit skeptical after seeing the implementation if this is really a good direction, besides the fact that it's kinda implicit that clients should add these fields on the spec side, it seems also kinda error prone on the implementation side, and seeing that it looks a bit hacky even on our code I am not so certain it's a good direction for the spec

fromJson: (json) =>
(config.getForkSeq((json as {slot: Slot}).slot) >= ForkSeq.gloas ? blockGloas : blockBase).fromJson(json),
},
[EventType.blockGossip]: new ContainerType(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kinda warrants the question if we should also update block_gossip event

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, we should probably do it

@markolazic01

Copy link
Copy Markdown
Contributor Author

thanks @markolazic01 for looking into this, I am a bit skeptical after seeing the implementation if this is really a good direction, besides the fact that it's kinda implicit that clients should add these fields on the spec side, it seems also kinda error prone on the implementation side, and seeing that it looks a bit hacky even on our code I am not so certain it's a good direction for the spec

I agree, I am happy to reimplement this if you have another approach in mind, at least we discovered that this isn't the best way to do it. We can discuss a new solution on discord.

@markolazic01
markolazic01 marked this pull request as draft August 19, 2026 21:17
nflaig pushed a commit that referenced this pull request Aug 22, 2026
## Motivation

Split out from the block / builder event PRs (#9854, #9875, #9876) as a
standalone change, as suggested by @markolazic01.

The `eventstream` handler in `getEventsApi` forwards every emitter event
through a single `onEvent({type: topic, message: data})` call, where
`topic` is the full `EventType` union and `data` (and therefore
`message`) is `any`. That object literal only type-checks via
TypeScript's discriminated-union distribution path
(`typeRelatedToDiscriminatedType`), which bails out once the number of
source discriminant combinations exceeds 25.

`EventType` currently has exactly **25** members, so it compiles today.
Adding a **26th** event tips it over the cap and fails with:

```
TS2345: Argument of type '{ type: EventType; message: any; }' is not assignable to parameter of type 'BeaconEvent'.
  Types of property 'type' are incompatible.
    Type 'EventType' is not assignable to type 'EventType.<lastMember>'.
```

which is why each new-event PR currently has to add this cast. Landing
it once here unblocks those PRs without each carrying the change.

## Description

Assert `routes.events.BeaconEvent` at the `onEvent` call. The cast only
makes explicit the type erasure that already exists at this
`chain.emitter` boundary — `message` is `any`, so the topic/message
pairing was never verified by the compiler regardless. The only
cast-free alternative would be to construct the event per-topic instead
of funneling every topic through one union-typed `onEvent({type,
message})` call, which is a larger refactor not worth it here.

**No runtime or current-compile behavior change** on `unstable` (25
`EventType` members).

---
🤖 Generated with AI assistance

---------

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants