Deprecate prior and add /validator/config endpoint#87
Conversation
| configs: | ||
| type: object | ||
| description: | | ||
| Mapping of validator public key (hex encoded with 0x prefix) to the full | ||
| `ValidatorConfig` document to set for that key. |
There was a problem hiding this comment.
Would it be possible this one to be the validator's index, rather than the public key?
In cases like DVs it's a bit better to have references of the index, rather than the public key, as the public keys the VC sees are partial keys, rather than the full key, as seen on the CL side. The current request which is with similar intent, POST /eth/v1/validator/prepare_beacon_proposer uses validator index. So my assumption is it won't be a big hurdle to use validator index here as well?
There was a problem hiding this comment.
I don't have a strong opinion here but it seems like the key manager clients that normally deal with just public keys would require a BN query to resolve the mapping from pubkey -> validator index before making the call. It would be good to know if this change would negatively impact any other software.
There was a problem hiding this comment.
You could do index for active keys but for new additions you wouldn't have an index, so if you wanted to support indices you'd still need to support pubkey as well unless you want inconsistent apis i think...
There was a problem hiding this comment.
Operationally pubkeys make much more sense for this. Node operators can pre-configure keys in batches at any time, including before they become active. With indexes, operators would need to continuously monitor the validator statuses and update their configs one-by-one or in small batches, quite impractical and unnecessarily complex.
Can't DVs work around this the same way they have worked around the current Keymanager API endpoints that are also using the pubkey?
There was a problem hiding this comment.
I agree with paul here, I think it's preferable to use public key here
51ee282 to
9f66e70
Compare
| type: string | ||
| description: | | ||
| - set: the document was validated and applied atomically | ||
| - not_found: the key is not known to the server |
There was a problem hiding this comment.
we should permit configs for keys not found i think, its not clear that if this is saying it's not set
There was a problem hiding this comment.
we should allow for preprovisioning
There was a problem hiding this comment.
added pre-provisioning and as a consequence this requires using pubkeys and not validator indices
| description: | | ||
| - set: the document was validated and applied atomically | ||
| - not_found: the key is not known to the server | ||
| - error: the document failed validation or could not be applied; no change |
There was a problem hiding this comment.
what should we do for unknown fields, silently accept ( client specific) or error here?
There was a problem hiding this comment.
removed additionalProperties: false for more leniency to match the rest of the keymanager API. Unrecognized fields should be ignored and invalid values for recognized fields should error
| description: | | ||
| Sets the block-production preferences of one or more keys. For each key in `request.configs`, | ||
| the submitted document REPLACES the key's entire configured fragment: the server MUST NOT merge | ||
| it with previously configured values. A field absent from the submitted document is unset and |
There was a problem hiding this comment.
a present builder object replaces default_config's builder entirely; inheritance applies only to absent top-level fields
right now prysm is looking at " BuilderEntry → BuilderConfig → default_config → client default" inheritance
in prysm it's whole object reading instead of field level reading . do we have to do inheritance by field level?
if builder config is set at the public key level then it replaces defaults in its entirety only if we are missing a field we fall back down the hierachy, not sure if others have feels about this
There was a problem hiding this comment.
BuilderEntry → BuilderConfig → default_config → client default
on the same page with this, I just tried disambiguating it in 8052f47
- keep pubkey as the config key (since no index exists for not-yet-active keys) - pre-provisioning: a config may be set for an unmanaged key - accept unrecognized fields to match the rest of the keymanager API - disambiguate per-builder field resolution
|
I am all for having this grab bag of options. Eth Docker may not configure every single one out of the gate; and, it's good to have it available. |
Add
/eth/v1/validator/config: atomic per-key management of block-production preferencesMotivation
With ePBS, proposers can talk to builders directly instead of through relay lists configured in a sidecar. The validator client becomes the owner of a per-key builder list with per-builder constraints: which builders to request bids from, an optional expected bid signer, a trusted-payment cap (
max_execution_payment), bid floors, boost factors, and an optional proxy to route requests through. The VC must own this list because it pre-signs the request authentications that bind each request to a builder's canonical URL.Today that configuration only exists as static per-client config files (see the example in OffchainLabs/prysm#17124). Defining many builder entries across hundreds or thousands of keys in a static file is verbose and error-prone, and downstream software (e.g. eth-docker, dappnode, etc) would need to maintain a different config dialect per client. The keymanager API already solves this class of problem for fee recipient, gas limit and graffiti, but as three separate endpoint families, and the ePBS builder preference set is about to grow well past what per-field endpoints can sanely express.
What this PR does
/eth/v1/validator/config(GET/POST), managing a validator's full block-production preferences (fee recipient, gas limit, graffiti, builder preferences) as one atomic per-key document.feerecipient,gas_limitandgraffitiendpoint families. This endpoint absorbs their responsibilities and replaces three partial-write surfaces with a single consistent one.The document model
Per key:
ValidatorConfig={fee_recipient?, target_gas_limit?, graffiti?, builder?}. Thebuilderblock holdsenabled, thebuilders[]list, and per-key fallback values. EachBuilderEntrycarriesurl(required; the signed identity), and optionalpubkey,proxy,max_execution_payment,min_bid,builder_boost_factor.Every field is optional. Resolution order is normative:
BuilderEntryfield, then the per-keyBuilderConfigfallback, then the same two levels withindefault_config, then the client default. Key-level fields resolve document, thendefault_config, then client default.Monetary values are Gwei as decimal strings.
builder_boost_factorsemantics (including the reserved0/100/2**64 - 1values) follow ethereum/beacon-APIs#625;max_execution_paymentnaming follows the builder-specsBuilderPreferencesRequestV1.Example:
GET /eth/v1/validator/configReturns the configured fragments plus the read-only
default_config, so tooling can distinguish an explicit per-key value from an inherited default (and can resolve effective values locally):{ "data": { "default_config": { "fee_recipient": "0x8943545177806ED17B9F23F0a21ee5948eCaa776", "target_gas_limit": "30000000", "graffiti": "example graffiti", "builder": { "enabled": true, "builders": [ { "url": "https://builder-a.example.com" }, { "url": "https://builder-b.example.com" } ], "max_execution_payment": "1000000000" } }, "configs": { "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": { "fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3", "target_gas_limit": "45000000", "builder": { "enabled": true, "builders": [ { "url": "https://builder-a.example.com", "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", "proxy": "http://side-car:9001", "max_execution_payment": "250000000", "min_bid": "10000000", "builder_boost_factor": "100" } ], "max_execution_payment": "500000000" } }, "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": { "builder": { "enabled": false } } } } }Example:
POST /eth/v1/validator/configFull-replace per key. The third key shows the delete idiom: an empty document clears the key back to defaults, so there is no separate DELETE operation.
{ "configs": { "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": { "fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3", "builder": { "enabled": true, "builders": [ { "url": "https://builder-a.example.com", "max_execution_payment": "250000000" } ] } }, "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": { "builder": { "enabled": false } }, "0xb0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7": {} } }Response, per-key statuses keyed by the same pubkeys:
{ "data": { "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": { "status": "set" }, "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": { "status": "error", "message": "builder.builders[0].url is not a valid URL" }, "0xb0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7": { "status": "set" } } }Key semantics
default_config. An empty document{}clears the key entirely (this is the delete).default_configplus the normative resolution order.additionalProperties: falsethroughout): inside a document as a per-keyerror, in the envelope as a400. A typo'd preference must fail loudly, not be silently ignored.default_configis read-only through this API by schema construction.Relationship to other work
BuilderPreferencesRequestV1/submitBuilderPreferences/SignedRequestAuthV1(ethereum/builder-specs, gloas).BuilderEntry-style config: Decouple signed builder URL from the HTTP dial target OffchainLabs/prysm#17124.min_bid,builder_boost_factor): Add a POST produceBlockV4 beacon-APIs#625. Note this PR adoptsmax_execution_payment(builder-specs naming) where #625 saysmax_trusted_bid; these should converge.Notes for reviewers
default_configis deliberately read-only in this version: it is the minimal static floor a bare VC needs, and management tooling owns the per-key layer. Writable defaults can be added later without breaking changes.info.versionis bumped to2.0.0-devto signal the breaking deprecation; happy to adjust to the repo's release conventions.