Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(block-builder): a few minor cleanups #2412

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

abi87
Copy link
Collaborator

@abi87 abi87 commented Jan 25, 2025

This PR collects a few minor cleanup I collected while reviewing the block building code:

  • Early return from BuildBlockAndSidecars in case block building is disabled (as it could be for full nodes)
  • Consolidated checks over nil execution payload.
    • This required some changes to the rpc.Client to simplify the unit test that proves it
  • drop remotePayloadBuilders which are not really used at this point in time
  • minor improvement to app.toml config

startTime := time.Now()
defer s.metrics.measureRequestBlockForProposalTime(startTime)

// payload builder is disabled, so nothing to do
if s.localPayloadBuilder.Enabled() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

a minor optimization: if block building is disabled (as it should be, e.g. in full nodes) we could return early here

Comment on lines -53 to -55
// remotePayloadBuilders represents a list of remote block builders, these
// builders are connected to other execution clients via the EngineAPI.
remotePayloadBuilders []PayloadBuilder
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not sure what is this for, but not really used. Dropped

@@ -65,6 +65,8 @@ implementation = "{{.BeaconKit.KZG.Implementation}}"
[beacon-kit.payload-builder]
# Enabled determines if the local payload builder is enabled.
# It should be enabled for validators, but it can be disabled
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hopefully this clarifies how this variable should be set

Copy link

codecov bot commented Jan 25, 2025

Codecov Report

Attention: Patch coverage is 7.57576% with 61 lines in your changes missing coverage. Please review.

Project coverage is 27.30%. Comparing base (2afec05) to head (6b1866b).

Files with missing lines Patch % Lines
payload/builder/payload.go 0.00% 22 Missing ⚠️
beacon/validator/block_builder.go 0.00% 16 Missing ⚠️
beacon/validator/service.go 0.00% 9 Missing ⚠️
execution/client/client.go 0.00% 8 Missing ⚠️
execution/client/ethclient/rpc/client.go 0.00% 5 Missing ⚠️
execution/client/ethclient/rpc/header.go 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2412      +/-   ##
==========================================
+ Coverage   27.12%   27.30%   +0.18%     
==========================================
  Files         351      350       -1     
  Lines       15523    15482      -41     
  Branches       20       20              
==========================================
+ Hits         4210     4227      +17     
+ Misses      11110    11052      -58     
  Partials      203      203              
Files with missing lines Coverage Δ
execution/client/ethclient/engine.go 15.71% <100.00%> (+15.71%) ⬆️
execution/client/ethclient/ethclient.go 100.00% <100.00%> (+100.00%) ⬆️
node-core/components/validator_service.go 0.00% <ø> (ø)
execution/client/ethclient/rpc/header.go 0.00% <0.00%> (ø)
execution/client/ethclient/rpc/client.go 0.00% <0.00%> (ø)
execution/client/client.go 0.00% <0.00%> (ø)
beacon/validator/service.go 0.00% <0.00%> (ø)
beacon/validator/block_builder.go 0.00% <0.00%> (ø)
payload/builder/payload.go 0.00% <0.00%> (ø)

@@ -95,9 +93,6 @@ func (s *Service) BuildBlockAndSidecars(
if err != nil {
return nil, nil, err
}
if envelope == nil {
Copy link
Collaborator Author

@abi87 abi87 Jan 25, 2025

Choose a reason for hiding this comment

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

this check is not necessary since all code path leading here do intercept the condition envelope == nil and return an error.
I added a unit test around GetPayload to show this

return nil, err
}
return result, nil
return result, s.Call(ctx, result, GetPayloadMethodV3, payloadID)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nit for readability, don't feel strongly about this.
The only relevant point here is that ExecutionPayload is not nil

@@ -173,18 +173,13 @@ func (pb *PayloadBuilder) RetrievePayload(
}

payload := envelope.GetExecutionPayload()
if !payload.IsNil() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this check does not make sense. Note that we use payload below, without checking if is nil

@abi87 abi87 force-pushed the block-builder-minor-cleanup branch from 6f62f69 to a2df05f Compare January 25, 2025 17:36
@@ -47,26 +47,27 @@ func (pb *PayloadBuilder) RequestPayloadAsync(
}

if payloadID, found := pb.pc.Get(slot, parentBlockRoot); found {
pb.logger.Warn(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not sure why this is warning, I don't think this is an error condition really?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it should be for validators since if optimistic build is enabled, still we should probably revert to info

@abi87 abi87 self-assigned this Jan 25, 2025
startTime := time.Now()
defer s.metrics.measureRequestBlockForProposalTime(startTime)

if !s.localPayloadBuilder.Enabled() {
Copy link
Collaborator Author

@abi87 abi87 Jan 26, 2025

Choose a reason for hiding this comment

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

a minor optimization: if block building is disabled (as it should be, e.g. in full nodes) we could return early here.
This is currently only done in retrieveExecutionPayload so we partially build the block, to reject it all

@@ -298,7 +291,7 @@ func (s *Service) buildBlockBody(
// Dequeue deposits from the state.
depositIndex, err := st.GetEth1DepositIndex()
if err != nil {
return ErrNilDepositIndexStart
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we silence the error here, which I do not like. Improved the error handling


// ErrNilPayload is an error for when there is no payload
// in a beacon block.
ErrNilPayload = errors.New("nil payload in beacon block")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not used anymore since we do not check in validators anymore that payload is not nil.

// ErrNilBlkBody is an error for when the block body is nil.
ErrNilBlkBody = errors.New("nil block body")

// ErrNilBlobsBundle is an error for when the blobs bundle is nil.
ErrNilBlobsBundle = errors.New("nil blobs bundle")

// ErrNilDepositIndexStart is an error for when the deposit index start is
// nil.
ErrNilDepositIndexStart = errors.New("nil deposit index start")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

dropped and used the real error returned by KvStore getter instead


// TestGetPayloadV3NeverReturnsEmptyPayload shows that execution payload
// returned by ethClient is not nil.
func TestGetPayloadV3NeverReturnsEmptyPayload(t *testing.T) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this UT should give confidence that the payload from GetPayload call is never nil in current implementation

@@ -26,11 +26,11 @@ import (

// Client - Ethereum rpc client.
type Client struct {
*rpc.Client
rpc.Client
Copy link
Collaborator Author

@abi87 abi87 Jan 26, 2025

Choose a reason for hiding this comment

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

I replaced the rpc.Client implementation with an interface to ease up unit testing (allows easier mocks/stubs.

// convenient way to interact with an Ethereum node.
type Client struct {
type client struct {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

unexported as much as possible

Comment on lines +82 to +83
jwtSecret: secret,
jwtRefreshInterval: jwtRefreshInterval,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

for a limited number of parameters I much prefer passing them explicitly in the New function rather than using options.
Options seems to be strictly related to the implementation of Client interface and I have found an easy way to mock them.

)

// WithJWTSecret sets the JWT secret for the RPC client.
func WithJWTSecret(secret *jwt.Secret) func(rpc *Client) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We do use this approach with options in other parts of the codebase, but I personally don't really see much value to it.
We don't usually build structs in multiple ways, i.e. we don't generally have a struct specifying some options and not others.
If I am missing something, LMK

@abi87 abi87 marked this pull request as ready for review January 26, 2025 20:48
@abi87 abi87 requested a review from a team as a code owner January 26, 2025 20:48
@abi87 abi87 changed the title chore(block-builder): minor cleanups chore(block-builder): a few minor cleanups Jan 26, 2025
Comment on lines -70 to -76
Client: ethclient.New(
ethclientrpc.NewClient(
cfg.RPCDialURL.String(),
ethclientrpc.WithJWTSecret(jwtSecret),
ethclientrpc.WithJWTRefreshInterval(
cfg.RPCJWTRefreshInterval,
),
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

just moved the instantiation of ethClient up and replace the options with actual parameter in its New function

eip4844.KZGCommitment, eip4844.KZGProof, eip4844.Blob,
eip4844.KZGCommitment,
eip4844.KZGProof,
eip4844.Blob,
]]{
ExecutionPayload: t.Empty(version.Deneb),
Copy link
Collaborator Author

@abi87 abi87 Jan 26, 2025

Choose a reason for hiding this comment

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

This is one of key point of this cleanup: ExecutionPayload is never nil, cause Empty is the default empty ExecutionPayloadEnvelope struct.
I added a UT to verify it

@@ -166,29 +167,9 @@ func (pb *PayloadBuilder) RetrievePayload(
return nil, err
}

overrideBuilder := envelope.ShouldOverrideBuilder()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

below is just stuff for logging. I consolidated it slightly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant