Skip to content

Commit 715c3c3

Browse files
authored
Merge pull request #3620 from autonomys/share-price-migration
Add migration for the SharePrice structure change on Taurus
2 parents dbe553e + a8f8866 commit 715c3c3

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,104 @@
11
mod v1_to_v5;
22

3+
pub(crate) use share_price_v0::OperatorEpochSharePrice as OperatorEpochSharePriceV0;
34
pub use v1_to_v5::VersionCheckedMigrateDomainsV1ToV5;
5+
6+
mod share_price_v0 {
7+
use crate::staking::{DomainEpoch, SharePrice as SharePriceV1};
8+
use crate::{Config, Pallet};
9+
use frame_support::pallet_prelude::OptionQuery;
10+
use frame_support::{Identity, storage_alias};
11+
use parity_scale_codec::{Decode, Encode};
12+
use scale_info::TypeInfo;
13+
use sp_domains::OperatorId;
14+
use sp_runtime::{Perbill, Perquintill};
15+
16+
#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Default)]
17+
pub struct SharePrice(Perbill);
18+
19+
impl From<SharePrice> for SharePriceV1 {
20+
fn from(val: SharePrice) -> Self {
21+
SharePriceV1(Perquintill::from_parts(
22+
(val.0.deconstruct() as u64).saturating_mul(1_000_000_000u64),
23+
))
24+
}
25+
}
26+
27+
#[storage_alias]
28+
pub(crate) type OperatorEpochSharePrice<T: Config> = StorageDoubleMap<
29+
Pallet<T>,
30+
Identity,
31+
OperatorId,
32+
Identity,
33+
DomainEpoch,
34+
SharePrice,
35+
OptionQuery,
36+
>;
37+
38+
#[cfg(test)]
39+
mod tests {
40+
use super::*;
41+
use crate::staking::{SharePrice as SharePriceV1, get_share_price};
42+
use crate::tests::{Test, new_test_ext};
43+
44+
#[test]
45+
fn test_share_price_structure_migration() {
46+
for share_price_v0 in [
47+
SharePrice(Perbill::from_parts(1)),
48+
SharePrice(Perbill::one()),
49+
SharePrice(Perbill::from_rational(123456789u32, 987654321u32)),
50+
SharePrice(Perbill::from_rational(
51+
1_000_000_000u32,
52+
1_000_000_000u32 + 123456u32,
53+
)),
54+
] {
55+
let share_price_v1: SharePriceV1 = share_price_v0.clone().into();
56+
57+
for n in [
58+
1213u128,
59+
940u128,
60+
9678231u128,
61+
2367u128,
62+
834228u128,
63+
298749827u128,
64+
1234567890987654321u128,
65+
] {
66+
assert_eq!(
67+
share_price_v0.0.mul_floor::<u128>(n),
68+
share_price_v1.stake_to_shares::<Test>(n)
69+
);
70+
71+
// The v1 share price `shares_to_stake` will return a strict rounding down result
72+
// while the v0 may not, thus v0 share price may return more stake.
73+
assert!(
74+
share_price_v0.0.saturating_reciprocal_mul_floor::<u128>(n)
75+
>= share_price_v1.shares_to_stake::<Test>(n)
76+
);
77+
}
78+
}
79+
}
80+
81+
#[test]
82+
fn test_share_price_getter_migration() {
83+
new_test_ext().execute_with(|| {
84+
let operator_id = 0;
85+
let domain_epoch = (0u32.into(), 0u32).into();
86+
let share_price_v0 = SharePrice(Perbill::from_rational(123456789u32, 987654321u32));
87+
let share_price_v1: SharePriceV1 = share_price_v0.clone().into();
88+
89+
// Decode a v0 share price to v1 should result in an error
90+
let decode_result =
91+
<SharePriceV1 as Decode>::decode(&mut share_price_v0.encode().as_slice());
92+
assert!(decode_result.is_err());
93+
94+
// Insert an v0 share price
95+
OperatorEpochSharePrice::<Test>::insert(operator_id, domain_epoch, &share_price_v0);
96+
97+
// `get_share_price` should internally convert the v0 share price to v1.
98+
let share_price = get_share_price::<Test>(operator_id, domain_epoch);
99+
100+
assert_eq!(share_price, Some(share_price_v1));
101+
})
102+
}
103+
}
104+
}

crates/pallet-domains/src/staking.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate alloc;
55

66
use crate::block_tree::invalid_bundle_authors_for_receipt;
77
use crate::bundle_storage_fund::{self, deposit_reserve_for_storage_fund};
8+
use crate::migrations::OperatorEpochSharePriceV0;
89
use crate::pallet::{
910
Deposits, DomainRegistry, DomainStakingSummary, HeadDomainNumber, NextOperatorId,
1011
OperatorIdOwner, Operators, PendingSlashes, PendingStakingOperationCount, Withdrawals,
@@ -40,7 +41,7 @@ pub(crate) struct Deposit<Share: Copy, Balance: Copy> {
4041
/// A share price is parts per billion of shares/ai3.
4142
/// Note: Shares must always be equal to or lower than ai3, and both shares and ai3 can't be zero.
4243
#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Default)]
43-
pub struct SharePrice(Perquintill);
44+
pub struct SharePrice(pub Perquintill);
4445

4546
impl SharePrice {
4647
/// Creates a new instance of share price from shares and stake.
@@ -89,6 +90,16 @@ impl SharePrice {
8990
}
9091
}
9192

93+
// TODO: this is only needed for migration of the share price structure change in Taurus
94+
// remove once Taurus is deprecated
95+
pub(crate) fn get_share_price<T: Config>(
96+
operator_id: OperatorId,
97+
domain_epoch: DomainEpoch,
98+
) -> Option<SharePrice> {
99+
OperatorEpochSharePrice::<T>::get(operator_id, domain_epoch)
100+
.or_else(|| OperatorEpochSharePriceV0::<T>::get(operator_id, domain_epoch).map(Into::into))
101+
}
102+
92103
/// Unique epoch identifier across all domains. A combination of Domain and its epoch.
93104
#[derive(TypeInfo, Debug, Encode, Decode, Copy, Clone, PartialEq, Eq)]
94105
pub struct DomainEpoch(DomainId, EpochIndex);
@@ -477,10 +488,7 @@ pub(crate) fn do_convert_previous_epoch_deposits<T: Config>(
477488
let epoch_share_price = match deposit.pending {
478489
None => return Ok(()),
479490
Some(pending_deposit) => {
480-
match OperatorEpochSharePrice::<T>::get(
481-
operator_id,
482-
pending_deposit.effective_domain_epoch,
483-
) {
491+
match get_share_price::<T>(operator_id, pending_deposit.effective_domain_epoch) {
484492
Some(p) => p,
485493
None => {
486494
ensure!(
@@ -533,7 +541,7 @@ pub(crate) fn do_convert_previous_epoch_withdrawal<T: Config>(
533541
return Ok(());
534542
}
535543

536-
match OperatorEpochSharePrice::<T>::get(operator_id, withdraw.domain_epoch) {
544+
match get_share_price::<T>(operator_id, withdraw.domain_epoch) {
537545
Some(p) => p,
538546
None => return Err(Error::MissingOperatorEpochSharePrice),
539547
}

0 commit comments

Comments
 (0)