[ARC-0049] Introduce Redelegation and Extend Unbonding Time#3228
[ARC-0049] Introduce Redelegation and Extend Unbonding Time#3228raychu86 wants to merge 14 commits into
Conversation
…feat/extend-unbond
Signed-off-by: Raymond Chu <14917648+raychu86@users.noreply.github.com>
| V14 = 14, | ||
| /// V15: Introduces the record-existence check and `commit.*.raw` instruction variants. | ||
| /// Increase the anchor time to 35. | ||
| /// V15: Introduces the record-existence check, `commit.*.raw` instruction variants, |
There was a problem hiding this comment.
Note: depending on when this gets merged, likely needs to be updated
|
|
||
| /// The `CreditsVersion` is used to track the version of the `credits.aleo` program. | ||
| #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| pub enum CreditsVersion { |
There was a problem hiding this comment.
Can we comment at which ConsensusVersion they become active. Or even better strongly type this in the Network trait.
That trait being unpleasant to import is a known painpoint, but we dont have a comprehensive solution for it and anything required the credits version will probably also need the Network trait.
|
|
||
| /**********************************************************************************************************************/ | ||
|
|
||
| // The `redelegated` mapping contains the delegator with their redelegation information. |
There was a problem hiding this comment.
Can we add invariants at the top of this file?
There was a problem hiding this comment.
Pull request overview
Implements ARC-0049: extends the unbonding period in credits.aleo/unbond_public from 360 to 403,200 blocks and adds a new redelegate function that lets a delegator switch validators while remaining bonded, subject to a 403,200-block per-delegator cooldown. The activation is gated behind a new ConsensusVersion::V15, which requires introducing a credits_v1 snapshot of credits.aleo (the V1 keys/program, plus V2 keys including the new redelegate circuit) and a CreditsVersion enum so the VM/process can load the appropriate program edition for each consensus range.
Changes:
- Add
redelegate(function + finalize +redelegatedmapping +redelegate_statestruct) tocredits.aleo, extend unbond cooldown to 403,200, and removeredelegated[r1]when a delegator is fully removed. - Introduce
CreditsVersion::{V0,V1,V2},Stack::new_credits,Stack::insert_credits_verifying_keys,Process::load_v1,Program::credits_v0/credits_v1, and gate the V2 stack swap on theV15block height inVM::advance. - Carve out V1 credits keys (mainnet/testnet/canary) and add new V2
redelegatekeys, plusTransition::is_redelegateand a V15 gate inVM::check_transaction_execution; add tests for the new unbond period, the redelegate happy path, cooldown enforcement, validator/self-redelegate rejection, and unbond cleanup.
Reviewed changes
Copilot reviewed 25 out of 126 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| synthesizer/program/src/resources/credits.aleo | Adds redelegated mapping/struct and redelegate finalize; extends unbond cooldown to 403,200; removes redelegated state on full unbond. |
| synthesizer/program/src/resources/credits_v0.aleo | Snapshots the pre-V8 credits program for V0 loading. |
| synthesizer/program/src/lib.rs | Adds credits_v0() / credits_v1() constructors. |
| synthesizer/process/src/stack/mod.rs | Introduces CreditsVersion and helpers new_credits / insert_credits_verifying_keys. |
| synthesizer/process/src/lib.rs | Refactors Process::load* to a shared load_with_credits helper; adds load_v1. |
| synthesizer/process/src/tests/test_credits.rs | Adds tests for redelegate state, cooldown, validator-cannot-redelegate, etc. |
| synthesizer/src/vm/mod.rs | Loads the correct credits version per consensus height and swaps program to V1/V2 at the V8/V15 boundary. |
| synthesizer/src/vm/verify.rs | Gates redelegate calls behind ConsensusVersion::V15. |
| synthesizer/src/vm/tests/test_v15/{mod.rs,update_credits.rs} | New tests around credits.aleo stack update and unbond/redelegate behavior at the V15 boundary. |
| synthesizer/src/vm/tests/test_v14/snark_verify.rs | Imports adjusted for new test helpers. |
| ledger/store/src/transaction/deployment.rs | Populates editions 0/1/2 of credits.aleo in the deployment store. |
| ledger/block/src/transition/mod.rs | Adds Transition::is_redelegate helper. |
| console/network/src/{lib.rs,mainnet_v0.rs,testnet_v0.rs,canary_v0.rs,consensus_heights.rs} | Adds get_credits_v1_*_key accessors, V1 key maps, and updates the V15 docstring. |
| parameters/src/{mainnet,testnet,canary}/mod.rs + resources/credits_v1/, resources/credits/redelegate. | Splits existing credits keys into credits_v1 and adds new V2 redelegate keys; adds insert_*_credit_v1_keys! macro and tests for redelegate keys. |
|
|
||
| // Perform checks if the execution contains `credits.aleo/redelegate`. | ||
| if execution.transitions().any(|t| t.is_redelegate()) { | ||
| // Do not allow `credits.aleo/upgrade` calls on the previous inclusion version or until after the migration block has passed. |
| self.update_credits_verifying_keys()?; | ||
| self.update_credits_program(CreditsVersion::V1)?; | ||
| } | ||
| // If the block advances to `ConsensusVersion::v15`, update the credits program to V2. |
| ensure!( | ||
| program_edition == credits_version_as_edition, | ||
| "The provided credits version ({program_edition}) should match the stack's program edition ({credits_version_as_edition})." | ||
| ); |
| .ok_or_else(|| anyhow!("Proving key for credits.aleo/{function_name}' not found")) | ||
| } | ||
|
|
||
| /// Returns the verifying key for the given function name in the v1 version of `credits.aleo`. | ||
| fn get_credits_v1_verifying_key(function_name: String) -> Result<&'static Arc<VarunaVerifyingKey<Self>>> { | ||
| CREDITS_V1_VERIFYING_KEYS | ||
| .get(&function_name) | ||
| .ok_or_else(|| anyhow!("Verifying key for credits.aleo/{function_name}' not found")) |
| .ok_or_else(|| anyhow!("Proving key (v0) for credits.aleo/{function_name}' not found")) | ||
| } | ||
|
|
||
| /// Returns the verifying key for the given function name in the v1 version of `credits.aleo`. | ||
| fn get_credits_v1_verifying_key(function_name: String) -> Result<&'static Arc<VarunaVerifyingKey<Self>>> { | ||
| TESTNET_CREDITS_V1_VERIFYING_KEYS | ||
| .get(&function_name) | ||
| .ok_or_else(|| anyhow!("Verifying key (v0) for credits_v0.aleo/{function_name}' not found")) |
| .ok_or_else(|| anyhow!("Proving key (v0) for credits.aleo/{function_name}' not found")) | ||
| } | ||
|
|
||
| /// Returns the verifying key for the given function name in the v1 version of `credits.aleo`. | ||
| fn get_credits_v1_verifying_key(function_name: String) -> Result<&'static Arc<VarunaVerifyingKey<Self>>> { | ||
| CANARY_CREDITS_V1_VERIFYING_KEYS | ||
| .get(&function_name) | ||
| .ok_or_else(|| anyhow!("Verifying key (v0) for credits_v0.aleo/{function_name}' not found")) |
Motivation
This PR implements the features proposed in ARC-0049.
The current 360-block unbonding period provides weak economic finality and limited deterrence against short-term stake mobility. Extending it to ~14 days strengthens economic security, but introduces capital inefficiency for honest delegators wanting to switch validators. A new
redelegatefunction addresses this by allowing instant stake reassignment between validators without leaving the bonded state, subject to a matching cooldown.This is done by:
credits.aleo/unbond_publicfrom360u32to403200u32blocks. The circuit and VK are unchanged since only thefinalizescope is modified.redelegatefunction tocredits.aleothat reassigns a delegator's stake between validators while remaining bonded.redelegate, matching the unbonding period.ConsensusVersionfor activation at a specific block height.Test Plan
Tests have been added covering the new unbonding period,
redelegatesuccess and failure cases, cooldown boundary enforcement, andConsensusVersiongating.