Chapter 14
Rewards

Requirements: Rewards Requirements


Contents



14.1 Overview
14.2 Types
14.3 Reward Distribution
14.4 APIs
14.5 Leader Selection
14.6 Claiming



14.1 # Overview

Espresso incentivizes validators who act honestly and help secure the network through rewards distributed as Espresso tokens (ESP). Validators stake tokens in the form of Espresso tokens in the stake table contract. They earn rewards by proposing new blocks. In the case of dishonest behavior, their staked capital can be penalized. Validators can miss the rewards if they fail to propose a block when they are selected as the leader. Validators list is basically the stake table which is constructed from the permissionless stake table contract every epoch.

Hotshot executes add_epoch_root(decided_header: Header) to construct the stake table based on contract data and update the in-memory state. This function processes all stake table contract events and selects validators that meet the specified criteria. Only the top 100 validators with stakes above a minimum threshold are included. Leaders are selected using a Distributed Randomness Beacon (DRB). The leader proposing a block receives a commission reward, and the remaining reward is distributed among delegators based on their stakes. The stake table from the contract is only populated third epoch onwards (root is e -2 ) Therefore, reward distribution starts from the third epoch onwards.

14.2 Types

Each validator has a commission rate and a set of delegators contributing to their total stake.

The Validator type has the following fields:

If a validator wants to stake tokens, it must delegate tokens to itself. Thus, the validator’s account address will also appear in the delegators list. This relaxes the requirement for node operators to possess the tokens themselves. The Espresso Foundation can delegate tokens to the node operator, allowing them to remain an active node, provided they meet the criteria.

The ComputedRewards type represents the calculated rewards for a validator and its delegators after processing a block reward. It includes:

The reward distribution is computed by the validator’s compute_rewards method, which allocates the total block reward between delegators (proportional to their stake) and the validator’s commission (based on the commission rate). Any rounding discrepancies are adjusted in the validator’s commission to ensure the total reward matches the block reward.

Rewards are applied to the in-memory state, reward merkle tree in this case, via the apply_rewards method, which updates the persistent reward balances for each delegator and the validator.

14.3 Reward Distribution

Rewards are tracked using a Universal Merkle Tree data structure called the RewardMerkleTree. It uses the SHA3 hashing algorithm and has an arity of 256 (28), meaning each node has 256 children. Since an Ethereum address is 160 bits (or 20 bytes) long, each byte can correspond to one level of the tree, resulting in a fixed depth of 20. This structure allows efficient lookups, as each byte determines which child to traverse at each level. It also eliminates the need for deeper trees, making proof verification faster because the number of hash computations required to generate or verify a proof is significantly reduced. The tree stores reward amounts as 256-bit unsigned integers (U256).

Each reward distribution updates an account’s balance by adding the new reward to the previous balance. Thus, an account’s total reward balance in the RewardMerkleTree is the cumulative sum of all rewards received over time.

Updating the reward Merkle tree requires each node to have the existing reward account entries for which rewards need to be distributed. Since each reward entry represents a cumulative sum, the node must know the previous account balance to correctly apply the new reward. If it does not, the node needs to catch up. Each query node stores the reward Merklized state in its own database. During catchup, the node can directly query the database for the exact snapshot it needs. If the exact snapshot is not available, it can rebuild the state using an older snapshot and by applying the undecided proposals stored in consensus storage. If that still doesn’t work, the node can request the missing reward accounts from other peers. This can be done using the catchup API or the peer-to-peer (P2P) catchup, which uses a simple request-response protocol. This catchup process ensures consistency and must occur whenever a node proposes a block or validates a proposal.

During proposal validation, the node recalculates the rewards and verifies that the computed reward Merkle tree commitment matches the one included in the proposal. Hence, the node must first catch up on the reward accounts and reconstruct the corresponding state.

14.4 APIs

14.5 Leader Selection

The leader selection process in a randomized committee is based on a pseudo-random breakpoint.

This breakpoint is derived by hashing together the DRB (Distributed Randomness Beacon) result, the current view number, and a hash of the stake table using the SHA-512 hashing algorithm. The resulting hash output is then reduced modulo the total cumulative stake, producing a breakpoint value within the range of possible cumulative stakes.

Nodes in the stake table are ordered by xor(public key, DRB result), with the DRB result cyclically repeated to match the number of bytes in the public key. The leader for a given view is the first node whose cumulative total stake is strictly greater than the breakpoint. The leader selection process is deterministic, and all nodes will independently select the same leader for the same view. The time required to produce the DRB result makes it practically impossible to bias.

14.6 Claiming

Note: This section requires further discussion and has not been implemented yet.