Fee recipient, graffiti and gas limit
When one of your validators proposes a block, three settings shape it:
- the fee recipient: the execution-layer address that receives the priority fees (tips) of the block and any MEV payment;
- the graffiti: 32 bytes of free text stored in the block;
- the gas limit: the gas limit the validator asks for. Each block can move the network's gas limit a little toward the proposer's preference.
Each can be set once for all validators on the command line, and overridden per validator in
validators.yml or through the Keymanager API.
Fee recipient
Warning: Always set a fee recipient that you control. If you set none, the integrated validator client sends your block rewards from fees to the Grandine team's donation address (see Default behavior).
Set one address for all validators with --suggested-fee-recipient:
grandine \
--network mainnet \
--jwt-secret /path/to/jwt.hex \
--eth1-rpc-urls http://EL-HOST:8551 \
--keystore-dir /path/to/validator_keys \
--keystore-password-file /path/to/password.txt \
--suggested-fee-recipient 0xYOUR_EXECUTION_ADDRESS
With Docker, add the same option after the image name:
docker run \
-v $HOME/.grandine:/root/.grandine \
sifrai/grandine:stable \
--network mainnet \
--suggested-fee-recipient 0xYOUR_EXECUTION_ADDRESS \
...
The address must be a valid 20-byte execution address. Use an address whose private key you hold, or a smart contract you have checked, such as a pool's fee distributor. It does not need to match the withdrawal address.
At startup, Grandine logs the default it will use:
suggested fee recipient: 0x...
Check this line after every configuration change.
Per-validator fee recipients
Add fee_recipient to a validator's entry in validators.yml
(~/.grandine/<NETWORK>/validator/validators.yml by default):
- enabled: true
pubkey: "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"
type: local_keystore
keystore_path: /path/to/validator_keys/keystore-0.json
keystore_password_path: /path/to/secrets/keystore-0.txt
fee_recipient: "0x0000000000000000000000000000000000000001"
Edit the file only while Grandine is stopped, or use the Keymanager API, which changes it for you at runtime.
Fee recipient precedence
For a validator run by the integrated validator client, the first match wins:
fee_recipientin the validator'svalidators.ymlentry (also what the Keymanager API sets);--suggested-fee-recipient;- the Grandine donation address.
When a Grandine beacon node builds a block for a validator, it uses, in order:
- the address a validator client sent through
POST /eth/v1/validator/prepare_beacon_proposer(remote validator clients send this; the integrated one does not need to); - the
validators.ymlentry on the beacon node, if it has one for that validator; - the beacon node's
--suggested-fee-recipient; - the Grandine donation address.
Default behavior when none is set
- Integrated validator client (plain
grandinewith keys): Grandine falls back to its donation address,0xe7cf7C3BA875Dd3884Ed6a9082d342cb4FBb1f1b. This address is used for local blocks and sent to the builder in validator registrations. The startup linesuggested fee recipientshows it. - Beacon node only (
grandine bn): when a remote validator client does not send a fee recipient for a validator, the beacon node uses its own--suggested-fee-recipient, or else the donation address. Set--suggested-fee-recipienton beacon nodes that serve other validator clients. - Separate validator client (
grandine vc): there is no fallback address. A validator without a fee recipient, either from--suggested-fee-recipientor fromvalidators.yml, is not reported to the beacon nodes throughprepare_beacon_proposer, is not registered with a builder, and gets no proposer preferences published (from Gloas on). The beacon node then pays its own default fee recipient for blocks it builds locally. See Validator client.
Graffiti
Set a default graffiti with --graffiti:
grandine ... --graffiti "my staking setup"
The text must fit in 32 bytes (UTF-8). A longer value is rejected at startup.
--graffiti can be given more than once. Grandine then rotates through the values, one per block
proposal:
grandine ... --graffiti "first" --graffiti "second" --graffiti "third"
Per-validator graffiti goes in validators.yml:
- enabled: true
pubkey: "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"
type: local_keystore
keystore_path: /path/to/validator_keys/keystore-0.json
keystore_password_path: /path/to/secrets/keystore-0.txt
graffiti: "validator zero"
Precedence: the validators.yml entry (or the Keymanager API), then --graffiti, then none.
Grandine validates the per-validator graffiti on startup and refuses to start if it is too long.
Client fingerprint ("blockprint")
When a Grandine beacon node builds a block, it appends a short client fingerprint to the graffiti
if there is room. The fingerprint names the execution client and both clients' commits, followed by
Grandine/<version>. For example, the graffiti test with a Besu execution client may become:
test BU4e2eGR6a37 Grandine/1.2.3
Parts that do not fit are left out, and your own text is never truncated. With no graffiti set, the
block carries only the fingerprint. This helps researchers measure client diversity. To turn it off,
start the beacon node with --disable-blockprint-graffiti. It is a beacon node option: with
grandine vc, the remote beacon node decides.
Gas limit
By default, Grandine asks for the gas limit scheduled by the network configuration for the current
epoch, or 60,000,000 when no schedule applies. Change the default for all validators with
--default-gas-limit:
grandine ... --default-gas-limit 60000000
Per validator, set gas_limit in validators.yml:
- enabled: true
pubkey: "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"
type: local_keystore
keystore_path: /path/to/validator_keys/keystore-0.json
keystore_password_path: /path/to/secrets/keystore-0.txt
gas_limit: 60000000
Precedence: the validators.yml entry (or the Keymanager API), then --default-gas-limit, then the
scheduled limit, then 60,000,000.
The gas limit goes into builder registrations and, from the Gloas fork on, into the proposer preferences that Grandine publishes. If a configured limit exceeds the scheduled one, Grandine warns when it registers validators:
3 validators configured gas limit exceeds the recommended gas limit of 60000000
Tip: Change the gas limit only if you follow the community's coordination on it. Most operators should leave the default.
Changing settings at runtime with the Keymanager API
The Keymanager API changes these settings without a restart. Grandine stores
the change in the validator's validators.yml entry, so it survives restarts. Enable the API with
--enable-validator-api. It listens on 127.0.0.1:5055 by default and requires the bearer token
stored in api-token.txt in the validator directory (or in --validator-api-token-file).
TOKEN=$(cat ~/.grandine/mainnet/validator/api-token.txt)
PUBKEY=0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a
Fee recipient:
# Read
curl -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:5055/eth/v1/validator/$PUBKEY/feerecipient
# Set
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ethaddress": "0xYOUR_EXECUTION_ADDRESS"}' \
http://127.0.0.1:5055/eth/v1/validator/$PUBKEY/feerecipient
# Remove the override (fall back to the default)
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:5055/eth/v1/validator/$PUBKEY/feerecipient
Gas limit:
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"gas_limit": "60000000"}' \
http://127.0.0.1:5055/eth/v1/validator/$PUBKEY/gas_limit
Graffiti:
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"graffiti": "my staking setup"}' \
http://127.0.0.1:5055/eth/v1/validator/$PUBKEY/graffiti
GET and DELETE work the same way for gas_limit and graffiti. A successful POST returns
202 Accepted, and a DELETE returns 204 No Content.
Notes:
GET .../feerecipientreturns the value that applies, including the default. Withgrandine vcand no fee recipient configured, it returns404.GET .../gas_limitreturns the effective gas limit, including the scheduled default.- A
POSTorDELETEfor a validator without avalidators.ymlentry returns404. Validators loaded only from--web3signer-urlshave no entry. See Web3Signer for how to give one an entry.
Command line options
--suggested-fee-recipient(default: none; the integrated validator client andgrandine bnfall back to the Grandine donation address): default fee recipient for all validators.--graffiti(default: none): default block graffiti, up to 32 bytes. Repeat it to rotate values.--disable-blockprint-graffiti(default: disabled): beacon node option. Do not append the client fingerprint to the graffiti.--default-gas-limit(default: the scheduled gas limit, or60000000): default gas limit for all validators.--enable-validator-api(default: disabled): enables the Keymanager API used to change these settings at runtime.
See the command line reference for the full list.