Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/core/content/learn/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Berachain Improvement Proposals (BRIPs) are welcome from anyone, by [contributin

Below are important changes shipped to Berachain.

## September 2025

**Enhanced validator lifecycle documentation** – Updated explanation of effective balance calculation and hysteresis mechanism in the [validator lifecycle guide](/nodes/validator-lifecycle).

## August 2025

**Reward Vault enhanced functionality** – Added two new functions to enhance staking and reward management capabilities:
Expand Down
115 changes: 81 additions & 34 deletions apps/core/content/nodes/validator-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,83 +15,80 @@ Validators have several key responsibilities:
- Participating in consensus by voting on the canonical chain
- Maintaining network security through their staked tokens

The Validator's Voting Power is the amount of `$BERA` they have deposited, rounded down to the nearest `{{ constants.mainnet.stakeMinimumIncrement }}`. Their Voting Power, as a proportion of the total Voting Power among all validators, is their probability of being selected to propose a block.
The Validator's Voting Power is determined by their **Effective Balance**, which is calculated from their actual balance using [specific rounding rules](/nodes/validator-lifecycle#voting-power). The Effective Balance is rounded down to the nearest `{{ constants.mainnet.stakeMinimumIncrement }}` BERA to determine **Voting Power**.

The limit on the number of active validators, termed in this document the `ValidatorSetCap`, is set in Beacon-Kit, and can only be affected
by Berachain governance actions followed by an update to Beacon-Kit.
by Berachain governance actions followed by an update to Beacon-Kit. This limit is `{{constants.mainnet.validatorActiveSetSize}}` currently.

## Validator Lifecycle

This diagram illustrates the life cycle of a validator:

![Validator Lifecycle](/assets/validator-lifecycle.png)

The labeled states are as follows:
The labelled states:

- **Deposited**
Deposit event captured by Beacon-kit and deposit message signature is verified.
Deposit event captured by Beacon-Kit and deposit message signature verified.

- **Eligible**
Validator has been marked as `EligibleForActivationQueue`.
Validator marked as `EligibleForActivationQueue`.

- **Active**
The validator is marked as Active after 1 epoch from the Eligible state. Currently, the Active Set consists of `{{constants.mainnet.validatorActiveSetSize}}` Validators, which is the number of Validators that can propose blocks.
Validator becomes Active after 1 epoch in Eligible. The Active Set has `{{constants.mainnet.validatorActiveSetSize}}` validators (the block proposers).

- **Exited**
The validator is marked for exit if the `ValidatorSetCap` limit is hit and the validator has the lowest effective balance or a lower-order pubKey if it has the same effective balance as another validator.
Validator is marked for exit if the `VSC` is hit and it has the lowest effective balance or a lower-order pubKey among equals.

- **Withdrawn**
Once the validator is marked as exited, after a delay of 1 epoch, validator funds are fully withdrawn. All `$BERA` staked to a Validator is returned to the Validator's Withdrawal Credentials Address.

With the states defined, let’s examine each in detail, along with the transitions between them.
After being marked Exited and a 1-epoch delay, funds are fully withdrawn. All $BERA staked is returned to the validator’s withdrawal address.

## Deposited State
With the states defined, let's look at each in detail and how you move between them.

The validator’s journey begins with a deposit transaction on the **Execution Layer** (via the Deposit Contract). Once this deposit transaction is successful and emits an event, it is captured by beacon-kit nodes and processed for signature verification.
### Deposited State

The initial deposit transaction establishes a connection between a validator's Consensus Layer identity and its Execution Layer identity and
decides the withdrawal address for the $BERA stake.
The validator’s journey starts with a deposit on the **Execution Layer** (via the Deposit Contract). Once the deposit is successful and emits an event, beacon-kit nodes pick it up and verify the signature.

Credentials Address,
The deposit links your Consensus Layer and Execution Layer identities and sets the withdrawal address for your $BERA.

- **Verification Delay**
It takes 2 ETH1 blocks (on the EVM layer) from the event emission to verify the event on the Consensus Layer. If the deposit event is processed at epoch `N`, the validator is then considered in the **Deposited** state, provided the validator’s balance equals (or exceeds) the minimum required for staking.
It takes 2 ETH1 blocks (on the EVM layer) from event emission to verification on the Consensus Layer. If processed at epoch `N`, the validator is in **Deposited** if the balance meets the minimum.

- **Minimum Requirement**
A total of **{{ constants.mainnet.minEffectiveBalance }} BERA** is required for a validator to reach the Deposited state. (Multiple deposits can accumulate to this amount.)
**{{ constants.mainnet.minEffectiveBalance }} BERA** is needed to reach Deposited. (Multiple deposits can add up.)

- **Signature Verification**
- On the first deposit, the validator’s signature is fully verified (similar to ETH2).
- Subsequent deposits simply increase the validator’s balance (no additional signature verification is done).
- First deposit: full signature check (like ETH2).
- Later deposits: just increase balance (no extra signature check).

### Potential Failure Points
#### Potential Failure Points

1. **Deposit Transaction Failure on the EVM Layer**

> **Note**: Funds are **not lost** if the transaction fails on the EVM layer due to any of these reasons.
> **Note**: Funds are **not lost** if the transaction fails on the EVM layer for these reasons.
- **Invalid Inputs**
- Invalid pubKey, signature, or withdrawal credentials (e.g., incorrect lengths).
- Invalid deposit amount (less than the **minimum deposit amount of {{ constants.mainnet.registrationMinimum }} BERA**, or not a multiple of 1 gwei).
- Bad pubKey, signature, or withdrawal credentials (wrong lengths).
- Deposit amount too low (**minimum {{ constants.mainnet.registrationMinimum }} BERA**) or not a multiple of 1 gwei.
- **Operator Address Issues**
- A non-zero operator address **must** be passed on the **first** deposit.
- A zero address **must** be passed on **subsequent** deposits.
- **Gas Issues**
- If the transaction consumes 100% of the provided gas, it may fail; increase gas if necessary.
- Non-zero operator address **required** on the **first** deposit.
- **Front-Running (DOS Attack)**
- Someone could front-run the deposit transaction, setting an operator address that you did not intend.
- If your transaction fails with a revert related to the operator address, it might indicate you were front-ran.
- **Important**: If your transaction is front-ran and sets a different operator address, **do not continue** with that validator. Generate a new set of keys because the attacker could control your POL rewards. [learn more](https://gist.github.com/neverDefined/e9ada58947bf8bd855051c3cf48f2d83)
- **Important**: If your transaction is front-ran and [`BeaconDeposit:getOperator`](https://docs.berachain.com/developers/contracts/beacondeposit#getoperator) shows a different pubkey than yours, **do not continue** with that validator. Generate a new set of keys because the attacker could control your POL rewards. [learn more](https://gist.github.com/neverDefined/e9ada58947bf8bd855051c3cf48f2d83)

2. **Deposit Message Signature Verification Failure on the Consensus Layer**
> **WARNING**: **Funds are lost** if signature verification fails on the Consensus Layer.
- Mismatch between signed and actual withdrawal credentials.
- Mismatch between signed and actual pubKey.
- Mismatch between signed and actual withdrawal credentials, pubkey, or deposit amount.

After remaining in the **Deposited** state for 1 epoch, the validator automatically moves to the **Eligible** state and becomes eligible for activation.

## Eligible State
### Eligible State

Once the validator enters the **Deposited** state at epoch `N`, it is marked as `EligibleForActivationQueue` as soon as epoch `N+1` starts. This is guaranteed because there is no cap on the activation queue size.

The validator remains in this **Eligible** state for 1 epoch. Afterward, it is added to the **Active** set, provided the `ValidatorSetCap` is not exceeded, or if the validator is of higher priority (i.e., higher effective balance or lower-order pubKey among equals).

## Active State
### Active State

After spending 1 epoch in the **Eligible** state (say at `N+1`), the validator is marked **Active** at the start of epoch `N+2`.

Expand All @@ -102,7 +99,7 @@ Once **Active**:
- **CometBFT Consensus** will use the validator for block proposals, validations, and voting.
- The higher a validator’s `EffectiveBalance`, the higher its voting power—and thus, the more frequently it will be polled for block proposals.

## Exited State
### Exited State

A Validator may choose to exit by [withdrawing their complete stake](/nodes/guides/withdraw-stake). Otherwise, the **only** reason for a validator to be evicted from the set (and have its funds returned) is if the `ValidatorSetCap` is reached and another validator with a higher priority enters. Higher priority is determined by:

Expand All @@ -111,7 +108,7 @@ A Validator may choose to exit by [withdrawing their complete stake](/nodes/guid

When the validator is evicted from the validator set, it is marked **Exited**.

## Withdrawn State
### Withdrawn State

Once the validator is marked **Exited** (say at epoch `M`), its funds are fully withdrawn at epoch `M+1`. Because BeaconKit does not currently enforce a cap on validator churn, this finalizes the validator’s lifecycle.

Expand All @@ -128,3 +125,53 @@ Putting it all together, we have a complete picture of the Berachain validator l
![Validator Extended Lifecycle](/assets/validator-extended-lifecycle.png)

Note that transitions between states are done via a queue, on a FIFO basis, with a cap on the number of transitions in each state to limit excessive churn in the validator set.

## Voting Power

A validator’s **voting power** depends directly on their effective balance. The higher your effective balance, the more often you’ll be selected to propose blocks, and the more weight your votes carry in consensus.

The effective balance calculation uses a specific rounding formula: `min(actual_balance - (actual_balance % effective_balance_increment), max_effective_balance)`. This means your effective balance is always rounded down to the nearest 10,000 BERA increment, and any balance above the maximum effective balance (10 million BERA) is ignored for voting power calculations.

For example, if you have 125,000 BERA staked, your effective balance becomes 120,000 BERA (rounded down to the nearest 10,000 BERA increment).

Effective balance updates happen at the end of each epoch and use hysteresis to avoid constant voting power changes from small balance moves. The system uses a few key constants to decide when effective balance changes.

- **EBI** (Effective Balance Increment): `{{ constants.mainnet.stakeMinimumIncrement }}` BERA (10,000 BERA), the base unit for effective balance.
- **HQ** (Hysteresis Quotient): 4
- **HDM** (Hysteresis Downward Multiplier): 1
- **HUM** (Hysteresis Upward Multiplier): 5

Thresholds are calculated as:

- **HI** (Hysteresis Increment):

$$
\text{HI} = \frac{\text{EBI}}{\text{HQ}} = \frac{10{,}000\ \text{BERA}}{4} = 2{,}500\ \text{BERA}
$$

- **Downward Threshold**:

$$
\text{Down} = \text{HI} \times \text{HDM} = 2{,}500\ \text{BERA} \times 1 = 2{,}500\ \text{BERA}
$$

- **Upward Threshold**:
$$
\text{Up} = \text{HI} \times \text{HUM} = 2{,}500\ \text{BERA} \times 5 = 12{,}500\ \text{BERA}
$$

To decrease your effective balance, your actual balance must drop below your current effective balance minus the downward threshold (2,500 BERA). To increase it, your actual balance must exceed your current effective balance plus the upward threshold (12,500 BERA).

**Example:**
If a validator has an effective balance of 100,000 BERA:

- To decrease: actual balance < 97,500 BERA
- To increase: actual balance > 112,500 BERA

**Scenario 1: Raising Effective Balance to 110,000 BERA**
To increase your effective balance from 100,000 to 110,000 BERA, you need to trigger the upward threshold. The most efficient approach is to deposit 12,501 BERA (bringing your actual balance to 112,501 BERA), which exceeds the upward threshold of 112,500 BERA. This triggers the effective balance update, and the 112,501 BERA is rounded down to 110,000 BERA. You can then withdraw the excess 2,501 BERA if desired, leaving you with exactly 110,000 BERA actual balance and 110,000 BERA effective balance.

**Scenario 2: Reducing Effective Balance to 90,000 BERA**
To decrease your effective balance from 100,000 to 90,000 BERA, you need to withdraw between 2,501 and 10,000 $BERA inclusive, enough so your actual balance drops below 97,500 BERA.

This hysteresis keeps voting power stable, so validators don't see their power bounce around with every small deposit or withdrawal.