From 5372b8b490f6e6d8a7828c3016b038e6ccd515c1 Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 9 Sep 2025 10:15:41 -0400 Subject: [PATCH 1/8] fixes for phrasing and organization --- .../core/content/nodes/validator-lifecycle.md | 61 +++++++++---------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index c55a636e..c491b770 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -20,78 +20,75 @@ The Validator's Voting Power is the amount of `$BERA` they have deposited, round 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. +## 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`. @@ -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: @@ -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. From 72ff33810fefd35765f699bce7ba657a43f2777b Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 9 Sep 2025 10:15:57 -0400 Subject: [PATCH 2/8] describe hysteresis impact --- .../core/content/nodes/validator-lifecycle.md | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index c491b770..84e3cbf8 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -15,7 +15,7 @@ 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. The Effective Balance is rounded down to the nearest `{{ constants.mainnet.stakeMinimumIncrement }}` BERA (the effective balance increment), but changes to Effective Balance are subject to hysteresis to prevent frequent fluctuations. 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. @@ -125,3 +125,50 @@ 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. Only significant changes move the needle—no need to worry about your voting power catching a cold from a minor balance sneeze. From dfc900603fec5c09b89755e6ceab0ae2a49ebe98 Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 9 Sep 2025 10:21:29 -0400 Subject: [PATCH 3/8] pnpm format --- apps/core/content/nodes/validator-lifecycle.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index 84e3cbf8..29712681 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -128,11 +128,11 @@ Note that transitions between states are done via a queue, on a FIFO basis, with ## 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. +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). +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. @@ -144,11 +144,13 @@ Effective balance updates happen at the end of each epoch and use hysteresis to 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} $$ @@ -162,13 +164,14 @@ To decrease your effective balance, your actual balance must drop below your cur **Example:** If a validator has an effective balance of 100,000 BERA: -- To decrease: actual balance < 97,500 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. +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. Only significant changes move the needle—no need to worry about your voting power catching a cold from a minor balance sneeze. From 7c9b7fe8c89e1d103ebbbf77db86d18129d51f5e Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 9 Sep 2025 10:42:06 -0400 Subject: [PATCH 4/8] update changelog --- apps/core/content/learn/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/core/content/learn/changelog.md b/apps/core/content/learn/changelog.md index 7ed3ccd4..42f2bcc2 100644 --- a/apps/core/content/learn/changelog.md +++ b/apps/core/content/learn/changelog.md @@ -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: From 4a9ca56a51d675f39f85e163af1dbf7952d35d34 Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 9 Sep 2025 10:44:27 -0400 Subject: [PATCH 5/8] remove unwanted dad joke --- apps/core/content/nodes/validator-lifecycle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index 29712681..e1eb8ddf 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -174,4 +174,4 @@ To increase your effective balance from 100,000 to 110,000 BERA, you need to tri **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. Only significant changes move the needle—no need to worry about your voting power catching a cold from a minor balance sneeze. +This hysteresis keeps voting power stable, so validators don't see their power bounce around with every small deposit or withdrawal. \ No newline at end of file From c28c9abd02d68e33a021db54d54718780f9125a8 Mon Sep 17 00:00:00 2001 From: Camembear Date: Tue, 16 Sep 2025 14:15:40 -0400 Subject: [PATCH 6/8] pnpm format --- apps/core/content/nodes/validator-lifecycle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index e1eb8ddf..2af298f9 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -174,4 +174,4 @@ To increase your effective balance from 100,000 to 110,000 BERA, you need to tri **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. \ No newline at end of file +This hysteresis keeps voting power stable, so validators don't see their power bounce around with every small deposit or withdrawal. From 55d24eb99181d4e9aa387465b5f2cb90946ded95 Mon Sep 17 00:00:00 2001 From: Camembear Date: Wed, 17 Sep 2025 14:13:33 -0400 Subject: [PATCH 7/8] wording --- apps/core/content/nodes/validator-lifecycle.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index 2af298f9..a329f0ae 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -15,10 +15,10 @@ 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 determined by their **Effective Balance**, which is calculated from their actual balance using specific rounding rules. The Effective Balance is rounded down to the nearest `{{ constants.mainnet.stakeMinimumIncrement }}` BERA (the effective balance increment), but changes to Effective Balance are subject to hysteresis to prevent frequent fluctuations. +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 From 7b81f9afca033a16f3f84775dd83903d817558e2 Mon Sep 17 00:00:00 2001 From: Camembear Date: Wed, 17 Sep 2025 14:13:50 -0400 Subject: [PATCH 8/8] pnpm format --- apps/core/content/nodes/validator-lifecycle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/core/content/nodes/validator-lifecycle.md b/apps/core/content/nodes/validator-lifecycle.md index a329f0ae..3954e127 100644 --- a/apps/core/content/nodes/validator-lifecycle.md +++ b/apps/core/content/nodes/validator-lifecycle.md @@ -18,7 +18,7 @@ Validators have several key responsibilities: 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. This limit is `{{constants.mainnet.validatorActiveSetSize}}` currently. +by Berachain governance actions followed by an update to Beacon-Kit. This limit is `{{constants.mainnet.validatorActiveSetSize}}` currently. ## Validator Lifecycle