Running a Decaf Node
Configuration for Decaf nodes
Decaf node operators are limited to a select group. If you are interested in running a node in a future release of Espresso, contact us.
This page give the configuration used to run different types of nodes in the Decaf testnet. For general information on running an Espresso node, see Running an Espresso Node.
All nodes in Decaf use the ghcr.io/espressosystems/espresso-sequencer/sequencer:20260312 Docker image, or an equivalent image built from source. Depending on the type of node, the configuration varies.
The configuration for all node types includes ESPRESSO_SEQUENCER_GENESIS_FILE=/genesis/decaf.toml. This file is built into the official Docker images. Operators building their own images will need to ensure this file is included and their nodes are pointed at it.
Staking
Regardless of the type of node being operated, if you are starting a node for the first time, it will need to be registered in the stake table and have some stake delegated to it in order to participate in consensus.
With the initial release of Proof-of-stake, participation is limited to a dynamic, permissionless set of 100 nodes. In each epoch (period of roughly 24 hours) the 100 nodes with the most delegated stake form the active participation set.
Registering a Node
In order for a node to participate, it must be registered in the stake table contract on Ethereum Sepolia. During this process, the node's consensus keys are associated with a unique Ethereum address. This Ethereum address will receive commission, but does not exist on the node itself.
Interfacing with the stake table can be done using the staking-cli. Here is the command to use to register a node in the stake table:
docker run -e L1_PROVIDER -e STAKE_TABLE_ADDRESS -e MNEMONIC -e ACCOUNT_INDEX \
-e CONSENSUS_PRIVATE_KEY -e STATE_PRIVATE_KEY \
ghcr.io/espressosystems/espresso-sequencer/staking-cli:main \
staking-cli register-validator \
--commission $COMMISSIONWhere:
L1_PROVIDER
The RPC provider URL to use when interacting with the L1. This should be an Ethereum Sepolia endpoint for Decaf
STAKE_TABLE_ADDRESS
The Decaf stake table address. This is 0x40304fbe94d5e7d1492dd90c53a2d63e8506a037
MNEMONIC
The Ethereum mnemonic to use in combination with ACCOUNT_INDEX to derive an Ethereum keypair unique to this node
ACCOUNT_INDEX
The Ethereum account index to use in combination with MNEMONIC to derive an Ethereum keypair unique to this node
CONSENSUS_PRIVATE_KEY
The node's staking-specific consensus key. This key looks something like: BLS_SIGNING_KEY~...
STATE_PRIVATE_KEY
The node's state-specific consensus key. This key looks something like: SCHNORR_SIGNING_KEY~...
COMMISSION
The proportion of rewards that the validator will earn, expressed as a decimal between 0 and 1 with up to two decimal places. The remaining rewards will be distributed proportionally to delegators
Here are some additional requirements:
Each Ethereum account used (derived from
MNEMONIC+ACCOUNT_INDEX) must have enough gas funds on the L1 to call the registration method of the contract.Each BLS (Espresso) key can be registered only once.
The commission cannot be changed later. One would need to deregister the validator, register another one, and direct delegators to redelegate in order to change it.
Remember, each Ethereum account can only be used to register a single validator once. For multiple validators, at a minimum, different account indices (or mnemonics) must be used.
The output of a successful register transaction command should be of the following form:
Setting the P2P address and x25519 key
Decaf only for now. Validators registered before the V3 stake table (all current Decaf validators) have no P2P address or x25519 key set and must set them once using the command below. Once the P2P networking upgrade activates, validators without these values are excluded from the active set and stop earning rewards. Mainnet will require this in a later release.
The P2P networking layer uses an authenticated, encrypted transport between validators. Each validator publishes two values in the stake table:
x25519 public key: used to encrypt connections between validators.
P2P address (
host:port): the address other validators dial to reach this node.
Requirements for the P2P address:
Use the node's public IP address or DNS name, not a private or loopback address.
It must be reachable over TCP from the public internet and route to the node's P2P bind port (
ESPRESSO_NODE_CLIQUENET_BIND_ADDRESS, default9977). Behind NAT, a firewall, or a load balancer, register the public address and forward that port to the node.
1. Obtain the x25519 key
The x25519 key belongs to the node's key set, alongside the BLS and state keys. How to obtain it depends on how the node's keys are configured.
Node configured with a mnemonic: the x25519 key is derived deterministically from the mnemonic, so no node change is needed. Print the public key using the same mnemonic (and
--indexif the node sets one):Node configured with explicit private keys or a key file without an x25519 key (most current validators): generate a keypair, add the private key to the node config, and restart.
Output:
Where you set the generated private key depends on how the node's other keys are configured:
Node using a key file (
ESPRESSO_NODE_KEY_FILE/ESPRESSO_SEQUENCER_KEY_FILE): add theESPRESSO_NODE_PRIVATE_X25519_KEY=...line to the key file itself.Node using explicit private key env vars (
ESPRESSO_NODE_PRIVATE_STAKING_KEY/ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEYandESPRESSO_NODE_PRIVATE_STATE_KEY/ESPRESSO_SEQUENCER_PRIVATE_STATE_KEY, no key file): setESPRESSO_NODE_PRIVATE_X25519_KEYas an env var alongside them.
Restart the node after setting the key. Without a persistent x25519 key the node uses a random ephemeral key on each start, which will not match the registered public key.
2. Register the public key and P2P address
Use the same wallet (MNEMONIC + ACCOUNT_INDEX) that registered the validator. This is a single invocation; the same command also rotates the values later if needed. New validators can instead pass --x25519-key and --p2p-addr directly to register-validator and skip this step.
For the full command reference, see Configuring networking (x25519 key and p2p address) in the staking-cli README.
Deregistering a Node
At any time after registration, you may choose to stop participating by deregistering. Deregistration is a two-step process: a deregister-validator transaction that exits the active set and unbonds all delegators, followed after the exit escrow period (~7 days) by a claim-validator-exit that returns the validator's principal to the operator address.
Any accumulated staking rewards must be claimed separately via claim-rewards (see Claiming staking rewards). Deregistration does not auto-claim rewards.
Step 1: Submit the deregistration transaction. This immediately removes the node from the active validator set and starts the exit escrow:
Step 2: Claim the validator exit after the escrow period. Once the exit escrow elapses, withdraw the principal back to the operator wallet:
VALIDATOR_ADDRESS is the Ethereum address that was associated with this validator at registration time (derived from MNEMONIC + ACCOUNT_INDEX).
Delegation
In order for a node to participate after it is registered, it must have Espresso tokens delegated to it. These can come from any users who hold Espresso tokens and wish to secure the network and earn rewards through staking. To bootstrap, it is possible for the node operator themselves to delegate to their own node, if they hold Espresso tokens.
Most delegators should use the Decaf staking UI at https://https://stake.decaf.espresso.network/.testnet.espresso.network/ to delegate, undelegate, and claim withdrawals through a wallet (e.g. MetaMask, Ledger). See Delegate $ESP Tokens for a walkthrough. The staking-cli commands below are equivalent and useful for scripting, multisigs, or node operators.
Delegate
To delegate to a registered node:
Delegations become active 2 epochs after the L1 transaction is finalized.
Undelegate (unstake)
Removing delegated tokens is a two-step process: an undelegate transaction that starts the exit escrow, followed (after ~7 days) by a claim-withdrawal that moves the tokens back to your wallet.
You can only have one pending undelegation per validator at a time. Claim each withdrawal before starting another undelegation from the same validator.
Step 1: Initiate the undelegation. The tokens enter the exit escrow and your effective stake decreases 2 epochs after L1 finalization:
Step 2: Claim the withdrawal after the escrow period. Once the exit escrow elapses, move the tokens back to your wallet:
The delegation can always be removed using the undelegate command with the same arguments.
More commands (+ Ledger support)
For more information on the staking CLI (including information on how to use it with a Ledger device), visit the README here.
Environment
When starting a node for the first time, set ESPRESSO_SEQUENCER_CONFIG_PEERSto the URL of a trusted node. This is used to fetch configuration required to join the P2P network. For example, this could be set to https://cache.decaf.testnet.espresso.network to use the Espresso Systems-operated nodes to fetch the config.
Once your node has successfully joined the network once, it should store the config locally, and this parameter will not be required on future restarts.
1. Regular Node
Command
sequencer -- http -- catchup -- status
Environment
Same for all nodes
Chosen by operators
Volumes
$ESPRESSO_SEQUENCER_STORAGE_PATH$ESPRESSO_SEQUENCER_KEY_FILE
Note: Instead of using the above variable $ESPRESSO_SEQUENCER_KEY_FILE to load your keys from a file, you can also set the following two individually:
$ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEY->BLS_SIGNING_KEY~...$ESPRESSO_SEQUENCER_PRIVATE_STATE_KEY->SCHNORR_SIGNING_KEY~...
2. DA Node
Requires operator to additionally run a Postgres server
Command
sequencer -- storage-sql -- http -- catchup -- status -- query
Environment
Same for all nodes
Chosen by operators
Volumes
$ESPRESSO_SEQUENCER_KEY_FILE
Archival Node
Requires operator to additionally run a Postgres server
Command
sequencer -- storage-sql -- http -- catchup -- status -- query
Environment
Same for all nodes
Chosen by operators
Volumes
$ESPRESSO_SEQUENCER_STORAGE_PATH$ESPRESSO_SEQUENCER_KEY_FILE
Note: Instead of using the above variable $ESPRESSO_SEQUENCER_KEY_FILE to load your keys from a file, you can also set the following two individually:
$ESPRESSO_SEQUENCER_PRIVATE_STAKING_KEY->BLS_SIGNING_KEY~...$ESPRESSO_SEQUENCER_PRIVATE_STATE_KEY->SCHNORR_SIGNING_KEY~...
TCP optimizations
We ask also that operators perform some TCP optimizations to improve the networking performance of their nodes. Listed below are the different ways to apply them depending on how your node is set up:
When using Docker Compose
Add the following to your sequencer service:
When just using Docker
Modify your docker run command like so:
When running natively
Create a file at
/etc/sysctl.d/espresso-opts.confAdd the following to it:
Run this command to apply the new settings without rebooting:
Note: this will apply the TCP optimizations to all TCP connections on your machine.
Hardware requirements
Hardware requirements are still in flux, but for now we recommend the following:
Non-DA Node: 2 Core CPU, 2GB memory DA Node: (Sequencer) 4 core CPU, 8GB memory + (Database) 2 Core, 4GB memory.
Storage (DA node): 1.2 TB SSD minimum, ability to scale on demand.
Storage (non-DA Node): Negligible, kilobytes
Last updated

