Support validator account level relay choice
As a node operator, different customers want to select different sources of MEV. To enable efficient distribution of validator keys across regions and consensus client types, our validator clients hold keys from different customers.
Teku and Lighthouse support specification of fee_recipient at the validator key level.
It would be great if mev-boost / builder-api could utilize the same file but with an added parameter per validator key to select the appropriate relay when that particular key is chosen to propose a block.
This would also enable solo stakers who have more than one validator to explore different sources of MEV without having to run multiple nodes.
Could you provide a specific example?
An issue is that mev-boost and the relay needs to conform to the builder spec: https://ethereum.github.io/builder-specs/
This API spec only allows setting fee_recipient and gas_limit for a specific validator, and mev-boost is just proxying that data to the relays which prepare it for the builders. There is no way for mev-boost to select additional preferences at the builders.
Ah - so, should I raise this at the builder-spec repo?
A specific example:
- One customer "trusts" relays 3,4,5 as sources of MEV
- Another customer "trusts" relays 1,2,3
Right now, the only way to handle this is to have different consensus clients for the two customers with differently associated MEV boost sidecars...
hmmm i see, i think this would indeed be easiest handled in mev-boost. and it seems related to #155, file based relay list, where you could set this relation. we'll discuss internally and report back in a little bit.
For reference, the Teku/Lighthouse config file format looks like this:
{
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
"validator_registration": {
"enabled": true,
"gas_limit": "12345654321"
}
}
},
"default_config": {
"fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
"validator_registration": {
"enabled": false
}
}
}
The most simple config for mev-boost could look like this (and allow per-proposer overrides):
{
"default_config": {
"relays": [
"https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net"
]
}
}
The most simple config for mev-boost could look like this (and allow per-proposer overrides):
{ "default_config": { "relays": [ "https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net" ] } }
wouldn't make sense to add these relay entry inside validator registration?
as "https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net" refers to a particular public key.
my take:
{
"builder_relays_groups": {
"groupA": ["https://[email protected]", "http://..."],
"groupB": ["https://[email protected]", "http://...."]
},
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
"validator_registration": {
"enabled": true,
"builder_relays_group": "groupB",
"gas_limit": "12345654321"
}
}
},
"default_config": {
"fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
"validator_registration": {
"enabled": false,
"builder_relays_group": "groupA"
}
}
}
For simplicity, I would propose following:
{
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
"validator_registration": {
"enabled": true,
"relay": "https://other-builder-relay-kiln.flashbots.net"
"gas_limit": "12345654321"
}
}
},
"default_config": {
"fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
"validator_registration": {
"relay": "https://default-builder-relay-kiln.flashbots.net"
"enabled": false
}
}
}
-
relaysneeds to be an array - i prefer to allow setting
relaysdirectly, not requiring groups - i'd prefer the prop be named only
relaysinstead ofbuilder_relays, but if we want to reuse the same config i see the argument for giving it the longer name for sake of clarity - how about allowing both URL and group reference?
{
"builder_relays_groups": {
"groupB": [
"https://[email protected]",
"http://...."
]
},
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
"validator_registration": {
"enabled": true,
"builder_relays": ["https://[email protected]"],
"gas_limit": "12345654321"
}
}
},
"default_config": {
"fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
"validator_registration": {
"enabled": false,
"builder_relays": ["groupB"]
}
}
}
relaysneeds to be an array- i prefer to allow setting
relaysdirectly, not requiring groups- i'd prefer the prop be named only
relaysinstead ofbuilder_relays, but if we want to reuse the same config i see the argument for giving it the longer name for sake of clarity- how about allowing both URL and group reference?
{ "builder_relays_groups": { "groupB": [ "https://[email protected]", "http://...." ] }, "proposer_config": { "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": { "fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3", "validator_registration": { "enabled": true, "builder_relays": ["https://[email protected]"], "gas_limit": "12345654321" } } }, "default_config": { "fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "validator_registration": { "enabled": false, "builder_relays": ["groupB"] } } }
looks good to me.
Once we find an agreement we should formalize with a schema definition so we can be clear on formats and what is required and what is optional. (ie, in teku we require default_config to be present, and other things too to minimize chances of misconfigurations)
I'm thinking about changing from validator_registration to builder_registration.
{
"proposer_config": {
"0x...": {
"fee_recipient": "0x..",
"builder_registration": {
"enabled": true,
"builder_relays": ["https://[email protected]"],
"gas_limit": "12345654321"
}
}
}
From a validator configuration perspective seems clearer. If that section is being translated in a validator_registration from the perspective of a builder, it's just a technicality.
Looks good too. In this case we could consider changing builder_relays to relays because it's already in the builder context 🤔
For reference: see also the Prysm PR https://github.com/prysmaticlabs/prysm/pull/10992
Just to clarify things : builder_relays, either if it is in the proposer_config or the default_config, is an array of either:
- group references
- relay url
And can also be a combination of both ?
I think it is even better to have builder instead of builder_registration. So we remove the "clash" with the internal validator_registation object.
"builder": {
"enabled": true,
"relays": ["https://[email protected]"],
"gas_limit": "12345654321"
}
Just to clarify things :
builder_relays, either if it is in theproposer_configor thedefault_config, is an array of either:
- group references
- relay url
yes
And can also be a combination of both ?
I vote for maximum flexibility: combination
Hey @james-prysm, in teku we are doing our final review\changes to officially release builder-related params and config.
Doing that I came up with some ideas to improve UX in the proposer config file. I saw you at prysm just merged PRs for supporting this.
The change that affects CL clients is just a rename of validator_registration into builder
{
"builder_relays_groups": {
"groupB": [
"https://[email protected]",
"http://...."
]
},
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
"builder": {
"enabled": true,
"relays": ["https://[email protected]"],
"gas_limit": "12345654321"
}
}
},
"default_config": {
"fee_recipient": "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
"builder": {
"enabled": false,
"relays": ["groupB"]
}
}
}
Do you think it should replace the -relays flag ?
Imo yes, cause it collides with the default_config, unless we provide explicit flags for other default fields (fee_recipient, enabled)
It should not replace the -relays flag, but i think if someone specifies the config and -relays, it should fail with a log message
@tbenr just seeing this now... thanks for letting me know, I'll go update this.
Just catching up with this from the Lighthouse side and I have a few questions
- It seems strange to mix concerns by combining
mev-boostconfig with CL config. IMO the fee recipient and gas limit are fundamentally CL parameters, while the relay assignments aremev-boost's domain. My question is: doesmev-boostmake use of the fee-recipient/gas limit, and do the CLs that already support this format (Teku+Prysm) make use of the relay assignments? Lighthouse currently only supports a single builder, so we'd have no use for the relay assignments if we were to support this config. - Should CLs support the
mev-boostconfig even when they aren't using a builder (i.e. for a local EL)? - Is the config intended to be reloaded on-demand, and if so how often? I notice that Teku don't reload it by default and will reload it at most once per epoch if
--validators-proposer-config-refresh-enabledis set. This seems like it could be an issue for VCs managing thousands of keys, as there may be frequent updates which users want actioned faster than once-per-epoch, but reading/loading the file too often could add significant latency.
Given my current understanding of the design space my preference would be for a separate push-based API for the gas limit to be added alongside the push-based Fee recipient API, and a separate relay assignment config file for mev-boost. IMO this re-separates concerns addressing points (1) and (2), while also mitigating the performance-latency trade-off of (3).
the way Prysm works right now is we have an enable-builder flag that will turn on validator registration. if a user has their prysm validator client started with enable-builder then the fee recipient API will also be updated on the mev-boost side, if it's not on then it'll just continue with the prepare beacon proposer call.
@michaelsproul mev-boost only uses the relays config from this file, gasLimit and feeRecipient need to be sent as a validator registration that's signed with the validator key, so mev-boost wouldn't even be able to use that.
Thanks everyone for all the input so far (and @0xpanoramix for his work on implementing this in #186). Let's continue the spec-specific conversations in https://github.com/ethereum/builder-specs/pull/41/files 🙏
Succeeded by #455