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

blocksv3: add ignore_builders flag #377

Closed
wants to merge 2 commits into from

Conversation

eserilev
Copy link

@eserilev eserilev commented Dec 5, 2023

The new blocksv3 endpoint doesn't provide validator clients with the ability to express wether to fetch a block from the builder relay or the local execution client. For example, the Lighthouse VC has a builder-proposal flag that, when set, will always attempt to fetch a block from the builder relay. Since the LH VC uses the blocksv2 endpoints, the flag just simply decides wether to attempt to fetch a block from the blinded payload endpoint or the full payload endpoint. With the consolidation of these two endpoints into the new blocksv3 endpoint, validators no longer have the ability to choose between fetching from the builder relay or the local execution client. If a user were to run multiple VCs and wanted some to use the builder relay and others to use the local execution client, they would be forced to run multiple BNs.

This PR suggests a new query param to the blocksv3 endpoint that, when set to true, will always ignore block builders and attempt to fetch blocks from the local execution client.

Thanks @jimmygchen & Lighthouse team for raising this issue

@mcdee
Copy link
Contributor

mcdee commented Dec 5, 2023

When this endpoint was originally proposed there was significant pushback from some client teams on allowing the validator client to state the source of the payload (builder/local), as it was considered that it was the job of the beacon node to decide if to use a relay or not. Hence there was no such control in the endpoint.

As such, I would want to see agreement on this change from the client teams (and specifically what happens when ignore_builders=false is passed to the endpoint) before it was merged to avoid inconsistent implementations.

@rolfyone
Copy link
Collaborator

rolfyone commented Dec 5, 2023

Any client that hasn't implemented this would basically look the same as if they are ignoring the setting, it'd be confusing as a consumer to figure out what's going on, so i could imagine this being the source of several downstream bugs...

I'm not saying we shouldn't do this, just fair warning is my intent...

@michaelsproul
Copy link
Collaborator

The ship hasn't sailed on v3 – we're still in the process of testing it on devnets. I think it would be OK to get clients to commit to supporting ignore_builders for their testnet/mainnet Deneb releases, if that is deemed desirable.

@mcdee Lighthouse VC (and maybe others) have supported this flow of some validators using builders and others not using builders for a long time, so I worry we'll break some people's setups if we don't add this flag. The workaround of having to run separate "builder BNs" and "local BNs" is kind of annoying, especially if you're running keys on behalf of another party and need to switch them around.

I feel like Consensys Staking are probably using the per-validator builder config, can you confirm @jmcruz1983?

@g11tech
Copy link
Contributor

g11tech commented Dec 5, 2023

i would like to propose an alternative and more comprehensive flag in the query params: builder_selection something which has been serving lodestar quite well and we feel would be a value add to upstream it in produceblockv3 :

export enum BuilderSelection {
  BuilderAlways = "builderalways",
  MaxProfit = "maxprofit",
  /** Only activate builder flow for DVT block proposal protocols */
  BuilderOnly = "builderonly",
  /** Only builds execution block*/
  ExecutionOnly = "executiononly",
}
  • builderalways: always chooses builder if builder block is produced else engine (useful in debugging scenarios)
  • maxprofit: whichever pays out more (default)
  • builderonly: no execution block production triggered, so if builder block is not produced the api will fail (useful in DVT)
  • executiononly: not to trigger builder even if builder is configured on the beacon, for e.g. not ok with choice of a friends builders

https://github.com/ChainSafe/lodestar/blob/5201ac40cc4eb5cfa5235e5cb718047572c9441d/packages/api/src/beacon/routes/validator.ts#L42:L49

cc @nflaig

@jimmygchen
Copy link
Contributor

Interesting! I can see how these flags could be potentially useful.

There are similar options at the beacon node level in Lighthouse, and I've used them for testing too. Although it feels like having this level of granularity via the API could add complexity, as clients may already have different options (e.g. prefer builder, profit threshold, max profit etc) and different ways of controlling payload selection at the BN level, and this adds more combinations and could lead to unexpected behaviour when using different BN/VC combinations. Do we always priortise the HTTP param over the BN configuration, or the other way around?

@nflaig
Copy link
Collaborator

nflaig commented Dec 5, 2023

Do we always priortise the HTTP param over the BN configuration, or the other way around?

As the purpose of this PR is to give the validator client more control over the payload selection I'd say HTTP param should be prioritised.

@eserilev
Copy link
Author

eserilev commented Dec 5, 2023

I believe additional controls on the VC side, in general, provide a better user experience. The question is how much control makes sense, especially within the context of some of the drawbacks that were mentioned above.

In the case where a client doesn't support a subset (or all) builder_selection options, we would simply fallback to the default functionality. Falling back to default without communicating that to the user seems like bad UX. Maybe we could define some 2xx status code to inform the user that the request succeeded but the builder_selection flag was ignored? In that case, the bare minimum implementation here would be to provide the relevant status code if a builder_selection flag was provided but not supported by the BN.

@mcdee
Copy link
Contributor

mcdee commented Dec 5, 2023

Maybe we could define some 2xx status code to inform the user that the request succeeded but the builder_selection flag was ignored?

Please, no. If it's going into the standard we should have agreement from all client teams that they are happy implementing it.

@rolfyone
Copy link
Collaborator

rolfyone commented Dec 6, 2023

The BuilderSelection i would be ok with, but agree that weird return codes would be very sub-optimal...

I'm not fully across the builder flows to know if 'maxprofit' will work, but I've circulated the PR in the team to see if there's feedback...

BuilderAlways and BuilderOnly is curious - the latter mentioning DVT which not all clients support, so this is potentially a scenario that some clients won't be able to support yet... It's hard to say 'clients need to support all the things' when pre-requisites exist like DVT...

@tbenr
Copy link
Contributor

tbenr commented Dec 6, 2023

In teku we have a comparison factor and we already have an issue to allow this configuration to be specified per-validator instead of being a beacon node configuration applied to all connected keys.

Consensys/teku#7123

https://docs.teku.consensys.io/reference/cli#builder-bid-compare-factor

So if we generalize the maxprofit to a comparison factor, this will solve our problem "how to pass this configuration from VC to BN".

We already support the builder_always mode, I see the benefits of the other modes too.

@michaelsproul
Copy link
Collaborator

michaelsproul commented Dec 6, 2023

The 1st part of this comment is what I started writing before I had what I think is a good idea (see 2nd section)


thought process

I'm trying to work out how to proceed on this. I can't make a compelling case for why ignore_builders should be per-validator while other configuration knobs should not. But then we open up a whole can of worms. Lighthouse currently has around 4 configuration options affecting block production:

  • always-prefer-builders: does what it says on the tin
  • builder-profit-threshold: only use builder if payout greater than N (duplicate of mev-boost's min-bid)
  • should-override-percentage-threshold: ignore the EL's recommendation to build locally if the builder block is N% more profitable (this is maybe dubious, do you guys have this?)
  • builder_proposals (already per validator): control whether the validator accepts builder blocks (false equivalent to execution_only/local_only, true equivalent to max_profit).

And then there's builder_only which we currently have no equivalent for. In the case of the builder-profit-threshold and the override-percentage-threshold, the numeric values would need to be communicated to the BN as part of the builder_selection. Probably it would be cleaner to have one percentage value like Teku's 😮 ------>


what I think is a good idea

I think the comparison factor (a la Teku) could encode a lot of cases! If we let the comparison factor be c and we take the local block whenever c * local_block_value / 100 >= builder_block_value then:

  • builder_always is c=0 (except when builder_block_value=0 which IMO is irrelevant)
  • local_always is c=inf (maybe encoded as c=INT_MAX and using saturating arithmetic)
  • max_profit is c=100
  • other preferences are also expressible (similar to Lighthouse's thresholds)

There is no equivalent for builder_only, but that kind of confirms my suspicion that it isn't quite like the others. I think if we standardised this comparison factor then in Lighthouse we would do away with the other options and just use this for everything. On the "front-end" the interface can present all sorts of niceties, but on the backend it's just a single uint64 that gets transmitted from VC -> BN.

Thanks @tbenr for lighting the way!


PS: using snake_case throughout to be consistent with other endpoints

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

@michaelsproul how would this play with the circuit breakers currently within lighthouse?

(BTW would be good to call it builder_block_value rather than execution_block_value, as the latter is ambiguous.)

@michaelsproul
Copy link
Collaborator

Thanks @mcdee, fixed!

For the circuit breakers, I think these would need to remain configurable per-BN. Arguably they shouldn't be meddled with very often, as they're a liveness protection mechanism.

Similarly, if some clients wanted to support DVT/builder_only then this could be a per-BN flag for the same reason (risks liveness and should not be used in the majority of cases).

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

The problem then is that you end up with parameters you're sending to the beacon node that may or may not be ignored, depending on the state of the chain and the configuration of the beacon node.

I'd be more than happy to have some way of controlling block production from the validator client, but only if parameters sent in with the request are honored. If they are advisory only, and each beacon node has its own set of rules as to what it actually does based on criteria that are invisible to the validator client (not just the beacon node, but also the state of the MEV relays and network connectivity to them), it feels like we're letting ourselves in for potential confusion down the line e.g. "I said I wanted to only use a builder execution payload (perhaps for OFAC), and it gave me a local one instead (with a proscribed transaction in it)".

@michaelsproul
Copy link
Collaborator

The problem then is that you end up with parameters you're sending to the beacon node that may or may not be ignored, depending on the state of the chain and the configuration of the beacon node.

For users that really care about this, there's still a way to achieve it without per-validator config for these BN-specific parameters. E.g. in Lighthouse you could run the BN with --builder-fallback-disable-checks.

each beacon node has its own set of rules as to what it actually does based on criteria that are invisible to the validator client (not just the beacon node, but also the state of the MEV relays and network connectivity to them),

I'm not sure what you meant by mentioning network connectivity here, but I think it's a salient example. Even if we try to cede as much control as possible to the VC, the BN is still going to return a local block if e.g. the MEV relay completely times out or fails to produce a block. I think given we can't give 100% control to the VC, then best-effort measures are OK.

"I said I wanted to only use a builder execution payload (perhaps for OFAC), and it gave me a local one instead (with a proscribed transaction in it)".

For users that want this they can enforce it on the VC side as a last line of defence, i.e. reject all non-builder blocks returned from the v3 API. Although I personally would not support this feature in the Lighthouse VC, because it harms the network.

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

I think given we can't give 100% control to the VC, then best-effort measures are OK.

To be clear, I agree with the situation at current where a beacon node will build a local block if it deems it the best option to do so (e.g. circuit breaker activated). I worry more about the fact that this is best-efforts isn't communicated clearly.

Although I personally would not support this feature in the Lighthouse VC, because it harms the network.

Agreed, which is why I'm wary of having a parameter that suggests that one thing will happen (e.g. only builder-built block) when in reality something different may happen.

Perhaps the solution to my angsting is simply to rename the parameter to something that makes it clear that this is a preference or hint, as opposed to a constraint.

@michaelsproul
Copy link
Collaborator

Perhaps the solution to my angsting is simply to rename the parameter to something that makes it clear that this is a preference or hint, as opposed to a constraint.

Ah I see where you're coming from! My proposal is to just add the "comparison factor" to the existing API, which would avoid any certain language (like "always") in the BN spec. We could document that this parameter will be used by the BN if it is possible & deemed safe to propose either of the local or builder blocks. The VCs could then use less certain language as well like prefer-builder, prefer-local, or just expose the comparison factor param by name.

@g11tech
Copy link
Contributor

g11tech commented Dec 6, 2023

i think if a beacon doesn't support any of the options, they should error so that validator knows if the options have been respected or not, and the onus is on the one running the validator to make sure bns he/she is running with honor the options he has specified.

this allows one to have desired behavior w.r.t. what validator wants and what a beacon client currently supports

@g11tech
Copy link
Contributor

g11tech commented Dec 6, 2023

i like comparison factor to reduce the options space and could just be supported with addition of a new enum: c=N with effect as defined above, but i would still like to retain very straightforward values even if derivable from c=N (apart from the others which are not derivable like builder_only, execution_only where the builder/engine apis arent even triggered for e.g.)

so we can say some values each client have to support, and some values as optional ( e.g. builder_only)

@michaelsproul
Copy link
Collaborator

so we can say some values each client have to support, and some values as optional ( e.g. builder_only)

Is there a use-case for builder_only on a per-validator basis? If it's for DVT can we assume the DVT validators are using their own BN which they can configure? Or is it possible to share a BN between a regular VC & DVT VC with the middleware taking care of the DVT-specific stuff?

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

i think if a beacon doesn't support any of the options, they should error...

That would be no fun for any large-scale operation that deals with multiple beacon nodes that can be individually upgraded.

...the onus is on the one running the validator to make sure bns he/she is running with honor the options he has specified.

That doesn't work when the beacon node has situational switches (e.g. circuit breakers).

And having different beacon nodes work or not work with different parameters in the spec would be a significant pain. If this is going to be part of the standard then all beacon nodes should support it.

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

Ah I see where you're coming from! My proposal is to just add the "comparison factor" to the existing API, which would avoid any certain language (like "always") in the BN spec. We could document that this parameter will be used by the BN if it is possible & deemed safe to propose either of the local or builder blocks. The VCs could then use less certain language as well like prefer-builder, prefer-local, or just expose the comparison factor param by name.

If the client teams all agree to implement this, then sure.

@tbenr
Copy link
Contributor

tbenr commented Dec 6, 2023

I'm in favour of having only one param (compare factor) and leave the other options on the BN side.

@michaelsproul we apply the factor to he builder_bid not to the local_block_value.
Local block is choose if local_block_value >= c * builder_bid_value / 100.
In case of a draw, we choose local.

So encoding of builder_always and local_always are exchanged.

If this clients haven't implemented a similar comparison factor, maybe we can go this way so we don't have to do any internal conversion (which may be confusing)

@g11tech
Copy link
Contributor

g11tech commented Dec 6, 2023

i still insist of specifying some optional values, those who want to can implement it

Or is it possible to share a BN between a regular VC & DVT VC with the middleware taking care of the DVT-specific stuff?

yes obol does this
also SSV which i got familiar with recently, they all just run and can share BN/EL with other normal or DVT validators/middlewares

regarding circuit breaker: again leave to the specific beacon implementations to throw or simply do a builder proposal on builder_only, but the beacon should be expected to follow what its been asked for.

That would be no fun for any large-scale operation that deals with multiple beacon nodes that can be individually upgraded.

correct but those maintaining multi BN infra are very capable of handling such complications so that really isn't an issue imo

@mcdee
Copy link
Contributor

mcdee commented Dec 6, 2023

i still insist of specifying some optional values, those who want to can implement it

I'm strongly against this. Making implementation optional means it is very hard to trust the API servers to do one thing or another. Parameters should be well-defined, and agreed upon by all client teams, otherwise we don't have a standard spec.

@g11tech
Copy link
Contributor

g11tech commented Dec 6, 2023

i still insist of specifying some optional values, those who want to can implement it

I'm strongly against this. Making implementation optional means it is very hard to trust the API servers to do one thing or another. Parameters should be well-defined, and agreed upon by all client teams, otherwise we don't have a standard spec.

standardization is already failing hard on this particular flag imo, atleast allowing the interface could be standardized if not the implementations as clients will effectively need to deviate away from the standard.

@jimmygchen
Copy link
Contributor

+1 to having well-defined param values and have all clients respect them, so we don't run into inconsistency and interop issues when running with different BN/VC combinations. I think this would be important for DVT as well, if they could be communicating with multiple different BNs?

@rolfyone
Copy link
Collaborator

rolfyone commented Dec 6, 2023

standardization is already failing hard on this particular flag imo, atleast allowing the interface could be standardized if not the implementations as clients will effectively need to deviate away from the standard.

If this flag is failing hard lets define what its doing wrong and fix it... This is a critical path of block building, we should not be failing hard here.

@michaelsproul
Copy link
Collaborator

I think we're getting closer to a consensus decision.

  • Comparison factor is agreed useful by LH/Teku/Lodestar
  • It seems the best thing is to mandate that the comparison factor is implemented and honoured (modulo builder circuit breaker, which may be turned off at the BN-level if desired). i.e. it is not optional.

The remaining point of contention is builder_only which is desired by Lodestar, but is yet to reach consensus (I am skeptical of its usefulness).

@g11tech Is there any reason why DVT validators can't use prefer_builder (c=inf in Teku's notation) instead of builder_only? If it's just a matter of wasting a little work by building a local block when a builder block is desired, then I think this might be acceptable? For users that really don't want to waste this work and running 100% DVT, they can always turn it off at the BN level. Would this be an acceptable compromise?

The alternative that I see is having to define multiple query parameters, either comparison_factor and builder_only (mutually exclusive) or builder_selection and some profit threshold param (mutually exclusive?).

@james-prysm
Copy link
Contributor

There are a lot of configuration options put on the beacon node itself, I'd like to not see more options added to this API. we might have disagreements on the intended flows, as APIs may conflict with beacon node settings, it took a while to reach consensus on the states we get into for keymanager APIs and I feel like this is similar.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

@michaelsproul

@g11tech Is there any reason why DVT validators can't use prefer_builder (c=inf in Teku's notation) instead of builder_only?

the only diff is that the api should fail in case there is no builder block and musn't return with local. this is important for DVT because they all should get the same block to sign or not.

This behavior isn't really hard to implement imo and should be supported.

For users that really don't want to waste this work and running 100% DVT, they can always turn it off at the BN level.

I am for e.g. running solo + DVT from the same BNs (on holesky yet, but also looking to replicate on mainnet as well if things go well) and hence beacon level turning off doesnt work.

The alternative that I see is having to define multiple query parameters, either comparison_factor and builder_only (mutually exclusive) or builder_selection and some profit threshold param (mutually exclusive?).

yes any of these would work, though i would prefer the later solution as it seems more elegant to me.

@rolfyone

If this flag is failing hard lets define what its doing wrong and fix it... This is a critical path of block building, we should not be failing hard here.

I agree and we should incorporate the new use cases like DVT because standardization paves way for client diversity

@potuz

always take input from the local payload about the presence of censorship in the shouldOverrideBuilder flag.

i think this is a good idea and one can fail/error builder_only if shouldOverrideBuilder flag is there i.e. engine block is produced for determining censorship but still not returned.

So I am fine with local block always being produced for determining censorship but still the block production needs to follow the semantics of the passed builder_selection flag and fail/error hard if the request can't be processed as per the desired flags rather than silently ignoring the flags and responding with fallbacks

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

So I am fine with local block always being produced for determining censorship but still the block production needs to follow the semantics of the passed builder_selection flag and fail/error hard if the request can't be processed as per the desired flags rather than silently ignoring the flags and responding with fallbacks

I don't agree with this. One of the reasons for the metadata in the v3 response is that it provides enough information for the validator client to decide if it wants to work with the returned data or not.

If the validator client requests a blinded block but the consensus node does not want to provide it (if, for example, as in potuz's example the execution node has detected censorship) then it makes sense for the beacon node to return a locally built payload. There is very little downside in doing so (time to encode and shift the data over the wire) and the benefit is that the payload is available if the validator client wishes to use it. The validator client will easily be able to understand from the metadata that regardless of the fact that it wanted a payload from the builder the consensus node was only willing to provide one from the local execution node, so if it truly doesn't want to build a block it can error out itself.

I think that the principles we have here are:

  • consensus nodes will return what they deem best for the network, taking into account the proposer's preferences
  • consensus nodes should try as hard as they can to provide some sort of block the proposer can sign

These both seem reasonable to me, is there any disagreement here? If not then these should be able to guide what the API does.

@tbenr
Copy link
Contributor

tbenr commented Dec 7, 2023

The validator client will easily be able to understand from the metadata that regardless of the fact that it wanted a payload from the builder the consensus node was only willing to provide one from the local execution node, so if it truly doesn't want to build a block it can error out itself.

The problem with this is that you assume that a locally built block will produce a non-blind response. To me there is no such strong correlation, infact teku is currently returning blinded only due to current limitations (we will improve soon). In any case a BN could theoretically have an option to return blinded only for whatever reason.

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

The problem with this is that you assume that a locally built block will produce a non-blind response.

That was already part of the discussion for v3, and should be in the spec. Otherwise we're relying on the beacon node retaining state to allow the validator client to produce the block.

@tbenr
Copy link
Contributor

tbenr commented Dec 7, 2023

That was already part of the discussion for v3, and should be in the spec. Otherwise we're relying on the beacon node retaining state to allow the validator client to produce the block.

I get the stateless-stateful argument, but if local MUST be returned as unblinded, than I think we should rename from "blinded" to "builder" or similar. But that's off topic.

@tbenr
Copy link
Contributor

tbenr commented Dec 7, 2023

I think that the principles we have here are:

  • consensus nodes will return what they deem best for the network, taking into account the proposer's preferences

  • consensus nodes should try as hard as they can to provide some sort of block the proposer can sign

These both seem reasonable to me, is there any disagreement here? If not then these should be able to guide what the API does.

The only concern I have is that, if the builder flow is used for DVT flows, it doesn't mean that censorship check are not done down the line.
So if there are deployments that requires flows to go over builder flow and any local checks are meaningless, than, if you want to run a mixed set of validators (a solo + DVT) then you want this to be controlled per validator, which requires a dedicated param to encode this. This is the argument from @g11tech . I'm not an expert of this alternative flows so correct me if I'm wrong.

@potuz
Copy link

potuz commented Dec 7, 2023

From what I read in this thread it seems that the fundamental point of contention here is whether the VC or the BN should decide the contents of the block. Given my stance up there about not allowing the easier bypassing of the anti-censorship defaults, I am of course on the camp that the BN should have the final say here.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

From what I read in this thread it seems that the fundamental point of contention here is whether the VC or the BN should decide the contents of the block. Given my stance up there about not allowing the easier bypassing of the anti-censorship defaults, I am of course on the camp that the BN should have the final say here.

I am fine with BN having a final say, but in the case that BN can't honor builder_only it should throw error and not resort with a local block

@tbenr

So if there are deployments that requires flows to go over builder flow and any local checks are meaningless, than, if you want to run a mixed set of validators (a solo + DVT) then you want this to be controlled per validator, which requires a dedicated param to encode this. This is the argument from @g11tech . I'm not an expert of this alternative flows so correct me if I'm wrong.

yes thats correct

@nflaig
Copy link
Collaborator

nflaig commented Dec 7, 2023

I am of course on the camp that the BN should have the final say here.

Technically, doesn't the beacon node just provide a suggestion on what to sign and publish? The validator has the keys and hence the final say on that, it can get the payload from multiple BNs or even the builder directly.

For example, the validator client can already prevent builder blocks by not calling registerValidator on the beacon node. As far as I am aware, all implementations only call this API if builder is explicitly enabled (via --builder flag or similar).

This implicitly addresses the problem statement of this PR

If a user were to run multiple VCs and wanted some to use the builder relay and others to use the local execution client, they would be forced to run multiple BNs.

A validator client without builder enabled will only produce local blocks as builder payload requests will always fail.

Considering this, I think it might make it even more important to have the HTTP param to indicate to the beacon node that it should not wait (and delay block proposal) for a builder response as it will fail anyways due to missing registration.

Alternatively, the beacon node could keep track of registered pubkeys and skip builder blocks for validators that never registered. This might be problematic if a multiple BNs are used and introducing an additional cache is probably not desired.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

That was already part of the discussion for v3, and should be in the spec. Otherwise we're relying on the beacon node retaining state to allow the validator client to produce the block.

I get the stateless-stateful argument, but if local MUST be returned as unblinded, than I think we should rename from "blinded" to "builder" or similar. But that's off topic.

I am also against mandating that BN can't be configured to revert with a blinded version of a local block because most of the small/solo setups have validators just hooked to 1 BN and can potential leverage on latency if blinded versions are send for signing to the validators. This might be more meaningful post deneb where there are blobs (keep in mind that max num blobs per block might blow up in future HFs)

So I would like that BNs should be free to provide implementations where they can respond with blinded even for the full block by supporting an explicit flag to do this (BN side, optional to implement)

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

but in the case that BN can't honor builder_only it should throw error and not resort with a local block

What is the rationale behind doing this and not returning a locally produced block, clearly stated as such?

We're trying to build blocks here, after all. I don't see what the downside of giving a local block if the beacon node has built it. The validator client can still decide not to use it, if it really doesn't want to.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

but in the case that BN can't honor builder_only it should throw error and not resort with a local block

What is the rationale behind doing this and not returning a locally produced block, clearly stated as such?

We're trying to build blocks here, after all. I don't see what the downside of giving a local block if the beacon node has built it. The validator client can still decide not to use it, if it really doesn't want to.

DVTs' proposals seem run in two ways:

  1. Round robin by electing one of the nodes to build block to propose and circulate it for signing
  2. by having a shared block sourced from builders and aggregating the signature.

So for 2, they need a deterministic output (given a matching set of builders)

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

DVTs proposals seem run in two ways:

1. Round robin by electing one of the nodes to propose

2. by having a shared block sourced from builders and aggregating the signature.

So for 2, they need a deterministic output (given a matching set of builders

We're not just building for DVT, but for DVT and option 2 above they can do the following:

  1. request a blinded block
  2. error if they don't receive a blinded block

Returning a locally built payload does not impact this workflow.

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

I am also against mandating that BN can't be configured to revert with a blinded version of a local block...

The nimbus folks were pretty strongly in favour of making the process as stateless as possible. And any system that uses multiple beacon nodes would fail if beacon nodes didn't return the full info.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

I am also against mandating that BN can't be configured to revert with a blinded version of a local block...

The nimbus folks were pretty strongly in favour of making the process as stateless as possible. And any system that uses multiple beacon nodes would fail if beacon nodes didn't return the full info.

only if explicitly configured by a flag on beacon blinded response would be returned. Again the one who is hooking the validator to BNs is supposed to know BN configurations, so by default it would be stateless only

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

DVTs proposals seem run in two ways:

1. Round robin by electing one of the nodes to propose

2. by having a shared block sourced from builders and aggregating the signature.

So for 2, they need a deterministic output (given a matching set of builders

We're not just building for DVT, but for DVT and option 2 above they can do the following:

1. request a blinded block

2. error if they don't receive a blinded block

Returning a locally built payload does not impact this workflow.

yes thats one hack, but again we also want to be able to configure the beacon to respond a local block in blinded version if configured that way.

I don't understand the opposition to throwing error on a query value builder_only and resorting to hacks and limiting the flexibility. if someone is producing a proposal with builder_only they are pretty clear about what they want and its easy to support with just marginal cost of ensuring that in the code.

@mcdee
Copy link
Contributor

mcdee commented Dec 7, 2023

I don't understand the opposition to throwing error on a query value builder_only and resorting to hacks and limiting the flexibility.

I don't see this as limiting flexibility, it seems to be adding an additional parameter (and complexity) for no gain.

In your example:

  1. validator sends a request for a block with builder_only parameter
  2. beacon node for whatever reason decides not to return a builder-supplied payload
  3. beacon node returns an error

In my example:

  1. validator sends a request for a block with `builder_factor set to 100
  2. beacon node for whatever reason decides not to return a builder-supplied payload
  3. beacon node returns a locally-built block

The only difference in the DVT validator client is that its error path kicks in when it doesn't receive a blinded block, rather than when it receives an error. And we lose the requirement for the additional builder_only parameter with the complexity that another flag brings with it.

@g11tech
Copy link
Contributor

g11tech commented Dec 7, 2023

I don't understand the opposition to throwing error on a query value builder_only and resorting to hacks and limiting the flexibility.

I don't see this as limiting flexibility, it seems to be adding an additional parameter (and complexity) for no gain.

In your example:

1. validator sends a request for a block with `builder_only` parameter

2. beacon node for whatever reason decides not to return a builder-supplied payload

3. beacon node returns an error

In my example:

1. validator sends a request for a block with `builder_factor set to 100

2. beacon node for whatever reason decides not to return a builder-supplied payload

3. beacon node returns a locally-built block

in that case lets just the rename executionPayloadBlinded to executionPayloadBuilder in the response to mean what it really is so that we can extend the API if need be to support sending blinded versions of local block in future if we want it to be.
then i am alright with the above changes

@tbenr
Copy link
Contributor

tbenr commented Dec 7, 2023

in that case lets just the rename executionPayloadBlinded to executionPayloadBuilder in the response to mean what it really is so that we can extend the API if need be to support sending blinded versions of local block in future if we want it to be.
then i am alright with the above changes

I agree with this. As said previously, I don't like that we are associating a data format (blind or unblind) with the source of the data (locally or externally generated). We can enforce it to be the same thing in the spec but I think it is not a good design.

adding a execution_payload_source: enum[local, builder] (or external) I think would be more precise.

@michaelsproul
Copy link
Collaborator

I've made a PR for the builder_comparison_factor here: #386.

I haven't added execution_payload_source to that PR, but wouldn't oppose a follow-up PR with that change.

@g11tech
Copy link
Contributor

g11tech commented Dec 11, 2023

I've made a PR for the builder_comparison_factor here: #386.

I haven't added execution_payload_source to that PR, but wouldn't oppose a follow-up PR with that change.

so #386 makes this PR redundant right?

@michaelsproul
Copy link
Collaborator

yeah this PR is redundant if we agree on #386

@eserilev
Copy link
Author

closing this in favor of #386

@eserilev eserilev closed this Dec 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants