-
Notifications
You must be signed in to change notification settings - Fork 1.1k
pallet-referenda: Migrate from Currency reserves to fungible holds #10701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
pallet-referenda: Migrate from Currency reserves to fungible holds #10701
Conversation
|
/cmd label T2-pallets |
…r I, updating related usages in the NativeBalance methods.
|
There is a runtime type mismatch now This means we need to migrate treasury first to use Fungible before this one. |
That mean we need to upgrade both together, because otherwise pallet-referenda won't support pallet-treasury for slash destination. IMO we can make treasury |
| >; | ||
| /// Currency type for this pallet. | ||
| type Currency: ReservableCurrency<Self::AccountId>; | ||
| type NativeBalance: Inspect<Self::AccountId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO better to keep the same old name Currency. It is still a kind of currency type, the underlying traits are fungible but this is fine. Most users won't see the difference as pallet-balances implements both. And if it breaks the compile error will be fine.
| &HoldReason::<I>::DecisionDeposit.into(), | ||
| &who, | ||
| amount, | ||
| Precision::Exact, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should use Precision::BestEffort, we don't want to prevent a kill from happening because the slash is failing for some reason.
| Self::slash_deposit(Some(status.submission_deposit.clone()))?; | ||
| Self::slash_deposit(status.decision_deposit.clone())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like that this can return an error here. We don't want to block the kill if for some reason the slash fails. Also fungible API never really specifies why it could fail. In the other comment I say to change to BestEffort to make this scenario less likely but still strictly speaking it doesn't prevent the slash from failing, so maybe better to actually ignore the error.
| Self::slash_deposit(Some(status.submission_deposit.clone()))?; | |
| Self::slash_deposit(status.decision_deposit.clone())?; | |
| let _ = Self::slash_deposit(Some(status.submission_deposit.clone())).inspect(/* log some error or something */); | |
| let _ = Self::slash_deposit(status.decision_deposit.clone()).inspect(/* log some error or something */); |
| if on_chain_version != 1 { | ||
| log::warn!(target: TARGET, "skipping migration from v1 to v2."); | ||
| return weight; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use versioned migration to factorize out those checks: e.g.
polkadot-sdk/substrate/frame/staking/src/migrations.rs
Lines 147 to 153 in 0433400
| pub type MigrateV15ToV16<T> = VersionedMigration< | |
| 15, | |
| 16, | |
| VersionUncheckedMigrateV15ToV16<T>, | |
| Pallet<T>, | |
| <T as frame_system::Config>::DbWeight, | |
| >; |
| let mut migrated_deposits = 0u32; | ||
|
|
||
| for (index, info) in v1::ReferendumInfoFor::<T, I>::iter() { | ||
| weight.saturating_accrue(T::DbWeight::get().reads(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it fine to do like this? T::DbWeight::get().reads(1) only returns the ref_time weight and ignores the proof_size weight.
| for (index, info) in v1::ReferendumInfoFor::<T, I>::iter() { | ||
| weight.saturating_accrue(T::DbWeight::get().reads(1)); | ||
|
|
||
| let deposits_to_migrate = Self::collect_deposits(&info); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no way for an attacker to start submitting small deposits and make this too big, isn't it? otherwise we should do a multi block migration.
Summary
This PR migrates
pallet-referendafrom the deprecatedCurrencytrait with anonymous reserves to the modernfungibletraits with typed holds, bumping the storage version from v1 to v2. This is part of the umbrella task #226.Changes
Config Updates
CurrencywithNativeBalanceusing the new fungible traits:fungible::Inspectfungible::Mutatefungible::Balancedfungible::InspectHoldfungible::MutateHoldHoldReason::DecisionDepositcomposite enum for tracking deposit holds with a specific reasonStorage Migration (v1 → v2)
Added
MigrateV1ToV2<T, I, OldCurrency>migration that:ReservableCurrencytraitHoldReason::DecisionDepositusing the newMutateHoldtraitThe migration gracefully handles edge cases:
Killedreferenda (no deposits to migrate)try-runtimehooks for pre/post upgrade verificationRuntime Integration
To use this migration in your runtime:
Testing
Added comprehensive test coverage:
migration_v1_to_v2_works- Tests full migration flow with multiple referendum types (Ongoing, Approved, TimedOut)migration_v1_to_v2_skips_if_not_v1- Verifies migration is skipped when not on version 1migration_v1_to_v2_handles_killed_referendum- Tests handling of killed referenda with no depositsChecklist
Trequired)/cmd label <label-name>to add labels