diff --git a/.gitignore b/.gitignore index dfb6730..ffd91a0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .DS_Store deploy node_modules +dictionary.dic diff --git a/apis/fee_recipient.yaml b/apis/fee_recipient.yaml index 30a9bd4..41334dc 100644 --- a/apis/fee_recipient.yaml +++ b/apis/fee_recipient.yaml @@ -1,7 +1,10 @@ get: operationId: listFeeRecipient + deprecated: true summary: List Fee Recipient. description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the fee recipient together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + List the validator public key to eth address mapping for fee recipient feature on a specific public key. The validator public key will return with the default fee recipient address if a specific one was not found. @@ -41,8 +44,11 @@ get: post: operationId: setFeeRecipient + deprecated: true summary: Set Fee Recipient. description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the fee recipient together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Sets the validator client fee recipient mapping which will then update the beacon node. Existing mappings for the same validator public key will be overwritten. Specific Public keys not mapped will continue to use the default address for fee recipient in accordance to the startup of the validator client and beacon node. @@ -85,8 +91,12 @@ post: $ref: "../keymanager-oapi.yaml#/components/responses/InternalError" delete: operationId: deleteFeeRecipient + deprecated: true summary: Delete Configured Fee Recipient - description: Delete a configured fee recipient mapping for the specified public key. + description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the fee recipient together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + + Delete a configured fee recipient mapping for the specified public key. security: - bearerAuth: [ ] tags: diff --git a/apis/gas_limit.yaml b/apis/gas_limit.yaml index b8bd339..5229ebf 100644 --- a/apis/gas_limit.yaml +++ b/apis/gas_limit.yaml @@ -1,7 +1,10 @@ get: operationId: getGasLimit + deprecated: true summary: Get Gas Limit. description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the gas limit together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Get the execution gas limit for an individual validator. This gas limit is the one used by the validator when proposing blocks via an external builder. If no limit has been set explicitly for a key then the process-wide default will be returned. @@ -44,8 +47,11 @@ get: post: operationId: setGasLimit + deprecated: true summary: Set Gas Limit. description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the gas limit together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Set the gas limit for an individual validator. This limit will be propagated to the beacon node for use on future block proposals. The beacon node is responsible for informing external block builders of the change. @@ -88,8 +94,11 @@ post: $ref: "../keymanager-oapi.yaml#/components/responses/InternalError" delete: operationId: deleteGasLimit + deprecated: true summary: Delete Configured Gas Limit description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the gas limit together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Delete a configured gas limit for the specified public key. The server may return a 400 status code if no external builder is configured. diff --git a/apis/graffiti.yaml b/apis/graffiti.yaml index 3c453c2..3c49283 100644 --- a/apis/graffiti.yaml +++ b/apis/graffiti.yaml @@ -1,7 +1,10 @@ get: operationId: getGraffiti + deprecated: true summary: Get Graffiti description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the graffiti together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Get the graffiti for an individual validator. If no graffiti is set explicitly, returns the process-wide default. security: @@ -45,8 +48,11 @@ get: post: operationId: setGraffiti + deprecated: true summary: Set Graffiti description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the graffiti together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Set the graffiti for an individual validator. security: - bearerAuth: [] @@ -85,8 +91,11 @@ post: delete: operationId: deleteGraffiti + deprecated: true summary: Delete Configured Graffiti description: | + **DEPRECATED**: superseded by the Validator Config endpoint (`/eth/v1/validator/config`), which manages the graffiti together with the rest of a validator's block-production preferences as one atomic per-key document. This endpoint will be removed in a future release. + Delete the configured graffiti for the specified public key. security: - bearerAuth: [] diff --git a/apis/validator_config.yaml b/apis/validator_config.yaml new file mode 100644 index 0000000..1459012 --- /dev/null +++ b/apis/validator_config.yaml @@ -0,0 +1,251 @@ +get: + operationId: getValidatorConfig + summary: Get Validator Config. + description: | + Returns the block-production preferences of the requested keys, or of all keys known to the + server when `pubkeys` is not given. + + Each configured key returns its complete document, exactly as it was submitted. A key the + server knows but has no document for returns an empty object; its effective preferences are + the read-only `default_config` included in the response, taken whole (documents are + all-or-nothing, so nothing is merged per field). Keys the server does not know are omitted + from the response entirely. + security: + - bearerAuth: [] + tags: + - Validator Config + parameters: + - in: query + name: pubkeys + required: false + description: | + Restrict the response to the given public keys. Keys the server does not know are omitted + from the response. When not given, the response covers all keys known to the server. + style: form + explode: false + schema: + type: array + items: + $ref: "../keymanager-oapi.yaml#/components/schemas/Pubkey" + responses: + "200": + description: Success response + content: + application/json: + schema: + title: GetValidatorConfigResponse + type: object + required: [data] + properties: + data: + type: object + required: [configs] + properties: + default_config: + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/ValidatorConfig" + - description: | + The defaults the client applies to keys with no configured document. + Read-only through this API. When present, `default_config` is itself a + complete document. When absent, keys without a document follow the + client's built-in defaults. + configs: + type: object + description: | + Mapping of validator public key (hex encoded with 0x prefix) to its configured + `ValidatorConfig` document. Keys with no per-key configuration map to an empty + object. + additionalProperties: + $ref: "../keymanager-oapi.yaml#/components/schemas/ValidatorConfig" + example: + data: + default_config: + fee_recipient: "0x8943545177806ED17B9F23F0a21ee5948eCaa776" + target_gas_limit: "30000000" + graffiti: "example graffiti" + builder: + enabled: true + builders: + - url: "https://builder-a.example.com" + auth_data: "0x68747470733a2f2f6275696c6465722d612e6578616d706c652e636f6d" + max_execution_payment: "0" + min_bid: "0" + builder_boost_factor: "100" + - url: "https://builder-b.example.com" + auth_data: "0x68747470733a2f2f6275696c6465722d622e6578616d706c652e636f6d" + max_execution_payment: "0" + min_bid: "0" + builder_boost_factor: "100" + configs: + "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": + fee_recipient: "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3" + target_gas_limit: "45000000" + graffiti: "example graffiti" + builder: + enabled: true + builders: + - url: "https://builder-a.example.com" + auth_data: "0x1234567890abcdef" + pubkey: "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" + max_execution_payment: "250000000" + min_bid: "10000000" + builder_boost_factor: "100" + - url: "https://builder-a.example.com" + auth_data: "0xdeadbeef" + max_execution_payment: "0" + min_bid: "0" + builder_boost_factor: "100" + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": + fee_recipient: "0x8943545177806ED17B9F23F0a21ee5948eCaa776" + target_gas_limit: "30000000" + graffiti: "" + builder: + enabled: false + "0xb0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7": {} + "400": + $ref: "../keymanager-oapi.yaml#/components/responses/BadRequest" + "401": + $ref: "../keymanager-oapi.yaml#/components/responses/Unauthorized" + "403": + $ref: "../keymanager-oapi.yaml#/components/responses/Forbidden" + "500": + $ref: "../keymanager-oapi.yaml#/components/responses/InternalError" + +post: + operationId: setValidatorConfig + summary: Set Validator Config. + description: | + Sets the block-production preferences of one or more keys. Each submitted document replaces + the key's entire configuration; the server MUST NOT merge it with previously stored values. + Submit either a complete document (`fee_recipient`, `target_gas_limit`, `graffiti`, and a + fully resolved `builder`) or an empty one (`{}`), which clears the key so it follows the + client's defaults again (there is no separate delete operation). Anything in between fails + that key with a per-key `error` status. + + Keys NOT present in `request.configs` are left untouched: only submitted keys are affected, so + a large key set may be split across multiple requests. Servers SHOULD accept request bodies + large enough to cover their full key set in one request (thousand-key batches are expected). + + A configuration may be set for a key the server does not yet manage. The server SHOULD store it + (pre-provisioning) so it takes effect when the key is later added; a server that does not + pre-provision returns `not_found`. + + Atomicity is per key, NOT per batch: each key's document takes effect fully or not at all, but + the batch is not transactional across keys. Keys that validate successfully are applied even + when other keys in the same request fail, and each key's outcome is reported in the per-key + response status. + + Servers MUST validate the syntax of every submitted field (types, formats, patterns). A + `builders` list containing two entries with the same (`url`, `auth_data`) pair, compared as + the decoded `auth_data` bytes, is invalid; the server MUST NOT silently drop the duplicate. + Any such failure rejects that key's entire document with a per-key `error` status: no part of + it is applied. + Unrecognized fields are ignored for forward compatibility, consistent with the rest of the + keymanager API. In particular, `default_config` is read-only and cannot be written through this + API. + security: + - bearerAuth: [] + tags: + - Validator Config + requestBody: + required: true + content: + application/json: + schema: + title: SetValidatorConfigRequest + type: object + required: [configs] + properties: + configs: + type: object + description: | + Mapping of validator public key (hex encoded with 0x prefix) to the full + `ValidatorConfig` document to set for that key, or `{}` to clear it. Keyed by + public key rather than validator index so configurations can be pre-provisioned + for keys that are not yet active. + additionalProperties: + $ref: "../keymanager-oapi.yaml#/components/schemas/ValidatorConfig" + example: + configs: + "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": + fee_recipient: "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3" + target_gas_limit: "45000000" + graffiti: "example graffiti" + builder: + enabled: true + builders: + - url: "https://builder-a.example.com" + auth_data: "0x68747470733a2f2f6275696c6465722d612e6578616d706c652e636f6d" + max_execution_payment: "250000000" + min_bid: "10000000" + builder_boost_factor: "100" + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": + fee_recipient: "0x8943545177806ED17B9F23F0a21ee5948eCaa776" + target_gas_limit: "30000000" + graffiti: "" + builder: + enabled: true + builders: + - url: "https://builder-b.example.com" + auth_data: "0xdeadbeef" + max_execution_payment: "0" + min_bid: "0" + builder_boost_factor: "100" + - url: "https://builder-b.example.com" + auth_data: "0xDEADBEEF" + max_execution_payment: "0" + min_bid: "0" + builder_boost_factor: "100" + "0xb0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7": {} + responses: + "200": + description: Success response + content: + application/json: + schema: + title: SetValidatorConfigResponse + type: object + required: [data] + properties: + data: + type: object + description: Status of each key in `request.configs`, keyed by the same public keys. + additionalProperties: + type: object + required: [status] + properties: + status: + type: string + description: | + - set: the document was validated and applied. A complete document is + stored (pre-provisioned if the key is not yet managed, taking effect + when it is added); `{}` clears the key's configuration. + - not_found: the server neither manages this key nor supports + pre-provisioning, so nothing was stored + - error: the document failed validation or could not be applied; no change + was made for this key + enum: + - set + - not_found + - error + example: set + message: + type: string + description: error message if status == error + example: + data: + "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": + status: set + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": + status: error + message: "builder.builders[1] duplicates the (url, auth_data) pair of builder.builders[0]" + "0xb0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7": + status: set + "400": + $ref: "../keymanager-oapi.yaml#/components/responses/BadRequest" + "401": + $ref: "../keymanager-oapi.yaml#/components/responses/Unauthorized" + "403": + $ref: "../keymanager-oapi.yaml#/components/responses/Forbidden" + "500": + $ref: "../keymanager-oapi.yaml#/components/responses/InternalError" diff --git a/keymanager-oapi.yaml b/keymanager-oapi.yaml index a5422ab..93d6dde 100644 --- a/keymanager-oapi.yaml +++ b/keymanager-oapi.yaml @@ -18,7 +18,7 @@ info: of at least 256 bits. If such a parameter is not given, the client SHOULD generate such a token and write it to a file, to be reused across multiple restarts of the binary. If such a parameter is given, but the file or token cannot be read, the client SHOULD treat this as an error: either abort the startup, or show the error and continue without exposing the key manager routes. - version: "Dev" + version: "2.0.0-dev" contact: name: Ethereum Github url: https://github.com/ethereum/keymanager-APIs/issues @@ -34,12 +34,17 @@ servers: default: "http://localhost/" tags: + - name: Validator Config + description: | + Management of a validator's full block-production preferences (fee recipient, gas limit, + graffiti, builders) as one atomic per-key document. Supersedes the Fee Recipient, Gas Limit + and Graffiti endpoints. - name: Fee Recipient - description: Set of endpoints for management of fee recipient. + description: Set of endpoints for management of fee recipient. Deprecated, superseded by Validator Config. - name: Gas Limit - description: Set of endpoints for management of gas limits. + description: Set of endpoints for management of gas limits. Deprecated, superseded by Validator Config. - name: Graffiti - description: Set of endpoints for management of graffiti. + description: Set of endpoints for management of graffiti. Deprecated, superseded by Validator Config. - name: Local Key Manager description: Set of endpoints for key management of local keys. - name: Remote Key Manager @@ -52,6 +57,8 @@ paths: $ref: './apis/local_keystores.yaml' /eth/v1/remotekeys: $ref: './apis/remote_keystores.yaml' + /eth/v1/validator/config: + $ref: './apis/validator_config.yaml' /eth/v1/validator/{pubkey}/feerecipient: $ref: './apis/fee_recipient.yaml' /eth/v1/validator/{pubkey}/gas_limit: @@ -83,6 +90,12 @@ components: $ref: './types/graffiti.yaml' Uint64: $ref: './types/uint.yaml#/Uint64' + ValidatorConfig: + $ref: './types/validator_config.yaml#/ValidatorConfig' + BuilderConfig: + $ref: './types/validator_config.yaml#/BuilderConfig' + BuilderEntry: + $ref: './types/validator_config.yaml#/BuilderEntry' SignerDefinition: $ref: './types/signer_definition.yaml' ImportRemoteSignerDefinition: diff --git a/types/validator_config.yaml b/types/validator_config.yaml new file mode 100644 index 0000000..1b43caf --- /dev/null +++ b/types/validator_config.yaml @@ -0,0 +1,136 @@ +ValidatorConfig: + type: object + description: | + All block-production preferences for one validator key, managed as a single document. A + document is all-or-nothing: it contains every field (`fee_recipient`, `target_gas_limit`, + `graffiti`, and `builder`, with each builder entry fully resolved), and the validator client + uses it exactly as submitted. A key without a document follows the client's defaults + (surfaced read-only as `default_config` on GET). Nothing is inherited or merged per field: + for a configured key the defaults play no role, so its document applies in full even where it + differs from them (for example, `builder.enabled: true` while the default is `false`). + properties: + fee_recipient: + $ref: "../keymanager-oapi.yaml#/components/schemas/EthAddress" + target_gas_limit: + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/Uint64" + - description: | + The gas limit the validator targets for its blocks. Communicated to builders and used + for local block production and gas limit voting. + graffiti: + $ref: "../keymanager-oapi.yaml#/components/schemas/Graffiti" + builder: + $ref: "#/BuilderConfig" + +BuilderConfig: + type: object + description: | + Preferences for sourcing blocks from builders. `enabled` switches the builder path on or off + for the key; a document may carry a `builders` list while `enabled` is `false`. `enabled` is + required; `builders` may be absent or empty, in which case no builders are solicited. + + Builder entries are submitted fully resolved: this API is called programmatically, and the + caller sets every preference an entry carries on the entry itself. There are no per-builder + fallback fields; every entry field except `pubkey` is required. + required: [enabled] + properties: + enabled: + type: boolean + description: | + Whether blocks may be sourced from builders for this key. + example: true + builders: + type: array + description: | + The builders this key requests bids from. + + Entries are identified by their (`url`, `auth_data`) pair: `url` compared as the exact + string, `auth_data` as its decoded bytes (hex case does not distinguish entries). One + list MUST NOT contain two entries with the same `url` and the same `auth_data`. Multiple + entries MAY share a `url`, each with different `auth_data`. Requests are made per entry, + so entries sharing a `url` result in one request to that `url` for each such entry. + items: + $ref: "#/BuilderEntry" + +BuilderEntry: + type: object + description: | + One builder this key may source blocks from. + required: [url, auth_data, max_execution_payment, min_bid, builder_boost_factor] + properties: + url: + type: string + format: uri + description: | + The URL this entry's requests are sent to. Multiple entries MAY share a `url`; entries are + identified by their (`url`, `auth_data`) pair (see `builders`). + example: "https://builder.example.com" + auth_data: + type: string + pattern: "^0x(?:[a-fA-F0-9]{2}){0,4096}$" + description: | + Opaque data used to authenticate this validator's requests to the builder. Agreed with the + builder out of band and placed verbatim in the `RequestAuthV1.data` the validator signs. The + builder checks the signature and the exact bytes. Its meaning is left to the two parties + (for example, a shared secret). At most `MAX_DATA_SIZE` (4096) bytes. + + The keymanager treats this value as opaque bytes: it only ever compares `auth_data` values + for equality, and never parses or inspects them. When no value has been agreed with the + builder out of band, the caller SHOULD set `auth_data` to the UTF-8 bytes of the builder's + own advertised URL, exactly as advertised, hex encoded: it is deterministic, distinct per + builder, and requires no coordination between the signers of a distributed validator. That + is purely a convention about what tooling writes into the field. + example: "0x68747470733a2f2f6275696c6465722e6578616d706c652e636f6d" + pubkey: + description: | + The builder's BLS public key. When set, binds trusted execution payments to this + builder's on-chain key: bids not signed by it MUST NOT be accepted. _48-bytes, hex + encoded with 0x prefix, case insensitive._ + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/Pubkey" + max_execution_payment: + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/Uint64" + - description: | + The maximum trusted execution payment, in Gwei, accepted from this builder. Bids + promising a trusted payment above this value MUST NOT be accepted. The remainder of a + builder's payment is expected in the trustless (in-protocol) form. + example: "250000000" + min_bid: + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/Uint64" + - description: | + The minimum total payment, in Gwei, that the validator will accept from this builder. + A bid whose `value` plus `execution_payment` is below this amount MUST NOT be + accepted. + example: "10000000" + builder_boost_factor: + allOf: + - $ref: "../keymanager-oapi.yaml#/components/schemas/Uint64" + - description: | + Percentage multiplier to apply to this builder's bid when choosing between a builder + bid and payload from the paired execution node. `builder_payload_value` is the bid's + total payment to the proposer, its `value` plus its `execution_payment`, and the + factor applies only to bids that passed the `max_execution_payment` and `min_bid` + checks. This value is only relevant if the beacon node has a viable + `ExecutionPayloadBid` available from this builder and receives a valid response from + the paired execution node. When these preconditions are met, the block producer MUST + act as follows: + + * if `exec_node_payload_value >= builder_boost_factor * (builder_payload_value // 100)` + for the highest builder bid known (each bid boosted by the factor applicable to the + builder it originates from), then commit to the local execution node payload. + * otherwise, commit to the builder bid. + + The following values encode common preferences and MUST be supported: + + * `builder_boost_factor=0`: prefer the local execution node payload unless an error + makes it unviable. + * `builder_boost_factor=100`: profit maximization mode; choose whichever payload pays + more. + * `builder_boost_factor=2**64 - 1`: prefer this builder's bid unless an error or + health check makes it unviable. + + Implementations should use saturating arithmetic or another technique to ensure that + large values of the `builder_boost_factor` do not trigger overflows or errors. + example: "100" diff --git a/wordlist.txt b/wordlist.txt index 2156f88..1c591b3 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -19,3 +19,8 @@ VPN BLS oapi Vero +Gwei +atomicity +uri +RequestAuthV +UTF