cargo +nightly fmt (#3540)

* cargo +nightly fmt

* add cargo-fmt check to ci

* update ci

* fmt

* fmt

* skip macro

* ignore bridges
This commit is contained in:
Shawn Tabrizi
2021-08-02 12:47:33 +02:00
committed by GitHub
parent 30e3012270
commit ff5d56fb76
350 changed files with 20617 additions and 21266 deletions
File diff suppressed because it is too large Load Diff
+300 -120
View File
@@ -16,24 +16,31 @@
//! Pallet to process claims from Ethereum addresses.
use sp_std::{prelude::*, fmt::Debug};
use sp_io::{hashing::keccak_256, crypto::secp256k1_ecdsa_recover};
use frame_support::{ensure, traits::{Currency, Get, VestingSchedule, IsSubType}, weights::Weight};
use parity_scale_codec::{Encode, Decode};
use frame_support::{
ensure,
traits::{Currency, Get, IsSubType, VestingSchedule},
weights::Weight,
};
pub use pallet::*;
use parity_scale_codec::{Decode, Encode};
use primitives::v1::ValidityError;
#[cfg(feature = "std")]
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256};
#[cfg(feature = "std")]
use sp_runtime::traits::Zero;
use sp_runtime::{
traits::{CheckedSub, SignedExtension, DispatchInfoOf}, RuntimeDebug,
traits::{CheckedSub, DispatchInfoOf, SignedExtension},
transaction_validity::{
TransactionValidity, ValidTransaction, InvalidTransaction, TransactionValidityError,
InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
},
RuntimeDebug,
};
use primitives::v1::ValidityError;
pub use pallet::*;
use sp_std::{fmt::Debug, prelude::*};
type CurrencyOf<T> = <<T as Config>::VestingSchedule as VestingSchedule<<T as frame_system::Config>::AccountId>>::Currency;
type CurrencyOf<T> = <<T as Config>::VestingSchedule as VestingSchedule<
<T as frame_system::Config>::AccountId,
>>::Currency;
type BalanceOf<T> = <CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
pub trait WeightInfo {
@@ -46,11 +53,21 @@ pub trait WeightInfo {
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn claim() -> Weight { 0 }
fn mint_claim() -> Weight { 0 }
fn claim_attest() -> Weight { 0 }
fn attest() -> Weight { 0 }
fn move_claim() -> Weight { 0 }
fn claim() -> Weight {
0
}
fn mint_claim() -> Weight {
0
}
fn claim_attest() -> Weight {
0
}
fn attest() -> Weight {
0
}
fn move_claim() -> Weight {
0
}
}
/// The kind of statement an account needs to make for a claim to be valid.
@@ -93,7 +110,10 @@ pub struct EthereumAddress([u8; 20]);
#[cfg(feature = "std")]
impl Serialize for EthereumAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let hex: String = rustc_hex::ToHex::to_hex(&self.0[..]);
serializer.serialize_str(&format!("0x{}", hex))
}
@@ -101,12 +121,17 @@ impl Serialize for EthereumAddress {
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for EthereumAddress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let base_string = String::deserialize(deserializer)?;
let offset = if base_string.starts_with("0x") { 2 } else { 0 };
let s = &base_string[offset..];
if s.len() != 40 {
Err(serde::de::Error::custom("Bad length of Ethereum address (should be 42 including '0x')"))?;
Err(serde::de::Error::custom(
"Bad length of Ethereum address (should be 42 including '0x')",
))?;
}
let raw: Vec<u8> = rustc_hex::FromHex::from_hex(s)
.map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?;
@@ -133,9 +158,9 @@ impl sp_std::fmt::Debug for EcdsaSignature {
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use super::*;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
@@ -146,7 +171,7 @@ pub mod pallet {
pub trait Config: frame_system::Config {
/// The overarching event type.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type VestingSchedule: VestingSchedule<Self::AccountId, Moment=Self::BlockNumber>;
type VestingSchedule: VestingSchedule<Self::AccountId, Moment = Self::BlockNumber>;
#[pallet::constant]
type Prefix: Get<&'static [u8]>;
type MoveClaimOrigin: EnsureOrigin<Self::Origin>;
@@ -192,11 +217,8 @@ pub mod pallet {
/// The block number is when the vesting should start.
#[pallet::storage]
#[pallet::getter(fn vesting)]
pub(super) type Vesting<T: Config> = StorageMap<
_,
Identity, EthereumAddress,
(BalanceOf<T>, BalanceOf<T>, T::BlockNumber),
>;
pub(super) type Vesting<T: Config> =
StorageMap<_, Identity, EthereumAddress, (BalanceOf<T>, BalanceOf<T>, T::BlockNumber)>;
/// The statement kind that must be signed, if any.
#[pallet::storage]
@@ -208,17 +230,15 @@ pub mod pallet {
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub claims: Vec<(EthereumAddress, BalanceOf<T>, Option<T::AccountId>, Option<StatementKind>)>,
pub claims:
Vec<(EthereumAddress, BalanceOf<T>, Option<T::AccountId>, Option<StatementKind>)>,
pub vesting: Vec<(EthereumAddress, (BalanceOf<T>, BalanceOf<T>, T::BlockNumber))>,
}
#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
claims: Default::default(),
vesting: Default::default(),
}
GenesisConfig { claims: Default::default(), vesting: Default::default() }
}
}
@@ -226,23 +246,32 @@ pub mod pallet {
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
// build `Claims`
self.claims.iter().map(|(a, b, _, _)| (a.clone(), b.clone())).for_each(|(a, b)| {
Claims::<T>::insert(a, b);
});
self.claims
.iter()
.map(|(a, b, _, _)| (a.clone(), b.clone()))
.for_each(|(a, b)| {
Claims::<T>::insert(a, b);
});
// build `Total`
Total::<T>::put(
self.claims.iter().fold(Zero::zero(), |acc: BalanceOf<T>, &(_, b, _, _)| acc + b),
self.claims
.iter()
.fold(Zero::zero(), |acc: BalanceOf<T>, &(_, b, _, _)| acc + b),
);
// build `Vesting`
self.vesting.iter().for_each(|(k, v)| { Vesting::<T>::insert(k, v); });
self.vesting.iter().for_each(|(k, v)| {
Vesting::<T>::insert(k, v);
});
// build `Signing`
self.claims.iter()
self.claims
.iter()
.filter_map(|(a, _, _, s)| Some((a.clone(), s.clone()?)))
.for_each(|(a, s)| {
Signing::<T>::insert(a, s);
});
// build `Preclaims`
self.claims.iter()
self.claims
.iter()
.filter_map(|(a, _, i, _)| Some((i.clone()?, a.clone())))
.for_each(|(i, a)| {
Preclaims::<T>::insert(i, a);
@@ -283,7 +312,7 @@ pub mod pallet {
pub fn claim(
origin: OriginFor<T>,
dest: T::AccountId,
ethereum_signature: EcdsaSignature
ethereum_signature: EcdsaSignature,
) -> DispatchResult {
ensure_none(origin)?;
@@ -422,9 +451,13 @@ pub mod pallet {
Claims::<T>::take(&old).map(|c| Claims::<T>::insert(&new, c));
Vesting::<T>::take(&old).map(|c| Vesting::<T>::insert(&new, c));
Signing::<T>::take(&old).map(|c| Signing::<T>::insert(&new, c));
maybe_preclaim.map(|preclaim| Preclaims::<T>::mutate(&preclaim, |maybe_o|
if maybe_o.as_ref().map_or(false, |o| o == &old) { *maybe_o = Some(new) }
));
maybe_preclaim.map(|preclaim| {
Preclaims::<T>::mutate(&preclaim, |maybe_o| {
if maybe_o.as_ref().map_or(false, |o| o == &old) {
*maybe_o = Some(new)
}
})
});
Ok(Pays::No.into())
}
}
@@ -443,19 +476,23 @@ pub mod pallet {
Call::claim(account, ethereum_signature) => {
let data = account.using_encoded(to_ascii_hex);
(Self::eth_recover(&ethereum_signature, &data, &[][..]), None)
}
},
// <weight>
// The weight of this logic is included in the `claim_attest` dispatchable.
// </weight>
Call::claim_attest(account, ethereum_signature, statement) => {
let data = account.using_encoded(to_ascii_hex);
(Self::eth_recover(&ethereum_signature, &data, &statement), Some(statement.as_slice()))
}
(
Self::eth_recover(&ethereum_signature, &data, &statement),
Some(statement.as_slice()),
)
},
_ => return Err(InvalidTransaction::Call.into()),
};
let signer = maybe_signer
.ok_or(InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()))?;
let signer = maybe_signer.ok_or(InvalidTransaction::Custom(
ValidityError::InvalidEthereumSignature.into(),
))?;
let e = InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into());
ensure!(<Claims<T>>::contains_key(&signer), e);
@@ -511,13 +548,13 @@ impl<T: Config> Pallet<T> {
fn eth_recover(s: &EcdsaSignature, what: &[u8], extra: &[u8]) -> Option<EthereumAddress> {
let msg = keccak_256(&Self::ethereum_signable_message(what, extra));
let mut res = EthereumAddress::default();
res.0.copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]);
res.0
.copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]);
Some(res)
}
fn process_claim(signer: EthereumAddress, dest: T::AccountId) -> sp_runtime::DispatchResult {
let balance_due = <Claims<T>>::get(&signer)
.ok_or(Error::<T>::SignerHasNoClaim)?;
let balance_due = <Claims<T>>::get(&signer).ok_or(Error::<T>::SignerHasNoClaim)?;
let new_total = Self::total().checked_sub(&balance_due).ok_or(Error::<T>::PotUnderflow)?;
@@ -552,11 +589,13 @@ impl<T: Config> Pallet<T> {
/// Validate `attest` calls prior to execution. Needed to avoid a DoS attack since they are
/// otherwise free to place on chain.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct PrevalidateAttests<T: Config + Send + Sync>(sp_std::marker::PhantomData<T>) where
pub struct PrevalidateAttests<T: Config + Send + Sync>(sp_std::marker::PhantomData<T>)
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>;
impl<T: Config + Send + Sync> Debug for PrevalidateAttests<T> where
<T as frame_system::Config>::Call: IsSubType<Call<T>>
impl<T: Config + Send + Sync> Debug for PrevalidateAttests<T>
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>,
{
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
@@ -569,8 +608,9 @@ impl<T: Config + Send + Sync> Debug for PrevalidateAttests<T> where
}
}
impl<T: Config + Send + Sync> PrevalidateAttests<T> where
<T as frame_system::Config>::Call: IsSubType<Call<T>>
impl<T: Config + Send + Sync> PrevalidateAttests<T>
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>,
{
/// Create new `SignedExtension` to check runtime version.
pub fn new() -> Self {
@@ -578,8 +618,9 @@ impl<T: Config + Send + Sync> PrevalidateAttests<T> where
}
}
impl<T: Config + Send + Sync> SignedExtension for PrevalidateAttests<T> where
<T as frame_system::Config>::Call: IsSubType<Call<T>>
impl<T: Config + Send + Sync> SignedExtension for PrevalidateAttests<T>
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>,
{
type AccountId = T::AccountId;
type Call = <T as frame_system::Config>::Call;
@@ -627,8 +668,15 @@ mod secp_utils {
res.0.copy_from_slice(&keccak_256(&public(secret).serialize()[1..65])[12..]);
res
}
pub fn sig<T: Config>(secret: &libsecp256k1::SecretKey, what: &[u8], extra: &[u8]) -> EcdsaSignature {
let msg = keccak_256(&<super::Pallet<T>>::ethereum_signable_message(&to_ascii_hex(what)[..], extra));
pub fn sig<T: Config>(
secret: &libsecp256k1::SecretKey,
what: &[u8],
extra: &[u8],
) -> EcdsaSignature {
let msg = keccak_256(&<super::Pallet<T>>::ethereum_signable_message(
&to_ascii_hex(what)[..],
extra,
));
let (sig, recovery_id) = libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), secret);
let mut r = [0u8; 65];
r[0..64].copy_from_slice(&sig.serialize()[..]);
@@ -639,27 +687,29 @@ mod secp_utils {
#[cfg(test)]
mod tests {
use hex_literal::hex;
use super::*;
use hex_literal::hex;
use secp_utils::*;
use sp_core::H256;
use parity_scale_codec::Encode;
use sp_core::H256;
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup, Identity},
transaction_validity::TransactionLongevity,
testing::Header,
};
use frame_support::{
assert_ok, assert_err, assert_noop, parameter_types,
ord_parameter_types, weights::{Pays, GetDispatchInfo}, traits::{ExistenceRequirement, GenesisBuild},
dispatch::DispatchError::BadOrigin,
};
use pallet_balances;
use crate::claims;
use claims::Call as ClaimsCall;
use frame_support::{
assert_err, assert_noop, assert_ok,
dispatch::DispatchError::BadOrigin,
ord_parameter_types, parameter_types,
traits::{ExistenceRequirement, GenesisBuild},
weights::{GetDispatchInfo, Pays},
};
use pallet_balances;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, Identity, IdentityLookup},
transaction_validity::TransactionLongevity,
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -734,7 +784,7 @@ mod tests {
type WeightInfo = ();
}
parameter_types!{
parameter_types! {
pub Prefix: &'static [u8] = b"Pay RUSTs to the TEST account:";
}
ord_parameter_types! {
@@ -770,8 +820,10 @@ mod tests {
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
// We use default for brevity, but you can configure as desired if needed.
pallet_balances::GenesisConfig::<Test>::default().assimilate_storage(&mut t).unwrap();
claims::GenesisConfig::<Test>{
pallet_balances::GenesisConfig::<Test>::default()
.assimilate_storage(&mut t)
.unwrap();
claims::GenesisConfig::<Test> {
claims: vec![
(eth(&alice()), 100, None, None),
(eth(&dave()), 200, None, Some(StatementKind::Regular)),
@@ -779,7 +831,9 @@ mod tests {
(eth(&frank()), 400, Some(43), None),
],
vesting: vec![(eth(&alice()), (50, 10, 1))],
}.assimilate_storage(&mut t).unwrap();
}
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
@@ -813,7 +867,11 @@ mod tests {
fn claiming_works() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&alice(), &42u64.encode(), &[][..])
));
assert_eq!(Balances::free_balance(&42), 100);
assert_eq!(Vesting::vesting_balance(&42), Some(50));
assert_eq!(Claims::total(), total_claims() - 100);
@@ -824,10 +882,20 @@ mod tests {
fn basic_claim_moving_works() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
assert_noop!(Claims::move_claim(Origin::signed(1), eth(&alice()), eth(&bob()), None), BadOrigin);
assert_noop!(
Claims::move_claim(Origin::signed(1), eth(&alice()), eth(&bob()), None),
BadOrigin
);
assert_ok!(Claims::move_claim(Origin::signed(6), eth(&alice()), eth(&bob()), None));
assert_noop!(Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])), Error::<Test>::SignerHasNoClaim);
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&bob(), &42u64.encode(), &[][..])));
assert_noop!(
Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])),
Error::<Test>::SignerHasNoClaim
);
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&bob(), &42u64.encode(), &[][..])
));
assert_eq!(Balances::free_balance(&42), 100);
assert_eq!(Vesting::vesting_balance(&42), Some(50));
assert_eq!(Claims::total(), total_claims() - 100);
@@ -839,7 +907,12 @@ mod tests {
new_test_ext().execute_with(|| {
assert_ok!(Claims::move_claim(Origin::signed(6), eth(&dave()), eth(&bob()), None));
let s = sig::<Test>(&bob(), &42u64.encode(), StatementKind::Regular.to_text());
assert_ok!(Claims::claim_attest(Origin::none(), 42, s, StatementKind::Regular.to_text().to_vec()));
assert_ok!(Claims::claim_attest(
Origin::none(),
42,
s,
StatementKind::Regular.to_text().to_vec()
));
assert_eq!(Balances::free_balance(&42), 200);
});
}
@@ -856,7 +929,11 @@ mod tests {
#[test]
fn claiming_does_not_bypass_signing() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&alice(), &42u64.encode(), &[][..])
));
assert_noop!(
Claims::claim(Origin::none(), 42, sig::<Test>(&dave(), &42u64.encode(), &[][..])),
Error::<Test>::InvalidStatement,
@@ -865,7 +942,11 @@ mod tests {
Claims::claim(Origin::none(), 42, sig::<Test>(&eve(), &42u64.encode(), &[][..])),
Error::<Test>::InvalidStatement,
);
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&frank(), &42u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&frank(), &42u64.encode(), &[][..])
));
});
}
@@ -874,21 +955,41 @@ mod tests {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
let s = sig::<Test>(&dave(), &42u64.encode(), StatementKind::Saft.to_text());
let r = Claims::claim_attest(Origin::none(), 42, s.clone(), StatementKind::Saft.to_text().to_vec());
let r = Claims::claim_attest(
Origin::none(),
42,
s.clone(),
StatementKind::Saft.to_text().to_vec(),
);
assert_noop!(r, Error::<Test>::InvalidStatement);
let r = Claims::claim_attest(Origin::none(), 42, s, StatementKind::Regular.to_text().to_vec());
let r = Claims::claim_attest(
Origin::none(),
42,
s,
StatementKind::Regular.to_text().to_vec(),
);
assert_noop!(r, Error::<Test>::SignerHasNoClaim);
// ^^^ we use ecdsa_recover, so an invalid signature just results in a random signer id
// being recovered, which realistically will never have a claim.
let s = sig::<Test>(&dave(), &42u64.encode(), StatementKind::Regular.to_text());
assert_ok!(Claims::claim_attest(Origin::none(), 42, s, StatementKind::Regular.to_text().to_vec()));
assert_ok!(Claims::claim_attest(
Origin::none(),
42,
s,
StatementKind::Regular.to_text().to_vec()
));
assert_eq!(Balances::free_balance(&42), 200);
assert_eq!(Claims::total(), total_claims() - 200);
let s = sig::<Test>(&dave(), &42u64.encode(), StatementKind::Regular.to_text());
let r = Claims::claim_attest(Origin::none(), 42, s, StatementKind::Regular.to_text().to_vec());
let r = Claims::claim_attest(
Origin::none(),
42,
s,
StatementKind::Regular.to_text().to_vec(),
);
assert_noop!(r, Error::<Test>::SignerHasNoClaim);
});
}
@@ -897,8 +998,14 @@ mod tests {
fn attesting_works() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
assert_noop!(Claims::attest(Origin::signed(69), StatementKind::Saft.to_text().to_vec()), Error::<Test>::SenderHasNoClaim);
assert_noop!(Claims::attest(Origin::signed(42), StatementKind::Regular.to_text().to_vec()), Error::<Test>::InvalidStatement);
assert_noop!(
Claims::attest(Origin::signed(69), StatementKind::Saft.to_text().to_vec()),
Error::<Test>::SenderHasNoClaim
);
assert_noop!(
Claims::attest(Origin::signed(42), StatementKind::Regular.to_text().to_vec()),
Error::<Test>::InvalidStatement
);
assert_ok!(Claims::attest(Origin::signed(42), StatementKind::Saft.to_text().to_vec()));
assert_eq!(Balances::free_balance(&42), 300);
assert_eq!(Claims::total(), total_claims() - 300);
@@ -910,7 +1017,11 @@ mod tests {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
// Alice's claim is 100
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&alice(), &42u64.encode(), &[][..])
));
assert_eq!(Balances::free_balance(&42), 100);
// Eve's claim is 300 through Account 42
assert_ok!(Claims::attest(Origin::signed(42), StatementKind::Saft.to_text().to_vec()));
@@ -970,7 +1081,11 @@ mod tests {
);
assert_ok!(Claims::mint_claim(Origin::root(), eth(&bob()), 200, None, None));
assert_eq!(Claims::total(), total_claims() + 200);
assert_ok!(Claims::claim(Origin::none(), 69, sig::<Test>(&bob(), &69u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
69,
sig::<Test>(&bob(), &69u64.encode(), &[][..])
));
assert_eq!(Balances::free_balance(&69), 200);
assert_eq!(Vesting::vesting_balance(&69), None);
assert_eq!(Claims::total(), total_claims());
@@ -989,14 +1104,29 @@ mod tests {
Claims::claim(Origin::none(), 69, sig::<Test>(&bob(), &69u64.encode(), &[][..])),
Error::<Test>::SignerHasNoClaim,
);
assert_ok!(Claims::mint_claim(Origin::root(), eth(&bob()), 200, Some((50, 10, 1)), None));
assert_ok!(Claims::claim(Origin::none(), 69, sig::<Test>(&bob(), &69u64.encode(), &[][..])));
assert_ok!(Claims::mint_claim(
Origin::root(),
eth(&bob()),
200,
Some((50, 10, 1)),
None
));
assert_ok!(Claims::claim(
Origin::none(),
69,
sig::<Test>(&bob(), &69u64.encode(), &[][..])
));
assert_eq!(Balances::free_balance(&69), 200);
assert_eq!(Vesting::vesting_balance(&69), Some(50));
// Make sure we can not transfer the vested balance.
assert_err!(
<Balances as Currency<_>>::transfer(&69, &80, 180, ExistenceRequirement::AllowDeath),
<Balances as Currency<_>>::transfer(
&69,
&80,
180,
ExistenceRequirement::AllowDeath
),
pallet_balances::Error::<Test, _>::LiquidityRestrictions,
);
});
@@ -1006,29 +1136,43 @@ mod tests {
fn add_claim_with_statement_works() {
new_test_ext().execute_with(|| {
assert_noop!(
Claims::mint_claim(Origin::signed(42), eth(&bob()), 200, None, Some(StatementKind::Regular)),
Claims::mint_claim(
Origin::signed(42),
eth(&bob()),
200,
None,
Some(StatementKind::Regular)
),
sp_runtime::traits::BadOrigin,
);
assert_eq!(Balances::free_balance(42), 0);
let signature = sig::<Test>(&bob(), &69u64.encode(), StatementKind::Regular.to_text());
assert_noop!(
Claims::claim_attest(
Origin::none(), 69, signature.clone(), StatementKind::Regular.to_text().to_vec()
Origin::none(),
69,
signature.clone(),
StatementKind::Regular.to_text().to_vec()
),
Error::<Test>::SignerHasNoClaim
);
assert_ok!(Claims::mint_claim(Origin::root(), eth(&bob()), 200, None, Some(StatementKind::Regular)));
assert_ok!(Claims::mint_claim(
Origin::root(),
eth(&bob()),
200,
None,
Some(StatementKind::Regular)
));
assert_noop!(
Claims::claim_attest(
Origin::none(), 69, signature.clone(), vec![],
),
Claims::claim_attest(Origin::none(), 69, signature.clone(), vec![],),
Error::<Test>::SignerHasNoClaim
);
assert_ok!(
Claims::claim_attest(
Origin::none(), 69, signature.clone(), StatementKind::Regular.to_text().to_vec()
)
);
assert_ok!(Claims::claim_attest(
Origin::none(),
69,
signature.clone(),
StatementKind::Regular.to_text().to_vec()
));
assert_eq!(Balances::free_balance(&69), 200);
});
}
@@ -1038,7 +1182,11 @@ mod tests {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
assert_err!(
Claims::claim(Origin::signed(42), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])),
Claims::claim(
Origin::signed(42),
42,
sig::<Test>(&alice(), &42u64.encode(), &[][..])
),
sp_runtime::traits::BadOrigin,
);
});
@@ -1048,7 +1196,11 @@ mod tests {
fn double_claiming_doesnt_work() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(42), 0);
assert_ok!(Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])));
assert_ok!(Claims::claim(
Origin::none(),
42,
sig::<Test>(&alice(), &42u64.encode(), &[][..])
));
assert_noop!(
Claims::claim(Origin::none(), 42, sig::<Test>(&alice(), &42u64.encode(), &[][..])),
Error::<Test>::SignerHasNoClaim
@@ -1060,10 +1212,21 @@ mod tests {
fn claiming_while_vested_doesnt_work() {
new_test_ext().execute_with(|| {
// A user is already vested
assert_ok!(<Test as Config>::VestingSchedule::add_vesting_schedule(&69, total_claims(), 100, 10));
assert_ok!(<Test as Config>::VestingSchedule::add_vesting_schedule(
&69,
total_claims(),
100,
10
));
CurrencyOf::<Test>::make_free_balance_be(&69, total_claims());
assert_eq!(Balances::free_balance(69), total_claims());
assert_ok!(Claims::mint_claim(Origin::root(), eth(&bob()), 200, Some((50, 10, 1)), None));
assert_ok!(Claims::mint_claim(
Origin::root(),
eth(&bob()),
200,
Some((50, 10, 1)),
None
));
// New total
assert_eq!(Claims::total(), total_claims() + 200);
@@ -1116,7 +1279,10 @@ mod tests {
new_test_ext().execute_with(|| {
assert_eq!(
<Pallet<Test>>::validate_unsigned(source, &ClaimsCall::claim(1, sig::<Test>(&alice(), &1u64.encode(), &[][..]))),
<Pallet<Test>>::validate_unsigned(
source,
&ClaimsCall::claim(1, sig::<Test>(&alice(), &1u64.encode(), &[][..]))
),
Ok(ValidTransaction {
priority: 100,
requires: vec![],
@@ -1126,11 +1292,17 @@ mod tests {
})
);
assert_eq!(
<Pallet<Test>>::validate_unsigned(source, &ClaimsCall::claim(0, EcdsaSignature([0; 65]))),
<Pallet<Test>>::validate_unsigned(
source,
&ClaimsCall::claim(0, EcdsaSignature([0; 65]))
),
InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(),
);
assert_eq!(
<Pallet<Test>>::validate_unsigned(source, &ClaimsCall::claim(1, sig::<Test>(&bob(), &1u64.encode(), &[][..]))),
<Pallet<Test>>::validate_unsigned(
source,
&ClaimsCall::claim(1, sig::<Test>(&bob(), &1u64.encode(), &[][..]))
),
InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(),
);
let s = sig::<Test>(&dave(), &1u64.encode(), StatementKind::Regular.to_text());
@@ -1148,8 +1320,11 @@ mod tests {
assert_eq!(
<Pallet<Test>>::validate_unsigned(
source,
&ClaimsCall::claim_attest(1, EcdsaSignature([0; 65]),
StatementKind::Regular.to_text().to_vec())
&ClaimsCall::claim_attest(
1,
EcdsaSignature([0; 65]),
StatementKind::Regular.to_text().to_vec()
)
),
InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(),
);
@@ -1181,12 +1356,11 @@ mod tests {
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking {
use super::*;
use secp_utils::*;
use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account};
use sp_runtime::DispatchResult;
use sp_runtime::traits::ValidateUnsigned;
use crate::claims::Call;
use frame_benchmarking::{account, benchmarks};
use frame_system::RawOrigin;
use secp_utils::*;
use sp_runtime::{traits::ValidateUnsigned, DispatchResult};
const SEED: u32 = 0;
@@ -1197,7 +1371,13 @@ mod benchmarking {
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap();
let eth_address = eth(&secret_key);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
super::Pallet::<T>::mint_claim(RawOrigin::Root.into(), eth_address, VALUE.into(), vesting, None)?;
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
None,
)?;
Ok(())
}
@@ -1210,7 +1390,7 @@ mod benchmarking {
eth_address,
VALUE.into(),
vesting,
Some(Default::default())
Some(Default::default()),
)?;
Ok(())
}
+341 -162
View File
@@ -49,33 +49,35 @@
//! the parachain remains active. Users can withdraw their funds once the slot is completed and funds are
//! returned to the crowdloan account.
use crate::{
slot_range::SlotRange,
traits::{Auctioneer, Registrar},
};
use frame_support::{
ensure, Identity, PalletId,
storage::{child, ChildTriePrefixIterator},
traits::{
Currency, ReservableCurrency, Get, ExistenceRequirement::AllowDeath
},
ensure,
pallet_prelude::Weight,
storage::{child, ChildTriePrefixIterator},
traits::{Currency, ExistenceRequirement::AllowDeath, Get, ReservableCurrency},
Identity, PalletId,
};
use sp_runtime::{
RuntimeDebug, MultiSignature, MultiSigner,
traits::{
AccountIdConversion, Hash, Saturating, Zero, One, CheckedAdd, Verify, IdentifyAccount,
},
};
use crate::traits::{Registrar, Auctioneer};
use crate::slot_range::SlotRange;
use parity_scale_codec::{Encode, Decode};
use sp_std::vec::Vec;
use primitives::v1::Id as ParaId;
pub use pallet::*;
use parity_scale_codec::{Decode, Encode};
use primitives::v1::Id as ParaId;
use sp_runtime::{
traits::{
AccountIdConversion, CheckedAdd, Hash, IdentifyAccount, One, Saturating, Verify, Zero,
},
MultiSignature, MultiSigner, RuntimeDebug,
};
use sp_std::vec::Vec;
type CurrencyOf<T> = <<T as Config>::Auctioneer as Auctioneer>::Currency;
type LeasePeriodOf<T> = <<T as Config>::Auctioneer as Auctioneer>::LeasePeriod;
type BalanceOf<T> = <CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
#[allow(dead_code)]
type NegativeImbalanceOf<T> = <CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance;
type NegativeImbalanceOf<T> =
<CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance;
type TrieIndex = u32;
@@ -83,25 +85,43 @@ pub trait WeightInfo {
fn create() -> Weight;
fn contribute() -> Weight;
fn withdraw() -> Weight;
fn refund(k: u32, ) -> Weight;
fn refund(k: u32) -> Weight;
fn dissolve() -> Weight;
fn edit() -> Weight;
fn add_memo() -> Weight;
fn on_initialize(n: u32, ) -> Weight;
fn on_initialize(n: u32) -> Weight;
fn poke() -> Weight;
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn create() -> Weight { 0 }
fn contribute() -> Weight { 0 }
fn withdraw() -> Weight { 0 }
fn refund(_k: u32, ) -> Weight { 0 }
fn dissolve() -> Weight { 0 }
fn edit() -> Weight { 0 }
fn add_memo() -> Weight { 0 }
fn on_initialize(_n: u32, ) -> Weight { 0 }
fn poke() -> Weight { 0 }
fn create() -> Weight {
0
}
fn contribute() -> Weight {
0
}
fn withdraw() -> Weight {
0
}
fn refund(_k: u32) -> Weight {
0
}
fn dissolve() -> Weight {
0
}
fn edit() -> Weight {
0
}
fn add_memo() -> Weight {
0
}
fn on_initialize(_n: u32) -> Weight {
0
}
fn poke() -> Weight {
0
}
}
#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)]
@@ -148,9 +168,9 @@ pub struct FundInfo<AccountId, Balance, BlockNumber, LeasePeriod> {
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::{pallet_prelude::*, ensure_signed, ensure_root};
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::{ensure_root, ensure_signed, pallet_prelude::*};
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
@@ -178,13 +198,13 @@ pub mod pallet {
/// The parachain registrar type. We just use this to ensure that only the manager of a para is able to
/// start a crowdloan for its slot.
type Registrar: Registrar<AccountId=Self::AccountId>;
type Registrar: Registrar<AccountId = Self::AccountId>;
/// The type representing the auctioning system.
type Auctioneer: Auctioneer<
AccountId=Self::AccountId,
BlockNumber=Self::BlockNumber,
LeasePeriod=Self::BlockNumber,
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
LeasePeriod = Self::BlockNumber,
>;
/// The maximum length for the memo attached to a crowdloan contribution.
@@ -199,7 +219,8 @@ pub mod pallet {
#[pallet::getter(fn funds)]
pub(super) type Funds<T: Config> = StorageMap<
_,
Twox64Concat, ParaId,
Twox64Concat,
ParaId,
FundInfo<T::AccountId, BalanceOf<T>, T::BlockNumber, LeasePeriodOf<T>>,
>;
@@ -305,7 +326,9 @@ pub mod pallet {
}
let new_raise = NewRaise::<T>::take();
let new_raise_len = new_raise.len() as u32;
for (fund, para_id) in new_raise.into_iter().filter_map(|i| Self::funds(i).map(|f| (f, i))) {
for (fund, para_id) in
new_raise.into_iter().filter_map(|i| Self::funds(i).map(|f| (f, i)))
{
// Care needs to be taken by the crowdloan creator that this function will succeed given
// the crowdloaning configuration. We do some checks ahead of time in crowdloan `create`.
let result = T::Auctioneer::place_bid(
@@ -349,9 +372,13 @@ pub mod pallet {
.ok_or(Error::<T>::FirstPeriodTooFarInFuture)?;
ensure!(last_period <= last_period_limit, Error::<T>::LastPeriodTooFarInFuture);
ensure!(end > <frame_system::Pallet<T>>::block_number(), Error::<T>::CannotEndInPast);
let last_possible_win_date = (first_period.saturating_add(One::one())).saturating_mul(T::Auctioneer::lease_period());
let last_possible_win_date = (first_period.saturating_add(One::one()))
.saturating_mul(T::Auctioneer::lease_period());
ensure!(end <= last_possible_win_date, Error::<T>::EndTooFarInFuture);
ensure!(first_period >= T::Auctioneer::lease_period_index(), Error::<T>::FirstPeriodInPast);
ensure!(
first_period >= T::Auctioneer::lease_period_index(),
Error::<T>::FirstPeriodInPast
);
// There should not be an existing fund.
ensure!(!Funds::<T>::contains_key(index), Error::<T>::FundNotEnded);
@@ -367,18 +394,21 @@ pub mod pallet {
CurrencyOf::<T>::reserve(&depositor, deposit)?;
Funds::<T>::insert(index, FundInfo {
depositor,
verifier,
deposit,
raised: Zero::zero(),
end,
cap,
last_contribution: LastContribution::Never,
first_period,
last_period,
trie_index,
});
Funds::<T>::insert(
index,
FundInfo {
depositor,
verifier,
deposit,
raised: Zero::zero(),
end,
cap,
last_contribution: LastContribution::Never,
first_period,
last_period,
trie_index,
},
);
NextTrieIndex::<T>::put(new_trie_index);
// Add a lock to the para so that the configuration cannot be changed.
@@ -401,7 +431,7 @@ pub mod pallet {
ensure!(value >= T::MinContribution::get(), Error::<T>::ContributionTooSmall);
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidParaId)?;
fund.raised = fund.raised.checked_add(&value).ok_or(Error::<T>::Overflow)?;
fund.raised = fund.raised.checked_add(&value).ok_or(Error::<T>::Overflow)?;
ensure!(fund.raised <= fund.cap, Error::<T>::CapExceeded);
// Make sure crowdloan has not ended
@@ -414,7 +444,10 @@ pub mod pallet {
// Make sure crowdloan has not already won.
let fund_account = Self::fund_account_id(index);
ensure!(!T::Auctioneer::has_won_an_auction(index, &fund_account), Error::<T>::BidOrLeaseActive);
ensure!(
!T::Auctioneer::has_won_an_auction(index, &fund_account),
Error::<T>::BidOrLeaseActive
);
// We disallow any crowdloan contributions during the VRF Period, so that people do not sneak their
// contributions into the auction when it would not impact the outcome.
@@ -425,7 +458,9 @@ pub mod pallet {
if let Some(ref verifier) = fund.verifier {
let signature = signature.ok_or(Error::<T>::InvalidSignature)?;
let payload = (index, &who, old_balance, value);
let valid = payload.using_encoded(|encoded| signature.verify(encoded, &verifier.clone().into_account()));
let valid = payload.using_encoded(|encoded| {
signature.verify(encoded, &verifier.clone().into_account())
});
ensure!(valid, Error::<T>::InvalidSignature);
}
@@ -439,11 +474,11 @@ pub mod pallet {
// In ending period; must ensure that we are in NewRaise.
LastContribution::Ending(n) if n == now => {
// do nothing - already in NewRaise
}
},
_ => {
NewRaise::<T>::append(index);
fund.last_contribution = LastContribution::Ending(now);
}
},
}
} else {
let endings_count = Self::endings_count();
@@ -452,13 +487,13 @@ pub mod pallet {
// Not in ending period and no auctions have ended ending since our
// previous bid which was also not in an ending period.
// `NewRaise` will contain our ID still: Do nothing.
}
},
_ => {
// Not in ending period; but an auction has been ending since our previous
// bid, or we never had one to begin with. Add bid.
NewRaise::<T>::append(index);
fund.last_contribution = LastContribution::PreEnding(endings_count);
}
},
}
}
@@ -538,7 +573,7 @@ pub mod pallet {
if refund_count >= T::RemoveKeysLimit::get() {
// Not everyone was able to be refunded this time around.
all_refunded = false;
break;
break
}
CurrencyOf::<T>::transfer(&fund_account, &who, balance, AllowDeath)?;
Self::contribution_kill(fund.trie_index, &who);
@@ -602,18 +637,21 @@ pub mod pallet {
let fund = Self::funds(index).ok_or(Error::<T>::InvalidParaId)?;
Funds::<T>::insert(index, FundInfo {
depositor: fund.depositor,
verifier,
deposit: fund.deposit,
raised: fund.raised,
end,
cap,
last_contribution: fund.last_contribution,
first_period,
last_period,
trie_index: fund.trie_index,
});
Funds::<T>::insert(
index,
FundInfo {
depositor: fund.depositor,
verifier,
deposit: fund.deposit,
raised: fund.raised,
end,
cap,
last_contribution: fund.last_contribution,
first_period,
last_period,
trie_index: fund.trie_index,
},
);
Self::deposit_event(Event::<T>::Edited(index));
Ok(())
@@ -669,15 +707,19 @@ impl<T: Config> Pallet<T> {
child::ChildInfo::new_default(T::Hashing::hash(&buf[..]).as_ref())
}
pub fn contribution_put(index: TrieIndex, who: &T::AccountId, balance: &BalanceOf<T>, memo: &[u8]) {
pub fn contribution_put(
index: TrieIndex,
who: &T::AccountId,
balance: &BalanceOf<T>,
memo: &[u8],
) {
who.using_encoded(|b| child::put(&Self::id_from_index(index), b, &(balance, memo)));
}
pub fn contribution_get(index: TrieIndex, who: &T::AccountId) -> (BalanceOf<T>, Vec<u8>) {
who.using_encoded(|b| child::get_or_default::<(BalanceOf<T>, Vec<u8>)>(
&Self::id_from_index(index),
b,
))
who.using_encoded(|b| {
child::get_or_default::<(BalanceOf<T>, Vec<u8>)>(&Self::id_from_index(index), b)
})
}
pub fn contribution_kill(index: TrieIndex, who: &T::AccountId) {
@@ -689,9 +731,12 @@ impl<T: Config> Pallet<T> {
}
pub fn contribution_iterator(
index: TrieIndex
index: TrieIndex,
) -> ChildTriePrefixIterator<(T::AccountId, (BalanceOf<T>, Vec<u8>))> {
ChildTriePrefixIterator::<_>::with_prefix_over_key::<Identity>(&Self::id_from_index(index), &[])
ChildTriePrefixIterator::<_>::with_prefix_over_key::<Identity>(
&Self::id_from_index(index),
&[],
)
}
/// This function checks all conditions which would qualify a crowdloan has ended.
@@ -701,40 +746,39 @@ impl<T: Config> Pallet<T> {
fn ensure_crowdloan_ended(
now: T::BlockNumber,
fund_account: &T::AccountId,
fund: &FundInfo<T::AccountId, BalanceOf<T>, T::BlockNumber, LeasePeriodOf<T>>
fund: &FundInfo<T::AccountId, BalanceOf<T>, T::BlockNumber, LeasePeriodOf<T>>,
) -> sp_runtime::DispatchResult {
// `fund.end` can represent the end of a failed crowdloan or the beginning of retirement
// If the current lease period is past the first period they are trying to bid for, then
// it is already too late to win the bid.
let current_lease_period = T::Auctioneer::lease_period_index();
ensure!(now >= fund.end || current_lease_period > fund.first_period, Error::<T>::FundNotEnded);
// free balance must greater than or equal amount raised, otherwise funds are being used
// and a bid or lease must be active.
ensure!(CurrencyOf::<T>::free_balance(&fund_account) >= fund.raised, Error::<T>::BidOrLeaseActive);
// `fund.end` can represent the end of a failed crowdloan or the beginning of retirement
// If the current lease period is past the first period they are trying to bid for, then
// it is already too late to win the bid.
let current_lease_period = T::Auctioneer::lease_period_index();
ensure!(
now >= fund.end || current_lease_period > fund.first_period,
Error::<T>::FundNotEnded
);
// free balance must greater than or equal amount raised, otherwise funds are being used
// and a bid or lease must be active.
ensure!(
CurrencyOf::<T>::free_balance(&fund_account) >= fund.raised,
Error::<T>::BidOrLeaseActive
);
Ok(())
Ok(())
}
}
impl<T: Config> crate::traits::OnSwap for Pallet<T> {
fn on_swap(one: ParaId, other: ParaId) {
Funds::<T>::mutate(one, |x|
Funds::<T>::mutate(other, |y|
sp_std::mem::swap(x, y)
)
)
Funds::<T>::mutate(one, |x| Funds::<T>::mutate(other, |y| sp_std::mem::swap(x, y)))
}
}
#[cfg(any(feature = "runtime-benchmarks", test))]
mod crypto {
use sp_core::ed25519;
use sp_io::crypto::{ed25519_sign, ed25519_generate};
use sp_std::{
vec::Vec,
convert::TryFrom,
};
use sp_runtime::{MultiSigner, MultiSignature};
use sp_io::crypto::{ed25519_generate, ed25519_sign};
use sp_runtime::{MultiSignature, MultiSigner};
use sp_std::{convert::TryFrom, vec::Vec};
pub fn create_ed25519_pubkey(seed: Vec<u8>) -> MultiSigner {
ed25519_generate(0.into(), Some(seed)).into()
@@ -751,24 +795,26 @@ mod crypto {
mod tests {
use super::*;
use std::{cell::RefCell, sync::Arc, collections::BTreeMap};
use frame_support::{
assert_ok, assert_noop, parameter_types,
traits::{OnInitialize, OnFinalize},
assert_noop, assert_ok, parameter_types,
traits::{OnFinalize, OnInitialize},
};
use sp_core::H256;
use primitives::v1::Id as ParaId;
use sp_core::H256;
use std::{cell::RefCell, collections::BTreeMap, sync::Arc};
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
use sp_runtime::{
testing::Header, traits::{BlakeTwo256, IdentityLookup}, DispatchResult,
};
use crate::{
mock::TestRegistrar,
traits::{OnSwap, AuctionStatus},
crowdloan,
mock::TestRegistrar,
traits::{AuctionStatus, OnSwap},
};
use sp_keystore::{testing::KeyStore, KeystoreExt};
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
DispatchResult,
};
use sp_keystore::{KeystoreExt, testing::KeyStore};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -840,7 +886,7 @@ mod tests {
para: ParaId,
first_period: u64,
last_period: u64,
amount: u64
amount: u64,
}
thread_local! {
static AUCTION: RefCell<Option<(u64, u64)>> = RefCell::new(None);
@@ -875,7 +921,8 @@ mod tests {
let account_id = Crowdloan::fund_account_id(para);
if winner {
let free_balance = Balances::free_balance(&account_id);
Balances::reserve(&account_id, free_balance).expect("should be able to reserve free balance");
Balances::reserve(&account_id, free_balance)
.expect("should be able to reserve free balance");
} else {
let reserved_balance = Balances::reserved_balance(&account_id);
Balances::unreserve(&account_id, reserved_balance);
@@ -915,10 +962,10 @@ mod tests {
let after_end = after_early_end - ending_period;
// Optional VRF delay
if after_end < vrf_delay() {
return AuctionStatus::VrfDelay(after_end);
return AuctionStatus::VrfDelay(after_end)
} else {
// VRF delay is done, so we just end the auction
return AuctionStatus::NotStarted;
return AuctionStatus::NotStarted
}
}
}
@@ -928,10 +975,19 @@ mod tests {
para: ParaId,
first_period: u64,
last_period: u64,
amount: u64
amount: u64,
) -> DispatchResult {
let height = System::block_number();
BIDS_PLACED.with(|p| p.borrow_mut().push(BidPlaced { height, bidder, para, first_period, last_period, amount }));
BIDS_PLACED.with(|p| {
p.borrow_mut().push(BidPlaced {
height,
bidder,
para,
first_period,
last_period,
amount,
})
});
Ok(())
}
@@ -974,9 +1030,11 @@ mod tests {
// our desired mockup.
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test>{
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 1000), (2, 2000), (3, 3000), (4, 4000)],
}.assimilate_storage(&mut t).unwrap();
}
.assimilate_storage(&mut t)
.unwrap();
let keystore = KeyStore::new();
let mut t: sp_io::TestExternalities = t.into();
t.register_extension(KeystoreExt(Arc::new(keystore)));
@@ -986,9 +1044,16 @@ mod tests {
fn new_para() -> ParaId {
for i in 0.. {
let para: ParaId = i.into();
if TestRegistrar::<Test>::is_registered(para) { continue }
assert_ok!(TestRegistrar::<Test>::register(1, para, Default::default(), Default::default()));
return para;
if TestRegistrar::<Test>::is_registered(para) {
continue
}
assert_ok!(TestRegistrar::<Test>::register(
1,
para,
Default::default(),
Default::default()
));
return para
}
unreachable!()
}
@@ -1023,7 +1088,14 @@ mod tests {
assert_eq!(bids(), vec![]);
assert_ok!(TestAuctioneer::place_bid(1, 2.into(), 0, 3, 6));
let b = BidPlaced { height: 0, bidder: 1, para: 2.into(), first_period: 0, last_period: 3, amount: 6 };
let b = BidPlaced {
height: 0,
bidder: 1,
para: 2.into(),
first_period: 0,
last_period: 3,
amount: 6,
};
assert_eq!(bids(), vec![b]);
assert_eq!(TestAuctioneer::auction_status(4), AuctionStatus::<u64>::StartingPeriod);
assert_eq!(TestAuctioneer::auction_status(5), AuctionStatus::<u64>::EndingPeriod(0, 0));
@@ -1069,7 +1141,15 @@ mod tests {
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
let para = new_para();
// Now try to create a crowdloan campaign
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, Some(pubkey.clone())));
assert_ok!(Crowdloan::create(
Origin::signed(1),
para,
1000,
1,
4,
9,
Some(pubkey.clone())
));
// This is what the initial `fund_info` should look like
let fund_info = FundInfo {
depositor: 1,
@@ -1110,13 +1190,24 @@ mod tests {
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 9, 9, None), e);
// Cannot create a crowdloan without some deposit funds
assert_ok!(TestRegistrar::<Test>::register(1337, ParaId::from(1234), Default::default(), Default::default()));
assert_ok!(TestRegistrar::<Test>::register(
1337,
ParaId::from(1234),
Default::default(),
Default::default()
));
let e = BalancesError::<Test, _>::InsufficientBalance;
assert_noop!(Crowdloan::create(Origin::signed(1337), ParaId::from(1234), 1000, 1, 3, 9, None), e);
assert_noop!(
Crowdloan::create(Origin::signed(1337), ParaId::from(1234), 1000, 1, 3, 9, None),
e
);
// Cannot create a crowdloan with nonsense end date
// This crowdloan would end in lease period 2, but is bidding for some slot that starts in lease period 1.
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 41, None), Error::<Test>::EndTooFarInFuture);
assert_noop!(
Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 41, None),
Error::<Test>::EndTooFarInFuture
);
});
}
@@ -1156,30 +1247,59 @@ mod tests {
let para = new_para();
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
// Set up a crowdloan
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, Some(pubkey.clone())));
assert_ok!(Crowdloan::create(
Origin::signed(1),
para,
1000,
1,
4,
9,
Some(pubkey.clone())
));
// No contributions yet
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 0);
// Missing signature
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::InvalidSignature);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 49, None),
Error::<Test>::InvalidSignature
);
let payload = (0u32, 1u64, 0u64, 49u64);
let valid_signature = crypto::create_ed25519_signature(&payload.encode(), pubkey.clone());
let valid_signature =
crypto::create_ed25519_signature(&payload.encode(), pubkey.clone());
let invalid_signature = MultiSignature::default();
// Invalid signature
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(invalid_signature)), Error::<Test>::InvalidSignature);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 49, Some(invalid_signature)),
Error::<Test>::InvalidSignature
);
// Valid signature wrong parameter
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 50, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
assert_noop!(Crowdloan::contribute(Origin::signed(2), para, 49, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 50, Some(valid_signature.clone())),
Error::<Test>::InvalidSignature
);
assert_noop!(
Crowdloan::contribute(Origin::signed(2), para, 49, Some(valid_signature.clone())),
Error::<Test>::InvalidSignature
);
// Valid signature
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(valid_signature.clone())));
assert_ok!(Crowdloan::contribute(
Origin::signed(1),
para,
49,
Some(valid_signature.clone())
));
// Reuse valid signature
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(valid_signature)), Error::<Test>::InvalidSignature);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 49, Some(valid_signature)),
Error::<Test>::InvalidSignature
);
let payload_2 = (0u32, 1u64, 49u64, 10u64);
let valid_signature_2 = crypto::create_ed25519_signature(&payload_2.encode(), pubkey);
@@ -1202,22 +1322,34 @@ mod tests {
let para = new_para();
// Cannot contribute to non-existing fund
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::InvalidParaId);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 49, None),
Error::<Test>::InvalidParaId
);
// Cannot contribute below minimum contribution
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 9, None), Error::<Test>::ContributionTooSmall);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 9, None),
Error::<Test>::ContributionTooSmall
);
// Set up a crowdloan
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 101, None));
// Cannot contribute past the limit
assert_noop!(Crowdloan::contribute(Origin::signed(2), para, 900, None), Error::<Test>::CapExceeded);
assert_noop!(
Crowdloan::contribute(Origin::signed(2), para, 900, None),
Error::<Test>::CapExceeded
);
// Move past end date
run_to_block(10);
// Cannot contribute to ended fund
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::ContributionPeriodOver);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para, 49, None),
Error::<Test>::ContributionPeriodOver
);
// If a crowdloan has already won, it should not allow contributions.
let para_2 = new_para();
@@ -1225,7 +1357,10 @@ mod tests {
// Emulate a win by leasing out and putting a deposit. Slots pallet would normally do this.
let crowdloan_account = Crowdloan::fund_account_id(para_2);
set_winner(para_2, crowdloan_account, true);
assert_noop!(Crowdloan::contribute(Origin::signed(1), para_2, 49, None), Error::<Test>::BidOrLeaseActive);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para_2, 49, None),
Error::<Test>::BidOrLeaseActive
);
// Move past lease period 1, should not be allowed to have further contributions with a crowdloan
// that has starting period 1.
@@ -1233,7 +1368,10 @@ mod tests {
assert_ok!(Crowdloan::create(Origin::signed(1), para_3, 1000, 1, 4, 40, None));
run_to_block(40);
assert_eq!(TestAuctioneer::lease_period_index(), 2);
assert_noop!(Crowdloan::contribute(Origin::signed(1), para_3, 49, None), Error::<Test>::ContributionPeriodOver);
assert_noop!(
Crowdloan::contribute(Origin::signed(1), para_3, 49, None),
Error::<Test>::ContributionPeriodOver
);
});
}
@@ -1249,7 +1387,15 @@ mod tests {
assert_ok!(TestAuctioneer::new_auction(5, 0));
// Set up a crowdloan
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, first_period, last_period, 20, None));
assert_ok!(Crowdloan::create(
Origin::signed(1),
para,
1000,
first_period,
last_period,
20,
None
));
run_to_block(8);
// Can def contribute when auction is running.
@@ -1259,7 +1405,10 @@ mod tests {
run_to_block(10);
// Can't contribute when auction is in the VRF delay period.
assert!(TestAuctioneer::auction_status(System::block_number()).is_vrf());
assert_noop!(Crowdloan::contribute(Origin::signed(2), para, 250, None), Error::<Test>::VrfDelayInProgress);
assert_noop!(
Crowdloan::contribute(Origin::signed(2), para, 250, None),
Error::<Test>::VrfDelayInProgress
);
run_to_block(15);
// Its fine to contribute when no auction is running.
@@ -1278,7 +1427,15 @@ mod tests {
assert_ok!(TestAuctioneer::new_auction(5, 0));
// Set up a crowdloan
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, first_period, last_period, 9, None));
assert_ok!(Crowdloan::create(
Origin::signed(1),
para,
1000,
first_period,
last_period,
9,
None
));
let bidder = Crowdloan::fund_account_id(para);
// Fund crowdloan
@@ -1292,11 +1449,14 @@ mod tests {
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 250, None));
run_to_block(10);
assert_eq!(bids(), vec![
BidPlaced { height: 5, amount: 250, bidder, para, first_period, last_period },
BidPlaced { height: 6, amount: 450, bidder, para, first_period, last_period },
BidPlaced { height: 9, amount: 700, bidder, para, first_period, last_period },
]);
assert_eq!(
bids(),
vec![
BidPlaced { height: 5, amount: 250, bidder, para, first_period, last_period },
BidPlaced { height: 6, amount: 450, bidder, para, first_period, last_period },
BidPlaced { height: 9, amount: 700, bidder, para, first_period, last_period },
]
);
// Endings count incremented
assert_eq!(Crowdloan::endings_count(), 1);
@@ -1405,9 +1565,14 @@ mod tests {
// Set up a crowdloan ending on 9
assert_ok!(Crowdloan::create(Origin::signed(1), para, 100000, 1, 1, 9, None));
// Make more contributions than our limit
for i in 1 ..= RemoveKeysLimit::get() * 2 {
for i in 1..=RemoveKeysLimit::get() * 2 {
Balances::make_free_balance_be(&i.into(), (1000 * i).into());
assert_ok!(Crowdloan::contribute(Origin::signed(i.into()), para, (i * 100).into(), None));
assert_ok!(Crowdloan::contribute(
Origin::signed(i.into()),
para,
(i * 100).into(),
None
));
}
assert_eq!(Balances::free_balance(account_id), 21000);
@@ -1427,7 +1592,7 @@ mod tests {
// Funds are returned
assert_eq!(Balances::free_balance(account_id), 0);
// 1 deposit for the crowdloan which hasn't dissolved yet.
for i in 1 ..= RemoveKeysLimit::get() * 2 {
for i in 1..=RemoveKeysLimit::get() * 2 {
assert_eq!(Balances::free_balance(&i.into()), i as u64 * 1000);
}
});
@@ -1469,16 +1634,25 @@ mod tests {
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None));
// Can't dissolve before it ends
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
assert_noop!(
Crowdloan::dissolve(Origin::signed(1), para),
Error::<Test>::NotReadyToDissolve
);
run_to_block(10);
set_winner(para, 1, true);
// Can't dissolve when it won.
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
assert_noop!(
Crowdloan::dissolve(Origin::signed(1), para),
Error::<Test>::NotReadyToDissolve
);
set_winner(para, 1, false);
// Can't dissolve while it still has user funds
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
assert_noop!(
Crowdloan::dissolve(Origin::signed(1), para),
Error::<Test>::NotReadyToDissolve
);
// All funds are refunded
assert_ok!(Crowdloan::refund(Origin::signed(2), para));
@@ -1508,7 +1682,10 @@ mod tests {
assert_ok!(Balances::reserve(&account_id, 150));
run_to_block(19);
assert_noop!(Crowdloan::withdraw(Origin::signed(2), 2, para), Error::<Test>::BidOrLeaseActive);
assert_noop!(
Crowdloan::withdraw(Origin::signed(2), 2, para),
Error::<Test>::BidOrLeaseActive
);
run_to_block(20);
// simulate the unreserving of para's funds, now that the lease expired. this actually
@@ -1566,7 +1743,6 @@ mod tests {
Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None),
Error::<Test>::FundNotEnded,
);
});
}
@@ -1648,16 +1824,13 @@ mod tests {
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking {
use super::{*, Pallet as Crowdloan};
use super::{Pallet as Crowdloan, *};
use frame_support::{assert_ok, traits::OnInitialize};
use frame_system::RawOrigin;
use frame_support::{
assert_ok,
traits::OnInitialize,
};
use sp_runtime::traits::{Bounded, CheckedSub};
use sp_std::prelude::*;
use frame_benchmarking::{benchmarks, whitelisted_caller, account, impl_benchmark_test_suite};
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
let events = frame_system::Pallet::<T>::events();
@@ -1671,7 +1844,8 @@ mod benchmarking {
let cap = BalanceOf::<T>::max_value();
let lease_period_index = T::Auctioneer::lease_period_index();
let first_period = lease_period_index;
let last_period = lease_period_index + ((SlotRange::LEASE_PERIODS_PER_SLOT as u32) - 1).into();
let last_period =
lease_period_index + ((SlotRange::LEASE_PERIODS_PER_SLOT as u32) - 1).into();
let para_id = id.into();
let caller = account("fund_creator", id, 0);
@@ -1706,7 +1880,12 @@ mod benchmarking {
let payload = (index, &who, BalanceOf::<T>::default(), value);
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey);
assert_ok!(Crowdloan::<T>::contribute(RawOrigin::Signed(who.clone()).into(), index, value, Some(sig)));
assert_ok!(Crowdloan::<T>::contribute(
RawOrigin::Signed(who.clone()).into(),
index,
value,
Some(sig)
));
}
benchmarks! {
+1 -1
View File
@@ -16,12 +16,12 @@
//! Code for elections.
use super::{BlockExecutionWeight, BlockLength, BlockWeights};
use frame_support::{
parameter_types,
weights::{DispatchClass, Weight},
};
use sp_runtime::Perbill;
use super::{BlockExecutionWeight, BlockLength, BlockWeights};
parameter_types! {
/// A limit for off-chain phragmen unsigned solution submission.
+17 -10
View File
@@ -16,8 +16,8 @@
//! Auxiliary `struct`/`enum`s for polkadot runtime.
use frame_support::traits::{OnUnbalanced, Imbalance, Currency};
use crate::NegativeImbalance;
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
/// Logic for the author to get a portion of fees.
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
@@ -31,8 +31,14 @@ where
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
let numeric_amount = amount.peek();
let author = <pallet_authorship::Pallet<R>>::author();
<pallet_balances::Pallet<R>>::resolve_creating(&<pallet_authorship::Pallet<R>>::author(), amount);
<frame_system::Pallet<R>>::deposit_event(pallet_balances::Event::Deposit(author, numeric_amount));
<pallet_balances::Pallet<R>>::resolve_creating(
&<pallet_authorship::Pallet<R>>::author(),
amount,
);
<frame_system::Pallet<R>>::deposit_event(pallet_balances::Event::Deposit(
author,
numeric_amount,
));
}
}
@@ -45,7 +51,7 @@ where
<R as frame_system::Config>::AccountId: Into<primitives::v1::AccountId>,
<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
{
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance<R>>) {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
if let Some(fees) = fees_then_tips.next() {
// for fees, 80% to treasury, 20% to author
let mut split = fees.ration(80, 20);
@@ -60,20 +66,18 @@ where
}
}
#[cfg(test)]
mod tests {
use super::*;
use frame_support::{parameter_types, traits::FindAuthor, weights::DispatchClass, PalletId};
use frame_system::limits;
use frame_support::{parameter_types, PalletId, weights::DispatchClass};
use frame_support::traits::FindAuthor;
use primitives::v1::AccountId;
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
Perbill,
};
use primitives::v1::AccountId;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -169,7 +173,8 @@ mod tests {
pub struct OneAuthor;
impl FindAuthor<AccountId> for OneAuthor {
fn find_author<'a, I>(_: I) -> Option<AccountId>
where I: 'a,
where
I: 'a,
{
Some(Default::default())
}
@@ -184,7 +189,9 @@ mod tests {
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
// We use default for brevity, but you can configure as desired if needed.
pallet_balances::GenesisConfig::<Test>::default().assimilate_storage(&mut t).unwrap();
pallet_balances::GenesisConfig::<Test>::default()
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
+219 -155
View File
@@ -16,33 +16,28 @@
//! Mocking utilities for testing with real pallets.
use sp_std::sync::Arc;
use sp_io::TestExternalities;
use sp_core::{H256, crypto::KeyTypeId};
use sp_runtime::{
traits::{
BlakeTwo256, IdentityLookup, One,
},
use crate::{
auctions, crowdloan, paras_registrar,
slot_range::SlotRange,
slots,
traits::{AuctionStatus, Auctioneer, Registrar as RegistrarT},
};
use sp_keystore::{KeystoreExt, testing::KeyStore};
use primitives::v1::{BlockNumber, Header, Id as ParaId, ValidationCode, HeadData, LOWEST_PUBLIC_ID};
use frame_support::{
parameter_types, assert_ok, assert_noop, PalletId,
traits::{Currency, OnInitialize, OnFinalize, KeyOwnerProofSystem, GenesisBuild},
};
use frame_system::EnsureRoot;
use runtime_parachains::{
ParaLifecycle, Origin as ParaOrigin,
paras, configuration, shared,
assert_noop, assert_ok, parameter_types,
traits::{Currency, GenesisBuild, KeyOwnerProofSystem, OnFinalize, OnInitialize},
PalletId,
};
use frame_support_test::TestRandomness;
use crate::{
auctions, crowdloan, slots, paras_registrar,
slot_range::SlotRange,
traits::{
Registrar as RegistrarT, Auctioneer, AuctionStatus,
},
use frame_system::EnsureRoot;
use primitives::v1::{
BlockNumber, HeadData, Header, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID,
};
use runtime_parachains::{configuration, paras, shared, Origin as ParaOrigin, ParaLifecycle};
use sp_core::{crypto::KeyTypeId, H256};
use sp_io::TestExternalities;
use sp_keystore::{testing::KeyStore, KeystoreExt};
use sp_runtime::traits::{BlakeTwo256, IdentityLookup, One};
use sp_std::sync::Arc;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -75,8 +70,7 @@ frame_support::construct_runtime!(
}
);
use crate::crowdloan::Error as CrowdloanError;
use crate::auctions::Error as AuctionsError;
use crate::{auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError};
parameter_types! {
pub const BlockHashCount: u32 = 250;
@@ -121,8 +115,10 @@ impl pallet_babe::Config for Test {
type ExpectedBlockTime = ExpectedBlockTime;
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
type KeyOwnerProofSystem = ();
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, pallet_babe::AuthorityId)>>::Proof;
type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
@@ -159,9 +155,9 @@ impl pallet_balances::Config for Test {
type ReserveIdentifier = [u8; 8];
}
impl configuration::Config for Test { }
impl configuration::Config for Test {}
impl shared::Config for Test { }
impl shared::Config for Test {}
impl paras::Config for Test {
type Origin = Origin;
@@ -236,14 +232,15 @@ pub fn new_test_ext() -> TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
GenesisBuild::<Test>::assimilate_storage(
&configuration::GenesisConfig {
config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB
max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default()
}
config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB
max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default()
},
&mut t
).unwrap();
},
&mut t,
)
.unwrap();
let keystore = KeyStore::new();
let mut ext: sp_io::TestExternalities = t.into();
ext.register_extension(KeystoreExt(Arc::new(keystore)));
@@ -255,9 +252,7 @@ const BLOCKS_PER_SESSION: u32 = 10;
fn maybe_new_session(n: u32) {
if n % BLOCKS_PER_SESSION == 0 {
shared::Pallet::<Test>::set_session_index(
shared::Pallet::<Test>::session_index() + 1
);
shared::Pallet::<Test>::set_session_index(shared::Pallet::<Test>::session_index() + 1);
Paras::test_on_new_session();
}
}
@@ -343,10 +338,10 @@ fn basic_end_to_end_works() {
assert_ok!(Crowdloan::create(
Origin::signed(2),
ParaId::from(para_2),
1_000, // Cap
1_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
200, // Block End
None,
));
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(para_2));
@@ -361,10 +356,10 @@ fn basic_end_to_end_works() {
assert_ok!(Auctions::bid(
Origin::signed(10),
ParaId::from(para_1),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
910, // Amount
910, // Amount
));
// User 2 will be a contribute to crowdloan for parachain 2
@@ -378,10 +373,7 @@ fn basic_end_to_end_works() {
crowdloan::Event::<Test>::HandleBidResult(ParaId::from(para_2), Ok(())).into(),
);
run_to_block(110);
assert_eq!(
last_event(),
auctions::Event::<Test>::AuctionClosed(1).into(),
);
assert_eq!(last_event(), auctions::Event::<Test>::AuctionClosed(1).into(),);
// Paras should have won slots
assert_eq!(
@@ -392,19 +384,33 @@ fn basic_end_to_end_works() {
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(para_2)),
// -- 1 --- 2 --- 3 --- 4 --- 5 ---------------- 6 --------------------------- 7 ----------------
vec![None, None, None, None, None, Some((crowdloan_account, 920)), Some((crowdloan_account, 920))],
vec![
None,
None,
None,
None,
None,
Some((crowdloan_account, 920)),
Some((crowdloan_account, 920))
],
);
// Should not be able to contribute to a winning crowdloan
Balances::make_free_balance_be(&3, 1_000_000_000);
assert_noop!(Crowdloan::contribute(Origin::signed(3), ParaId::from(2001), 10, None), CrowdloanError::<Test>::BidOrLeaseActive);
assert_noop!(
Crowdloan::contribute(Origin::signed(3), ParaId::from(2001), 10, None),
CrowdloanError::<Test>::BidOrLeaseActive
);
// New leases will start on block 400
let lease_start_block = 400;
run_to_block(lease_start_block);
// First slot, Para 1 should be transitioning to Parachain
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::UpgradingParathread));
assert_eq!(
Paras::lifecycle(ParaId::from(para_1)),
Some(ParaLifecycle::UpgradingParathread)
);
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
// Two sessions later, it has upgraded
@@ -419,8 +425,14 @@ fn basic_end_to_end_works() {
// Third slot, Para 2 should be upgrading, and Para 1 is downgrading
run_to_block(lease_start_block + 200);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::DowngradingParachain));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::UpgradingParathread));
assert_eq!(
Paras::lifecycle(ParaId::from(para_1)),
Some(ParaLifecycle::DowngradingParachain)
);
assert_eq!(
Paras::lifecycle(ParaId::from(para_2)),
Some(ParaLifecycle::UpgradingParathread)
);
// Two sessions later, they have transitioned
run_to_block(lease_start_block + 220);
@@ -435,7 +447,10 @@ fn basic_end_to_end_works() {
// Fifth slot, Para 2 is downgrading
run_to_block(lease_start_block + 400);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::DowngradingParachain));
assert_eq!(
Paras::lifecycle(ParaId::from(para_2)),
Some(ParaLifecycle::DowngradingParachain)
);
// Two sessions later, Para 2 is downgraded
run_to_block(lease_start_block + 420);
@@ -463,12 +478,10 @@ fn basic_errors_fail() {
validation_code.clone(),
));
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_noop!(Registrar::register(
Origin::signed(2),
para_id,
genesis_head,
validation_code,
), paras_registrar::Error::<Test>::NotOwner);
assert_noop!(
Registrar::register(Origin::signed(2), para_id, genesis_head, validation_code,),
paras_registrar::Error::<Test>::NotOwner
);
// Start an auction
let duration = 99u32;
@@ -476,15 +489,18 @@ fn basic_errors_fail() {
assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start));
// Cannot create a crowdloan if you do not own the para
assert_noop!(Crowdloan::create(
Origin::signed(2),
para_id,
1_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
None,
), crowdloan::Error::<Test>::InvalidOrigin);
assert_noop!(
Crowdloan::create(
Origin::signed(2),
para_id,
1_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
None,
),
crowdloan::Error::<Test>::InvalidOrigin
);
});
}
@@ -497,7 +513,7 @@ fn competing_slots() {
let para_id = LOWEST_PUBLIC_ID;
// Create n paras and owners
for n in 1 ..= max_bids {
for n in 1..=max_bids {
Balances::make_free_balance_be(&n, 1_000_000_000);
let genesis_head = Registrar::worst_head_data();
let validation_code = Registrar::worst_validation_code();
@@ -518,22 +534,22 @@ fn competing_slots() {
// Paras should be onboarded
run_to_block(20); // session 2
for n in 1 ..= max_bids {
for n in 1..=max_bids {
// Increment block number
run_to_block(System::block_number() + 10);
Balances::make_free_balance_be(&(n * 10), n * 1_000);
let (start, end) = match n {
1 => (0, 0),
2 => (0, 1),
3 => (0, 2),
4 => (0, 3),
5 => (1, 1),
6 => (1, 2),
7 => (1, 3),
8 => (2, 2),
9 => (2, 3),
1 => (0, 0),
2 => (0, 1),
3 => (0, 2),
4 => (0, 3),
5 => (1, 1),
6 => (1, 2),
7 => (1, 3),
8 => (2, 2),
9 => (2, 3),
10 => (3, 3),
_ => panic!("test not meant for this"),
};
@@ -542,10 +558,10 @@ fn competing_slots() {
assert_ok!(Auctions::bid(
Origin::signed(n * 10),
para_id + n - 1,
1, // Auction Index
1, // Auction Index
lease_period_index_start + start, // First Slot
lease_period_index_start + end, // Last slot
n * 900, // Amount
lease_period_index_start + end, // Last slot
n * 900, // Amount
));
}
@@ -582,7 +598,7 @@ fn competing_bids() {
let start_para = LOWEST_PUBLIC_ID - 1;
// Create 3 paras and owners
for n in 1 ..= 3 {
for n in 1..=3 {
Balances::make_free_balance_be(&n, 1_000_000_000);
let genesis_head = Registrar::worst_head_data();
let validation_code = Registrar::worst_validation_code();
@@ -604,20 +620,20 @@ fn competing_bids() {
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start));
for n in 1 ..= 3 {
for n in 1..=3 {
// Create a crowdloan for each para
assert_ok!(Crowdloan::create(
Origin::signed(n),
ParaId::from(start_para + n),
100_000, // Cap
100_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End,
200, // Block End,
None,
));
}
for n in 1 ..= 9 {
for n in 1..=9 {
// Increment block number
run_to_block(starting_block + n * 10);
@@ -630,10 +646,10 @@ fn competing_bids() {
assert_ok!(Auctions::bid(
Origin::signed(n * 10),
ParaId::from(para),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
n * 900, // Amount
n * 900, // Amount
));
} else {
// User 20 will be a contribute to crowdloan for parachain 2
@@ -654,7 +670,15 @@ fn competing_bids() {
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7 -------------
vec![None, None, None, None, None, Some((crowdloan_2, 1812)), Some((crowdloan_2, 1812))],
vec![
None,
None,
None,
None,
None,
Some((crowdloan_2, 1812)),
Some((crowdloan_2, 1812))
],
);
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2002)),
@@ -669,7 +693,7 @@ fn basic_swap_works() {
// This test will test a swap between a parachain and parathread works successfully.
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one()); // So events are emitted
// User 1 and 2 will own paras
// User 1 and 2 will own paras
Balances::make_free_balance_be(&1, 1_000_000_000);
Balances::make_free_balance_be(&2, 1_000_000_000);
// First register 2 parathreads with different data
@@ -706,17 +730,17 @@ fn basic_swap_works() {
assert_ok!(Crowdloan::create(
Origin::signed(1),
ParaId::from(2000),
1_000_000, // Cap
1_000_000, // Cap
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
200, // Block End
None,
));
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000));
// Bunch of contributions
let mut total = 0;
for i in 10 .. 20 {
for i in 10..20 {
Balances::make_free_balance_be(&i, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None));
total += 900 - i;
@@ -750,8 +774,16 @@ fn basic_swap_works() {
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread));
// Initiate a swap
assert_ok!(Registrar::swap(para_origin(2000).into(), ParaId::from(2000), ParaId::from(2001)));
assert_ok!(Registrar::swap(para_origin(2001).into(), ParaId::from(2001), ParaId::from(2000)));
assert_ok!(Registrar::swap(
para_origin(2000).into(),
ParaId::from(2000),
ParaId::from(2001)
));
assert_ok!(Registrar::swap(
para_origin(2001).into(),
ParaId::from(2001),
ParaId::from(2000)
));
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::DowngradingParachain));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::UpgradingParathread));
@@ -774,15 +806,21 @@ fn basic_swap_works() {
assert!(!Slots::lease(ParaId::from(2001)).is_empty());
// Cant dissolve
assert_noop!(Crowdloan::dissolve(Origin::signed(1), ParaId::from(2000)), CrowdloanError::<Test>::InvalidParaId);
assert_noop!(Crowdloan::dissolve(Origin::signed(2), ParaId::from(2001)), CrowdloanError::<Test>::NotReadyToDissolve);
assert_noop!(
Crowdloan::dissolve(Origin::signed(1), ParaId::from(2000)),
CrowdloanError::<Test>::InvalidParaId
);
assert_noop!(
Crowdloan::dissolve(Origin::signed(2), ParaId::from(2001)),
CrowdloanError::<Test>::NotReadyToDissolve
);
// Go way in the future when the para is offboarded
run_to_block(lease_start_block + 1000);
// Withdraw of contributions works
assert_eq!(Balances::free_balance(&crowdloan_account), total);
for i in 10 .. 20 {
for i in 10..20 {
assert_ok!(Crowdloan::withdraw(Origin::signed(i), i, ParaId::from(2001)));
}
assert_eq!(Balances::free_balance(&crowdloan_account), 0);
@@ -802,7 +840,7 @@ fn basic_swap_works() {
fn crowdloan_ending_period_bid() {
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one()); // So events are emitted
// User 1 and 2 will own paras
// User 1 and 2 will own paras
Balances::make_free_balance_be(&1, 1_000_000_000);
Balances::make_free_balance_be(&2, 1_000_000_000);
// First register 2 parathreads
@@ -839,17 +877,17 @@ fn crowdloan_ending_period_bid() {
assert_ok!(Crowdloan::create(
Origin::signed(1),
ParaId::from(2000),
1_000_000, // Cap
1_000_000, // Cap
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
200, // Block End
None,
));
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000));
// Bunch of contributions
let mut total = 0;
for i in 10 .. 20 {
for i in 10..20 {
Balances::make_free_balance_be(&i, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None));
total += 900 - i;
@@ -862,10 +900,10 @@ fn crowdloan_ending_period_bid() {
assert_ok!(Auctions::bid(
Origin::signed(2),
ParaId::from(2001),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
900, // Amount
));
// Go to beginning of ending period
@@ -874,7 +912,8 @@ fn crowdloan_ending_period_bid() {
assert_eq!(Auctions::auction_status(100), AuctionStatus::<u32>::EndingPeriod(0, 0));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(2001), 900));
winning[SlotRange::ZeroThree as u8 as usize] = Some((crowdloan_account, ParaId::from(2000), total));
winning[SlotRange::ZeroThree as u8 as usize] =
Some((crowdloan_account, ParaId::from(2000), total));
assert_eq!(Auctions::winning(0), Some(winning));
@@ -887,7 +926,8 @@ fn crowdloan_ending_period_bid() {
run_to_block(102);
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(2001), 900));
winning[SlotRange::ZeroThree as u8 as usize] = Some((crowdloan_account, ParaId::from(2000), total + 900));
winning[SlotRange::ZeroThree as u8 as usize] =
Some((crowdloan_account, ParaId::from(2000), total + 900));
assert_eq!(Auctions::winning(2), Some(winning));
})
}
@@ -904,14 +944,17 @@ fn auction_bid_requires_registered_para() {
// Can't bid with non-registered paras
Balances::make_free_balance_be(&1, 1_000_000_000);
assert_noop!(Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
), AuctionsError::<Test>::ParaNotRegistered);
assert_noop!(
Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
),
AuctionsError::<Test>::ParaNotRegistered
);
// Now we register the para
assert_ok!(Registrar::reserve(Origin::signed(1)));
@@ -923,14 +966,17 @@ fn auction_bid_requires_registered_para() {
));
// Still can't bid until it is fully onboarded
assert_noop!(Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
), AuctionsError::<Test>::ParaNotRegistered);
assert_noop!(
Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
),
AuctionsError::<Test>::ParaNotRegistered
);
// Onboarded on Session 2
run_to_session(2);
@@ -940,10 +986,10 @@ fn auction_bid_requires_registered_para() {
assert_ok!(Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
900, // Amount
));
});
}
@@ -986,29 +1032,29 @@ fn gap_bids_work() {
assert_ok!(Auctions::bid(
Origin::signed(10),
ParaId::from(2000),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 0, // Last slot
100, // Amount
100, // Amount
));
// Slot 4 for 400 from 10
assert_ok!(Auctions::bid(
Origin::signed(10),
ParaId::from(2000),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 3, // First Slot
lease_period_index_start + 3, // Last slot
400, // Amount
400, // Amount
));
// A bid for another para is counted separately.
assert_ok!(Auctions::bid(
Origin::signed(10),
ParaId::from(2001),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 1, // First Slot
lease_period_index_start + 1, // Last slot
555, // Amount
555, // Amount
));
assert_eq!(Balances::reserved_balance(&10), 400 + 555);
@@ -1016,19 +1062,19 @@ fn gap_bids_work() {
assert_ok!(Auctions::bid(
Origin::signed(20),
ParaId::from(2000),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 1, // First Slot
lease_period_index_start + 1, // Last slot
800, // Amount
800, // Amount
));
// Slot 3 for 200 from 20
assert_ok!(Auctions::bid(
Origin::signed(20),
ParaId::from(2000),
1, // Auction Index
1, // Auction Index
lease_period_index_start + 2, // First Slot
lease_period_index_start + 2, // Last slot
200, // Amount
200, // Amount
));
// Finish the auction
@@ -1038,7 +1084,15 @@ fn gap_bids_work() {
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 ---------- 4 -------------- 5 -------------- 6 -------------- 7 -------
vec![None, None, None, Some((10, 100)), Some((20, 800)), Some((20, 200)), Some((10, 400))],
vec![
None,
None,
None,
Some((10, 100)),
Some((20, 800)),
Some((20, 200)),
Some((10, 400))
],
);
// Appropriate amount is reserved (largest of the values)
assert_eq!(Balances::reserved_balance(&10), 400);
@@ -1125,17 +1179,17 @@ fn cant_bid_on_existing_lease_periods() {
assert_ok!(Crowdloan::create(
Origin::signed(1),
ParaId::from(2000),
1_000_000, // Cap
1_000_000, // Cap
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last Slot
400, // Long block end
400, // Long block end
None,
));
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000));
// Bunch of contributions
let mut total = 0;
for i in 10 .. 20 {
for i in 10..20 {
Balances::make_free_balance_be(&i, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None));
total += 900 - i;
@@ -1150,7 +1204,13 @@ fn cant_bid_on_existing_lease_periods() {
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 ------------- 4 ------------------------ 5 -------------
vec![None, None, None, Some((crowdloan_account, 8855)), Some((crowdloan_account, 8855))],
vec![
None,
None,
None,
Some((crowdloan_account, 8855)),
Some((crowdloan_account, 8855))
],
);
// Let's start another auction for the same range
@@ -1175,7 +1235,8 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start + 0,
lease_period_index_start + 1,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
assert_noop!(
@@ -1186,7 +1247,8 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start + 1,
lease_period_index_start + 2,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
assert_noop!(
@@ -1197,7 +1259,8 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start - 1,
lease_period_index_start + 0,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
assert_noop!(
@@ -1208,7 +1271,8 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start + 0,
lease_period_index_start + 0,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
assert_noop!(
@@ -1219,7 +1283,8 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start + 1,
lease_period_index_start + 1,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
assert_noop!(
@@ -1230,19 +1295,18 @@ fn cant_bid_on_existing_lease_periods() {
lease_period_index_start - 1,
lease_period_index_start + 5,
100,
), AuctionsError::<Test>::AlreadyLeasedOut,
),
AuctionsError::<Test>::AlreadyLeasedOut,
);
// Will work when not overlapping
assert_ok!(
Auctions::bid(
Origin::signed(crowdloan_account),
ParaId::from(2000),
2,
lease_period_index_start + 2,
lease_period_index_start + 3,
100,
)
);
assert_ok!(Auctions::bid(
Origin::signed(crowdloan_account),
ParaId::from(2000),
2,
lease_period_index_start + 2,
lease_period_index_start + 3,
100,
));
});
}
+56 -48
View File
@@ -18,47 +18,52 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod claims;
pub mod slots;
pub mod auctions;
pub mod claims;
pub mod crowdloan;
pub mod purchase;
pub mod elections;
pub mod impls;
pub mod paras_sudo_wrapper;
pub mod paras_registrar;
pub mod paras_sudo_wrapper;
pub mod purchase;
pub mod slot_range;
pub mod slots;
pub mod traits;
pub mod xcm_sender;
pub mod elections;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod integration_tests;
#[cfg(test)]
mod mock;
use primitives::v1::{AssignmentId, BlockNumber, ValidatorId};
use sp_runtime::{Perquintill, Perbill, FixedPointNumber};
use frame_system::limits;
use frame_support::{
parameter_types, traits::{Currency, OneSessionHandler},
weights::{Weight, constants::WEIGHT_PER_SECOND, DispatchClass},
pub use frame_support::weights::constants::{
BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight,
};
use pallet_transaction_payment::{TargetedFeeAdjustment, Multiplier};
use frame_support::{
parameter_types,
traits::{Currency, OneSessionHandler},
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight},
};
use frame_system::limits;
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use primitives::v1::{AssignmentId, BlockNumber, ValidatorId};
use sp_runtime::{FixedPointNumber, Perbill, Perquintill};
use static_assertions::const_assert;
pub use frame_support::weights::constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
pub use elections::{OffchainSolutionLengthLimit, OffchainSolutionWeightLimit};
pub use pallet_balances::Call as BalancesCall;
#[cfg(feature = "std")]
pub use pallet_staking::StakerStatus;
pub use pallet_timestamp::Call as TimestampCall;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use pallet_timestamp::Call as TimestampCall;
pub use pallet_balances::Call as BalancesCall;
pub use elections::{OffchainSolutionLengthLimit, OffchainSolutionWeightLimit};
/// Implementations of some helper traits passed into runtime modules as associated types.
pub use impls::ToAuthor;
pub type NegativeImbalance<T> = <pallet_balances::Pallet<T> as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance;
pub type NegativeImbalance<T> = <pallet_balances::Pallet<T> as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;
/// We assume that an on-initialize consumes 1% of the weight on average, hence a single extrinsic
/// will not be allowed to consume more than `AvailableBlockRatio - 1%`.
@@ -110,12 +115,8 @@ parameter_types! {
/// Parameterized slow adjusting fee updated based on
/// https://w3f-research.readthedocs.io/en/latest/polkadot/Token%20Economics.html#-2.-slow-adjusting-mechanism
pub type SlowAdjustingFeeUpdate<R> = TargetedFeeAdjustment<
R,
TargetBlockFullness,
AdjustmentVariable,
MinimumMultiplier
>;
pub type SlowAdjustingFeeUpdate<R> =
TargetedFeeAdjustment<R, TargetBlockFullness, AdjustmentVariable, MinimumMultiplier>;
/// The type used for currency conversion.
///
@@ -130,25 +131,26 @@ impl<T> sp_runtime::BoundToRuntimeAppPublic for ParachainSessionKeyPlaceholder<T
type Public = ValidatorId;
}
impl<T: pallet_session::Config> OneSessionHandler<T::AccountId> for ParachainSessionKeyPlaceholder<T>
impl<T: pallet_session::Config> OneSessionHandler<T::AccountId>
for ParachainSessionKeyPlaceholder<T>
{
type Key = ValidatorId;
fn on_genesis_session<'a, I: 'a>(_validators: I) where
fn on_genesis_session<'a, I: 'a>(_validators: I)
where
I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
T::AccountId: 'a
T::AccountId: 'a,
{
}
fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I) where
fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I)
where
I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
T::AccountId: 'a
T::AccountId: 'a,
{
}
fn on_disabled(_: usize) { }
fn on_disabled(_: usize) {}
}
/// A placeholder since there is currently no provided session key handler for parachain validator
@@ -158,25 +160,26 @@ impl<T> sp_runtime::BoundToRuntimeAppPublic for AssignmentSessionKeyPlaceholder<
type Public = AssignmentId;
}
impl<T: pallet_session::Config> OneSessionHandler<T::AccountId> for AssignmentSessionKeyPlaceholder<T>
impl<T: pallet_session::Config> OneSessionHandler<T::AccountId>
for AssignmentSessionKeyPlaceholder<T>
{
type Key = AssignmentId;
fn on_genesis_session<'a, I: 'a>(_validators: I) where
fn on_genesis_session<'a, I: 'a>(_validators: I)
where
I: Iterator<Item = (&'a T::AccountId, AssignmentId)>,
T::AccountId: 'a
T::AccountId: 'a,
{
}
fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I) where
fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I)
where
I: Iterator<Item = (&'a T::AccountId, AssignmentId)>,
T::AccountId: 'a
T::AccountId: 'a,
{
}
fn on_disabled(_: usize) { }
fn on_disabled(_: usize) {}
}
#[cfg(test)]
@@ -186,7 +189,7 @@ mod multiplier_tests {
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup, Convert, One},
traits::{BlakeTwo256, Convert, IdentityLookup, One},
Perbill,
};
@@ -238,9 +241,14 @@ mod multiplier_tests {
type OnSetCode = ();
}
fn run_with_system_weight<F>(w: Weight, mut assertions: F) where F: FnMut() -> () {
let mut t: sp_io::TestExternalities =
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
fn run_with_system_weight<F>(w: Weight, mut assertions: F)
where
F: FnMut() -> (),
{
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.unwrap()
.into();
t.execute_with(|| {
System::set_block_consumed_resources(w, 0);
assertions()
@@ -266,9 +274,9 @@ mod multiplier_tests {
// assume the multiplier is initially set to its minimum. We update it with values twice the
//target (target is 25%, thus 50%) and we see at which point it reaches 1.
let mut multiplier = MinimumMultiplier::get();
let block_weight = TargetBlockFullness::get()
* BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap()
* 2;
let block_weight = TargetBlockFullness::get() *
BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() *
2;
let mut blocks = 0;
while multiplier <= Multiplier::one() {
run_with_system_weight(block_weight, || {
+23 -13
View File
@@ -16,12 +16,12 @@
//! Mocking utilities for testing.
use std::{cell::RefCell, collections::HashMap};
use parity_scale_codec::{Encode, Decode};
use sp_runtime::traits::SaturatedConversion;
use frame_support::dispatch::{DispatchError, DispatchResult};
use primitives::v1::{HeadData, ValidationCode, Id as ParaId};
use crate::traits::Registrar;
use frame_support::dispatch::{DispatchError, DispatchResult};
use parity_scale_codec::{Decode, Encode};
use primitives::v1::{HeadData, Id as ParaId, ValidationCode};
use sp_runtime::traits::SaturatedConversion;
use std::{cell::RefCell, collections::HashMap};
thread_local! {
static OPERATIONS: RefCell<Vec<(ParaId, u32, bool)>> = RefCell::new(Vec::new());
@@ -130,9 +130,13 @@ impl<T: frame_system::Config> Registrar for TestRegistrar<T> {
},
}
})?;
OPERATIONS.with(|x| x.borrow_mut().push(
(id, frame_system::Pallet::<T>::block_number().saturated_into(), true)
));
OPERATIONS.with(|x| {
x.borrow_mut().push((
id,
frame_system::Pallet::<T>::block_number().saturated_into(),
true,
))
});
Ok(())
}
fn make_parathread(id: ParaId) -> DispatchResult {
@@ -149,16 +153,21 @@ impl<T: frame_system::Config> Registrar for TestRegistrar<T> {
PARATHREADS.with(|x| {
let mut parathreads = x.borrow_mut();
match parathreads.binary_search(&id) {
Ok(_) => Err(DispatchError::Other("already parathread, so cannot `make_parathread`")),
Ok(_) =>
Err(DispatchError::Other("already parathread, so cannot `make_parathread`")),
Err(i) => {
parathreads.insert(i, id);
Ok(())
},
}
})?;
OPERATIONS.with(|x| x.borrow_mut().push(
(id, frame_system::Pallet::<T>::block_number().saturated_into(), false)
));
OPERATIONS.with(|x| {
x.borrow_mut().push((
id,
frame_system::Pallet::<T>::block_number().saturated_into(),
false,
))
});
Ok(())
}
@@ -179,7 +188,8 @@ impl<T: frame_system::Config> Registrar for TestRegistrar<T> {
impl<T: frame_system::Config> TestRegistrar<T> {
pub fn operations() -> Vec<(ParaId, T::BlockNumber, bool)> {
OPERATIONS.with(|x| x.borrow().iter().map(|(p, b, c)| (*p, (*b).into(), *c)).collect::<Vec<_>>())
OPERATIONS
.with(|x| x.borrow().iter().map(|(p, b, c)| (*p, (*b).into(), *c)).collect::<Vec<_>>())
}
#[allow(dead_code)]
+179 -166
View File
@@ -17,31 +17,28 @@
//! Pallet to handle parathread/parachain registration and related fund management.
//! In essence this is a simple wrapper around `paras`.
use sp_std::{prelude::*, result};
use frame_support::{
ensure,
dispatch::DispatchResult,
traits::{Get, Currency, ReservableCurrency},
ensure,
pallet_prelude::Weight,
traits::{Currency, Get, ReservableCurrency},
};
use frame_system::{self, ensure_root, ensure_signed};
use primitives::v1::{
Id as ParaId, ValidationCode, HeadData, LOWEST_PUBLIC_ID,
};
use primitives::v1::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID};
use runtime_parachains::{
paras::{
self,
ParaGenesisArgs,
},
configuration,
ensure_parachain,
configuration, ensure_parachain,
paras::{self, ParaGenesisArgs},
Origin, ParaLifecycle,
};
use sp_std::{prelude::*, result};
use crate::traits::{Registrar, OnSwap};
use parity_scale_codec::{Encode, Decode};
use sp_runtime::{RuntimeDebug, traits::{Saturating, CheckedSub}};
use crate::traits::{OnSwap, Registrar};
pub use pallet::*;
use parity_scale_codec::{Decode, Encode};
use sp_runtime::{
traits::{CheckedSub, Saturating},
RuntimeDebug,
};
#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug)]
pub struct ParaInfo<Account, Balance> {
@@ -66,18 +63,28 @@ pub trait WeightInfo {
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn reserve() -> Weight { 0 }
fn register() -> Weight { 0 }
fn force_register() -> Weight { 0 }
fn deregister() -> Weight { 0 }
fn swap() -> Weight { 0 }
fn reserve() -> Weight {
0
}
fn register() -> Weight {
0
}
fn force_register() -> Weight {
0
}
fn deregister() -> Weight {
0
}
fn swap() -> Weight {
0
}
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use super::*;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
@@ -161,7 +168,8 @@ pub mod pallet {
/// The given account ID is responsible for registering the code and initial head data, but may only do
/// so if it isn't yet registered. (After that, it's up to governance to do so.)
#[pallet::storage]
pub type Paras<T: Config> = StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
pub type Paras<T: Config> =
StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
/// The next free `ParaId`.
#[pallet::storage]
@@ -363,8 +371,12 @@ impl<T: Config> Registrar for Pallet<T> {
// Upgrade a registered parathread into a parachain.
fn make_parachain(id: ParaId) -> DispatchResult {
// Para backend should think this is a parathread...
ensure!(paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::<T>::NotParathread);
runtime_parachains::schedule_parathread_upgrade::<T>(id).map_err(|_| Error::<T>::CannotUpgrade)?;
ensure!(
paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread),
Error::<T>::NotParathread
);
runtime_parachains::schedule_parathread_upgrade::<T>(id)
.map_err(|_| Error::<T>::CannotUpgrade)?;
// Once a para has upgraded to a parachain, it can no longer be managed by the owner.
// Intentionally, the flag stays with the para even after downgrade.
Self::apply_lock(id);
@@ -374,8 +386,12 @@ impl<T: Config> Registrar for Pallet<T> {
// Downgrade a registered para into a parathread.
fn make_parathread(id: ParaId) -> DispatchResult {
// Para backend should think this is a parachain...
ensure!(paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain), Error::<T>::NotParachain);
runtime_parachains::schedule_parachain_downgrade::<T>(id).map_err(|_| Error::<T>::CannotDowngrade)?;
ensure!(
paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain),
Error::<T>::NotParachain
);
runtime_parachains::schedule_parachain_downgrade::<T>(id)
.map_err(|_| Error::<T>::CannotDowngrade)?;
Ok(())
}
@@ -397,9 +413,7 @@ impl<T: Config> Registrar for Pallet<T> {
#[cfg(any(feature = "runtime-benchmarks", test))]
fn execute_pending_transitions() {
use runtime_parachains::shared;
shared::Pallet::<T>::set_session_index(
shared::Pallet::<T>::scheduled_session()
);
shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
paras::Pallet::<T>::test_on_new_session();
}
}
@@ -407,23 +421,28 @@ impl<T: Config> Registrar for Pallet<T> {
impl<T: Config> Pallet<T> {
/// Ensure the origin is one of Root, the `para` owner, or the `para` itself.
/// If the origin is the `para` owner, the `para` must be unlocked.
fn ensure_root_para_or_owner(origin: <T as frame_system::Config>::Origin, id: ParaId) -> DispatchResult {
ensure_signed(origin.clone()).map_err(|e| e.into())
.and_then(|who| -> DispatchResult {
let para_info = Paras::<T>::get(id).ok_or(Error::<T>::NotRegistered)?;
ensure!(!para_info.locked, Error::<T>::ParaLocked);
ensure!(para_info.manager == who, Error::<T>::NotOwner);
Ok(())
})
.or_else(|_| -> DispatchResult {
// Else check if para origin...
let caller_id = ensure_parachain(<T as Config>::Origin::from(origin.clone()))?;
ensure!(caller_id == id, Error::<T>::NotOwner);
Ok(())
}).or_else(|_| -> DispatchResult {
// Check if root...
ensure_root(origin.clone()).map_err(|e| e.into())
})
fn ensure_root_para_or_owner(
origin: <T as frame_system::Config>::Origin,
id: ParaId,
) -> DispatchResult {
ensure_signed(origin.clone())
.map_err(|e| e.into())
.and_then(|who| -> DispatchResult {
let para_info = Paras::<T>::get(id).ok_or(Error::<T>::NotRegistered)?;
ensure!(!para_info.locked, Error::<T>::ParaLocked);
ensure!(para_info.manager == who, Error::<T>::NotOwner);
Ok(())
})
.or_else(|_| -> DispatchResult {
// Else check if para origin...
let caller_id = ensure_parachain(<T as Config>::Origin::from(origin.clone()))?;
ensure!(caller_id == id, Error::<T>::NotOwner);
Ok(())
})
.or_else(|_| -> DispatchResult {
// Check if root...
ensure_root(origin.clone()).map_err(|e| e.into())
})
}
fn do_reserve(
@@ -436,11 +455,7 @@ impl<T: Config> Pallet<T> {
let deposit = deposit_override.unwrap_or_else(T::ParaDeposit::get);
<T as Config>::Currency::reserve(&who, deposit)?;
let info = ParaInfo {
manager: who.clone(),
deposit,
locked: false,
};
let info = ParaInfo { manager: who.clone(), deposit, locked: false };
Paras::<T>::insert(id, info);
Self::deposit_event(Event::<T>::Reserved(id, who));
@@ -466,11 +481,8 @@ impl<T: Config> Pallet<T> {
Default::default()
};
ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
let (genesis, deposit) = Self::validate_onboarding_data(
genesis_head,
validation_code,
false
)?;
let (genesis, deposit) =
Self::validate_onboarding_data(genesis_head, validation_code, false)?;
let deposit = deposit_override.unwrap_or(deposit);
if let Some(additional) = deposit.checked_sub(&deposited) {
@@ -478,11 +490,7 @@ impl<T: Config> Pallet<T> {
} else if let Some(rebate) = deposited.checked_sub(&deposit) {
<T as Config>::Currency::unreserve(&who, rebate);
};
let info = ParaInfo {
manager: who.clone(),
deposit,
locked: false,
};
let info = ParaInfo { manager: who.clone(), deposit, locked: false };
Paras::<T>::insert(id, info);
// We check above that para has no lifecycle, so this should not fail.
@@ -497,9 +505,10 @@ impl<T: Config> Pallet<T> {
match paras::Pallet::<T>::lifecycle(id) {
// Para must be a parathread, or not exist at all.
Some(ParaLifecycle::Parathread) | None => {},
_ => return Err(Error::<T>::NotParathread.into())
_ => return Err(Error::<T>::NotParathread.into()),
}
runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;
runtime_parachains::schedule_para_cleanup::<T>(id)
.map_err(|_| Error::<T>::CannotDeregister)?;
if let Some(info) = Paras::<T>::take(&id) {
<T as Config>::Currency::unreserve(&info.manager, info.deposit);
@@ -520,45 +529,40 @@ impl<T: Config> Pallet<T> {
) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> {
let config = configuration::Pallet::<T>::config();
ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::<T>::CodeTooLarge);
ensure!(genesis_head.0.len() <= config.max_head_data_size as usize, Error::<T>::HeadDataTooLarge);
ensure!(
genesis_head.0.len() <= config.max_head_data_size as usize,
Error::<T>::HeadDataTooLarge
);
let per_byte_fee = T::DataDepositPerByte::get();
let deposit = T::ParaDeposit::get()
.saturating_add(
per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into())
).saturating_add(
per_byte_fee.saturating_mul((validation_code.0.len() as u32).into())
);
.saturating_add(per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into()))
.saturating_add(per_byte_fee.saturating_mul((validation_code.0.len() as u32).into()));
Ok((ParaGenesisArgs {
genesis_head,
validation_code,
parachain,
}, deposit))
Ok((ParaGenesisArgs { genesis_head, validation_code, parachain }, deposit))
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_io::TestExternalities;
use sp_core::H256;
use sp_runtime::{
traits::{
BlakeTwo256, IdentityLookup,
}, Perbill,
};
use primitives::v1::{Balance, BlockNumber, Header};
use frame_system::limits;
use crate::{paras_registrar, traits::Registrar as RegistrarTrait};
use frame_support::{
traits::{OnInitialize, OnFinalize, GenesisBuild},
assert_ok, assert_noop, parameter_types,
assert_noop, assert_ok,
error::BadOrigin,
parameter_types,
traits::{GenesisBuild, OnFinalize, OnInitialize},
};
use runtime_parachains::{configuration, shared};
use frame_system::limits;
use pallet_balances::Error as BalancesError;
use crate::traits::Registrar as RegistrarTrait;
use crate::paras_registrar;
use primitives::v1::{Balance, BlockNumber, Header};
use runtime_parachains::{configuration, shared};
use sp_core::H256;
use sp_io::TestExternalities;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
Perbill,
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -636,7 +640,7 @@ mod tests {
type Event = Event;
}
impl configuration::Config for Test { }
impl configuration::Config for Test {}
parameter_types! {
pub const ParaDeposit: Balance = 10;
@@ -661,17 +665,18 @@ mod tests {
GenesisBuild::<Test>::assimilate_storage(
&configuration::GenesisConfig {
config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB
max_code_size: 2 * 1024 * 1024, // 2 MB
max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default()
}
},
},
&mut t
).unwrap();
&mut t,
)
.unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 10_000_000), (2, 10_000_000)],
}.assimilate_storage(&mut t).unwrap();
pallet_balances::GenesisConfig::<Test> { balances: vec![(1, 10_000_000), (2, 10_000_000)] }
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
@@ -691,7 +696,7 @@ mod tests {
// Session change every 3 blocks.
if (b + 1) % BLOCKS_PER_SESSION == 0 {
shared::Pallet::<Test>::set_session_index(
shared::Pallet::<Test>::session_index() + 1
shared::Pallet::<Test>::session_index() + 1,
);
Parachains::test_on_new_session();
}
@@ -765,10 +770,7 @@ mod tests {
assert!(Parachains::is_parathread(para_id));
assert!(!Parachains::is_parachain(para_id));
// Deregister it
assert_ok!(Registrar::deregister(
Origin::root(),
para_id,
));
assert_ok!(Registrar::deregister(Origin::root(), para_id,));
run_to_session(8);
// It is nothing
assert!(!Parachains::is_parathread(para_id));
@@ -794,7 +796,8 @@ mod tests {
assert!(Parachains::is_parathread(para_id));
assert_eq!(
Balances::reserved_balance(&1),
<Test as Config>::ParaDeposit::get() + 64 * <Test as Config>::DataDepositPerByte::get()
<Test as Config>::ParaDeposit::get() +
64 * <Test as Config>::DataDepositPerByte::get()
);
});
}
@@ -804,22 +807,28 @@ mod tests {
new_test_ext().execute_with(|| {
let para_id = LOWEST_PUBLIC_ID;
assert_noop!(Registrar::register(
Origin::signed(1),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
), Error::<Test>::NotReserved);
assert_noop!(
Registrar::register(
Origin::signed(1),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::NotReserved
);
// Successfully register para
assert_ok!(Registrar::reserve(Origin::signed(1)));
assert_noop!(Registrar::register(
Origin::signed(2),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
), Error::<Test>::NotOwner);
assert_noop!(
Registrar::register(
Origin::signed(2),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::NotOwner
);
assert_ok!(Registrar::register(
Origin::signed(1),
@@ -833,32 +842,44 @@ mod tests {
assert_ok!(Registrar::deregister(Origin::root(), para_id));
// Can't do it again
assert_noop!(Registrar::register(
Origin::signed(1),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
), Error::<Test>::NotReserved);
assert_noop!(
Registrar::register(
Origin::signed(1),
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::NotReserved
);
// Head Size Check
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_noop!(Registrar::register(
Origin::signed(2),
para_id + 1,
test_genesis_head((max_head_size() + 1) as usize),
test_validation_code(max_code_size() as usize),
), Error::<Test>::HeadDataTooLarge);
assert_noop!(
Registrar::register(
Origin::signed(2),
para_id + 1,
test_genesis_head((max_head_size() + 1) as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::HeadDataTooLarge
);
// Code Size Check
assert_noop!(Registrar::register(
Origin::signed(2),
para_id + 1,
test_genesis_head(max_head_size() as usize),
test_validation_code((max_code_size() + 1) as usize),
), Error::<Test>::CodeTooLarge);
assert_noop!(
Registrar::register(
Origin::signed(2),
para_id + 1,
test_genesis_head(max_head_size() as usize),
test_validation_code((max_code_size() + 1) as usize),
),
Error::<Test>::CodeTooLarge
);
// Needs enough funds for deposit
assert_noop!(Registrar::reserve(Origin::signed(1337)), BalancesError::<Test, _>::InsufficientBalance);
assert_noop!(
Registrar::reserve(Origin::signed(1337)),
BalancesError::<Test, _>::InsufficientBalance
);
});
}
@@ -877,10 +898,7 @@ mod tests {
));
run_to_session(2);
assert!(Parachains::is_parathread(para_id));
assert_ok!(Registrar::deregister(
Origin::root(),
para_id,
));
assert_ok!(Registrar::deregister(Origin::root(), para_id,));
run_to_session(4);
assert!(paras::Pallet::<Test>::lifecycle(para_id).is_none());
assert_eq!(Balances::reserved_balance(&1), 0);
@@ -903,17 +921,14 @@ mod tests {
run_to_session(2);
assert!(Parachains::is_parathread(para_id));
// Owner check
assert_noop!(Registrar::deregister(
Origin::signed(2),
para_id,
), BadOrigin);
assert_noop!(Registrar::deregister(Origin::signed(2), para_id,), BadOrigin);
assert_ok!(Registrar::make_parachain(para_id));
run_to_session(4);
// Cant directly deregister parachain
assert_noop!(Registrar::deregister(
Origin::root(),
para_id,
), Error::<Test>::NotParathread);
assert_noop!(
Registrar::deregister(Origin::root(), para_id,),
Error::<Test>::NotParathread
);
});
}
@@ -951,22 +966,17 @@ mod tests {
assert!(Parachains::is_parathread(para_2));
// Both paras initiate a swap
assert_ok!(Registrar::swap(
para_origin(para_1),
para_1,
para_2,
));
assert_ok!(Registrar::swap(
para_origin(para_2),
para_2,
para_1,
));
assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,));
assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,));
run_to_session(6);
// Deregister a parathread that was originally a parachain
assert_eq!(Parachains::lifecycle(para_1), Some(ParaLifecycle::Parathread));
assert_ok!(Registrar::deregister(runtime_parachains::Origin::Parachain(para_1).into(), para_1));
assert_ok!(Registrar::deregister(
runtime_parachains::Origin::Parachain(para_1).into(),
para_1
));
run_to_block(21);
@@ -1010,14 +1020,14 @@ mod tests {
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking {
use super::{*, Pallet as Registrar};
use frame_system::RawOrigin;
use super::{Pallet as Registrar, *};
use crate::traits::Registrar as RegistrarT;
use frame_support::assert_ok;
use sp_runtime::traits::Bounded;
use crate::traits::{Registrar as RegistrarT};
use frame_system::RawOrigin;
use runtime_parachains::{paras, shared, Origin as ParaOrigin};
use sp_runtime::traits::Bounded;
use frame_benchmarking::{account, benchmarks, whitelisted_caller, impl_benchmark_test_suite};
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
let events = frame_system::Pallet::<T>::events();
@@ -1034,8 +1044,13 @@ mod benchmarking {
let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
assert_ok!(Registrar::<T>::reserve(RawOrigin::Signed(caller.clone()).into()));
assert_ok!(Registrar::<T>::register(RawOrigin::Signed(caller).into(), para, genesis_head, validation_code));
return para;
assert_ok!(Registrar::<T>::register(
RawOrigin::Signed(caller).into(),
para,
genesis_head,
validation_code
));
return para
}
fn para_origin(id: u32) -> ParaOrigin {
@@ -1044,9 +1059,7 @@ mod benchmarking {
// This function moves forward to the next scheduled session for parachain lifecycle upgrades.
fn next_scheduled_session<T: Config>() {
shared::Pallet::<T>::set_session_index(
shared::Pallet::<T>::scheduled_session()
);
shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
paras::Pallet::<T>::test_on_new_session();
}
@@ -18,14 +18,14 @@
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use runtime_parachains::{
configuration, dmp, ump, hrmp,
ParaLifecycle,
paras::{self, ParaGenesisArgs},
};
use primitives::v1::Id as ParaId;
use parity_scale_codec::Encode;
pub use pallet::*;
use parity_scale_codec::Encode;
use primitives::v1::Id as ParaId;
use runtime_parachains::{
configuration, dmp, hrmp,
paras::{self, ParaGenesisArgs},
ump, ParaLifecycle,
};
#[frame_support::pallet]
pub mod pallet {
@@ -38,8 +38,9 @@ pub mod pallet {
#[pallet::config]
#[pallet::disable_frame_system_supertrait_check]
pub trait Config:
configuration::Config + paras::Config + dmp::Config + ump::Config + hrmp::Config {}
configuration::Config + paras::Config + dmp::Config + ump::Config + hrmp::Config
{
}
#[pallet::error]
pub enum Error<T> {
@@ -84,13 +85,17 @@ pub mod pallet {
#[pallet::weight((1_000, DispatchClass::Operational))]
pub fn sudo_schedule_para_cleanup(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
ensure_root(origin)?;
runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CouldntCleanup)?;
runtime_parachains::schedule_para_cleanup::<T>(id)
.map_err(|_| Error::<T>::CouldntCleanup)?;
Ok(())
}
/// Upgrade a parathread to a parachain
#[pallet::weight((1_000, DispatchClass::Operational))]
pub fn sudo_schedule_parathread_upgrade(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
pub fn sudo_schedule_parathread_upgrade(
origin: OriginFor<T>,
id: ParaId,
) -> DispatchResult {
ensure_root(origin)?;
// Para backend should think this is a parathread...
ensure!(
@@ -104,7 +109,10 @@ pub mod pallet {
/// Downgrade a parachain to a parathread
#[pallet::weight((1_000, DispatchClass::Operational))]
pub fn sudo_schedule_parachain_downgrade(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
pub fn sudo_schedule_parachain_downgrade(
origin: OriginFor<T>,
id: ParaId,
) -> DispatchResult {
ensure_root(origin)?;
// Para backend should think this is a parachain...
ensure!(
@@ -129,11 +137,11 @@ pub mod pallet {
ensure_root(origin)?;
ensure!(<paras::Pallet<T>>::is_valid_para(id), Error::<T>::ParaDoesntExist);
let config = <configuration::Pallet<T>>::config();
<dmp::Pallet<T>>::queue_downward_message(&config, id, xcm.encode())
.map_err(|e| match e {
dmp::QueueDownwardMessageError::ExceedsMaxMessageSize =>
Error::<T>::ExceedsMaxMessageSize.into(),
})
<dmp::Pallet<T>>::queue_downward_message(&config, id, xcm.encode()).map_err(|e| match e
{
dmp::QueueDownwardMessageError::ExceedsMaxMessageSize =>
Error::<T>::ExceedsMaxMessageSize.into(),
})
}
/// Forcefully establish a channel from the sender to the recipient.
+255 -174
View File
@@ -16,19 +16,22 @@
//! Pallet to process purchase of DOTs.
use parity_scale_codec::{Encode, Decode};
use sp_runtime::{Permill, RuntimeDebug, DispatchResult, DispatchError, AnySignature};
use sp_runtime::traits::{Zero, CheckedAdd, Verify, Saturating};
use frame_support::pallet_prelude::*;
use frame_support::traits::{
EnsureOrigin, Currency, ExistenceRequirement, VestingSchedule, Get
use frame_support::{
pallet_prelude::*,
traits::{Currency, EnsureOrigin, ExistenceRequirement, Get, VestingSchedule},
};
use frame_system::pallet_prelude::*;
use sp_core::sr25519;
use sp_std::prelude::*;
pub use pallet::*;
use parity_scale_codec::{Decode, Encode};
use sp_core::sr25519;
use sp_runtime::{
traits::{CheckedAdd, Saturating, Verify, Zero},
AnySignature, DispatchError, DispatchResult, Permill, RuntimeDebug,
};
use sp_std::prelude::*;
type BalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
/// The kind of a statement an account needs to make for a claim to be valid.
#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug)]
@@ -99,7 +102,11 @@ pub mod pallet {
type Currency: Currency<Self::AccountId>;
/// Vesting Pallet
type VestingSchedule: VestingSchedule<Self::AccountId, Moment=Self::BlockNumber, Currency=Self::Currency>;
type VestingSchedule: VestingSchedule<
Self::AccountId,
Moment = Self::BlockNumber,
Currency = Self::Currency,
>;
/// The origin allowed to set account status.
type ValidityOrigin: EnsureOrigin<Self::Origin>;
@@ -166,12 +173,8 @@ pub mod pallet {
// A map of all participants in the DOT purchase process.
#[pallet::storage]
pub(super) type Accounts<T: Config> = StorageMap<
_,
Blake2_128Concat, T::AccountId,
AccountStatus<BalanceOf<T>>,
ValueQuery,
>;
pub(super) type Accounts<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, AccountStatus<BalanceOf<T>>, ValueQuery>;
// The account that will be used to payout participants of the DOT purchase process.
#[pallet::storage]
@@ -199,13 +202,16 @@ pub mod pallet {
pub fn create_account(
origin: OriginFor<T>,
who: T::AccountId,
signature: Vec<u8>
signature: Vec<u8>,
) -> DispatchResult {
T::ValidityOrigin::ensure_origin(origin)?;
// Account is already being tracked by the pallet.
ensure!(!Accounts::<T>::contains_key(&who), Error::<T>::ExistingAccount);
// Account should not have a vesting schedule.
ensure!(T::VestingSchedule::vesting_balance(&who).is_none(), Error::<T>::VestingScheduleExists);
ensure!(
T::VestingSchedule::vesting_balance(&who).is_none(),
Error::<T>::VestingScheduleExists
);
// Verify the signature provided is valid for the statement.
Self::verify_signature(&who, &signature)?;
@@ -233,15 +239,21 @@ pub mod pallet {
pub fn update_validity_status(
origin: OriginFor<T>,
who: T::AccountId,
validity: AccountValidity
validity: AccountValidity,
) -> DispatchResult {
T::ValidityOrigin::ensure_origin(origin)?;
ensure!(Accounts::<T>::contains_key(&who), Error::<T>::InvalidAccount);
Accounts::<T>::try_mutate(&who, |status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
ensure!(status.validity != AccountValidity::Completed, Error::<T>::AlreadyCompleted);
status.validity = validity;
Ok(())
})?;
Accounts::<T>::try_mutate(
&who,
|status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
ensure!(
status.validity != AccountValidity::Completed,
Error::<T>::AlreadyCompleted
);
status.validity = validity;
Ok(())
},
)?;
Self::deposit_event(Event::<T>::ValidityUpdated(who, validity));
Ok(())
}
@@ -261,16 +273,19 @@ pub mod pallet {
) -> DispatchResult {
T::ValidityOrigin::ensure_origin(origin)?;
Accounts::<T>::try_mutate(&who, |status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
// Account has a valid status (not Invalid, Pending, or Completed)...
ensure!(status.validity.is_valid(), Error::<T>::InvalidAccount);
Accounts::<T>::try_mutate(
&who,
|status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
// Account has a valid status (not Invalid, Pending, or Completed)...
ensure!(status.validity.is_valid(), Error::<T>::InvalidAccount);
free_balance.checked_add(&locked_balance).ok_or(Error::<T>::Overflow)?;
status.free_balance = free_balance;
status.locked_balance = locked_balance;
status.vat = vat;
Ok(())
})?;
free_balance.checked_add(&locked_balance).ok_or(Error::<T>::Overflow)?;
status.free_balance = free_balance;
status.locked_balance = locked_balance;
status.vat = vat;
Ok(())
},
)?;
Self::deposit_event(Event::<T>::BalanceUpdated(who, free_balance, locked_balance));
Ok(())
}
@@ -287,44 +302,59 @@ pub mod pallet {
ensure!(payment_account == PaymentAccount::<T>::get(), DispatchError::BadOrigin);
// Account should not have a vesting schedule.
ensure!(T::VestingSchedule::vesting_balance(&who).is_none(), Error::<T>::VestingScheduleExists);
ensure!(
T::VestingSchedule::vesting_balance(&who).is_none(),
Error::<T>::VestingScheduleExists
);
Accounts::<T>::try_mutate(&who, |status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
// Account has a valid status (not Invalid, Pending, or Completed)...
ensure!(status.validity.is_valid(), Error::<T>::InvalidAccount);
Accounts::<T>::try_mutate(
&who,
|status: &mut AccountStatus<BalanceOf<T>>| -> DispatchResult {
// Account has a valid status (not Invalid, Pending, or Completed)...
ensure!(status.validity.is_valid(), Error::<T>::InvalidAccount);
// Transfer funds from the payment account into the purchasing user.
let total_balance = status.free_balance
.checked_add(&status.locked_balance)
.ok_or(Error::<T>::Overflow)?;
T::Currency::transfer(&payment_account, &who, total_balance, ExistenceRequirement::AllowDeath)?;
if !status.locked_balance.is_zero() {
let unlock_block = UnlockBlock::<T>::get();
// We allow some configurable portion of the purchased locked DOTs to be unlocked for basic usage.
let unlocked = (T::UnlockedProportion::get() * status.locked_balance).min(T::MaxUnlocked::get());
let locked = status.locked_balance.saturating_sub(unlocked);
// We checked that this account has no existing vesting schedule. So this function should
// never fail, however if it does, not much we can do about it at this point.
let _ = T::VestingSchedule::add_vesting_schedule(
// Apply vesting schedule to this user
// Transfer funds from the payment account into the purchasing user.
let total_balance = status
.free_balance
.checked_add(&status.locked_balance)
.ok_or(Error::<T>::Overflow)?;
T::Currency::transfer(
&payment_account,
&who,
// For this much amount
locked,
// Unlocking the full amount after one block
locked,
// When everything unlocks
unlock_block
);
}
total_balance,
ExistenceRequirement::AllowDeath,
)?;
// Setting the user account to `Completed` ends the purchase process for this user.
status.validity = AccountValidity::Completed;
Self::deposit_event(
Event::<T>::PaymentComplete(who.clone(), status.free_balance, status.locked_balance)
);
Ok(())
})?;
if !status.locked_balance.is_zero() {
let unlock_block = UnlockBlock::<T>::get();
// We allow some configurable portion of the purchased locked DOTs to be unlocked for basic usage.
let unlocked = (T::UnlockedProportion::get() * status.locked_balance)
.min(T::MaxUnlocked::get());
let locked = status.locked_balance.saturating_sub(unlocked);
// We checked that this account has no existing vesting schedule. So this function should
// never fail, however if it does, not much we can do about it at this point.
let _ = T::VestingSchedule::add_vesting_schedule(
// Apply vesting schedule to this user
&who,
// For this much amount
locked,
// Unlocking the full amount after one block
locked,
// When everything unlocks
unlock_block,
);
}
// Setting the user account to `Completed` ends the purchase process for this user.
status.validity = AccountValidity::Completed;
Self::deposit_event(Event::<T>::PaymentComplete(
who.clone(),
status.free_balance,
status.locked_balance,
));
Ok(())
},
)?;
Ok(())
}
@@ -348,7 +378,10 @@ pub mod pallet {
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_statement(origin: OriginFor<T>, statement: Vec<u8>) -> DispatchResult {
T::ConfigurationOrigin::ensure_origin(origin)?;
ensure!((statement.len() as u32) < T::MaxStatementLength::get(), Error::<T>::InvalidStatement);
ensure!(
(statement.len() as u32) < T::MaxStatementLength::get(),
Error::<T>::InvalidStatement
);
// Possibly this is worse than having the caller account be the payment account?
Statement::<T>::set(statement);
Self::deposit_event(Event::<T>::StatementUpdated);
@@ -359,9 +392,15 @@ pub mod pallet {
///
/// Origin must match the `ConfigurationOrigin`
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_unlock_block(origin: OriginFor<T>, unlock_block: T::BlockNumber) -> DispatchResult {
pub fn set_unlock_block(
origin: OriginFor<T>,
unlock_block: T::BlockNumber,
) -> DispatchResult {
T::ConfigurationOrigin::ensure_origin(origin)?;
ensure!(unlock_block > frame_system::Pallet::<T>::block_number(), Error::<T>::InvalidUnlockBlock);
ensure!(
unlock_block > frame_system::Pallet::<T>::block_number(),
Error::<T>::InvalidUnlockBlock
);
// Possibly this is worse than having the caller account be the payment account?
UnlockBlock::<T>::set(unlock_block);
Self::deposit_event(Event::<T>::UnlockBlockUpdated(unlock_block));
@@ -392,7 +431,8 @@ impl<T: Config> Pallet<T> {
// This function converts a 32 byte AccountId to its byte-array equivalent form.
fn account_to_bytes<AccountId>(account: &AccountId) -> Result<[u8; 32], DispatchError>
where AccountId: Encode,
where
AccountId: Encode,
{
let account_vec = account.encode();
ensure!(account_vec.len() == 32, "AccountId must be 32 bytes.");
@@ -404,7 +444,8 @@ fn account_to_bytes<AccountId>(account: &AccountId) -> Result<[u8; 32], Dispatch
/// WARNING: Executing this function will clear all storage used by this pallet.
/// Be sure this is what you want...
pub fn remove_pallet<T>() -> frame_support::weights::Weight
where T: frame_system::Config
where
T: frame_system::Config,
{
use frame_support::migration::remove_storage_prefix;
remove_storage_prefix(b"Purchase", b"Accounts", b"");
@@ -419,21 +460,20 @@ pub fn remove_pallet<T>() -> frame_support::weights::Weight
mod tests {
use super::*;
use sp_core::{H256, Pair, Public, crypto::AccountId32, ed25519};
use sp_core::{crypto::AccountId32, ed25519, Pair, Public, H256};
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
use sp_runtime::{
MultiSignature,
traits::{BlakeTwo256, IdentityLookup, Identity, Verify, IdentifyAccount, Dispatchable},
testing::Header
};
use frame_support::{
assert_ok, assert_noop, parameter_types,
ord_parameter_types, dispatch::DispatchError::BadOrigin,
};
use frame_support::traits::Currency;
use pallet_balances::Error as BalancesError;
use crate::purchase;
use frame_support::{
assert_noop, assert_ok, dispatch::DispatchError::BadOrigin, ord_parameter_types,
parameter_types, traits::Currency,
};
use pallet_balances::Error as BalancesError;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, Dispatchable, IdentifyAccount, Identity, IdentityLookup, Verify},
MultiSignature,
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -547,7 +587,8 @@ mod tests {
let unlock_block = 100;
Purchase::set_statement(Origin::signed(configuration_origin()), statement).unwrap();
Purchase::set_unlock_block(Origin::signed(configuration_origin()), unlock_block).unwrap();
Purchase::set_payment_account(Origin::signed(configuration_origin()), payment_account()).unwrap();
Purchase::set_payment_account(Origin::signed(configuration_origin()), payment_account())
.unwrap();
Balances::make_free_balance_be(&payment_account(), 100_000);
}
@@ -561,8 +602,9 @@ mod tests {
}
/// Helper function to generate an account ID from seed
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
AccountPublic: From<<TPublic::Pair as Pair>::Public>
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
@@ -622,7 +664,10 @@ mod tests {
Error::<Test>::InvalidStatement,
);
// Just right...
assert_ok!(Purchase::set_statement(Origin::signed(configuration_origin()), statement.clone()));
assert_ok!(Purchase::set_statement(
Origin::signed(configuration_origin()),
statement.clone()
));
assert_eq!(Statement::<Test>::get(), statement);
});
}
@@ -640,11 +685,17 @@ mod tests {
let bad_unlock_block = 50;
System::set_block_number(bad_unlock_block);
assert_noop!(
Purchase::set_unlock_block(Origin::signed(configuration_origin()), bad_unlock_block),
Purchase::set_unlock_block(
Origin::signed(configuration_origin()),
bad_unlock_block
),
Error::<Test>::InvalidUnlockBlock,
);
// Just right...
assert_ok!(Purchase::set_unlock_block(Origin::signed(configuration_origin()), unlock_block));
assert_ok!(Purchase::set_unlock_block(
Origin::signed(configuration_origin()),
unlock_block
));
assert_eq!(UnlockBlock::<Test>::get(), unlock_block);
});
}
@@ -659,7 +710,10 @@ mod tests {
BadOrigin,
);
// Just right...
assert_ok!(Purchase::set_payment_account(Origin::signed(configuration_origin()), payment_account.clone()));
assert_ok!(Purchase::set_payment_account(
Origin::signed(configuration_origin()),
payment_account.clone()
));
assert_eq!(PaymentAccount::<Test>::get(), payment_account);
});
}
@@ -672,8 +726,14 @@ mod tests {
assert_ok!(Purchase::verify_signature(&bob(), &bob_signature()));
// Mixing and matching fails
assert_noop!(Purchase::verify_signature(&alice(), &bob_signature()), Error::<Test>::InvalidSignature);
assert_noop!(Purchase::verify_signature(&bob(), &alice_signature()), Error::<Test>::InvalidSignature);
assert_noop!(
Purchase::verify_signature(&alice(), &bob_signature()),
Error::<Test>::InvalidSignature
);
assert_noop!(
Purchase::verify_signature(&bob(), &alice_signature()),
Error::<Test>::InvalidSignature
);
});
}
@@ -704,13 +764,21 @@ mod tests {
new_test_ext().execute_with(|| {
// Wrong Origin
assert_noop!(
Purchase::create_account(Origin::signed(alice()), alice(), alice_signature().to_vec()),
Purchase::create_account(
Origin::signed(alice()),
alice(),
alice_signature().to_vec()
),
BadOrigin,
);
// Wrong Account/Signature
assert_noop!(
Purchase::create_account(Origin::signed(validity_origin()), alice(), bob_signature().to_vec()),
Purchase::create_account(
Origin::signed(validity_origin()),
alice(),
bob_signature().to_vec()
),
Error::<Test>::InvalidSignature,
);
@@ -722,16 +790,26 @@ mod tests {
50
));
assert_noop!(
Purchase::create_account(Origin::signed(validity_origin()), alice(), alice_signature().to_vec()),
Purchase::create_account(
Origin::signed(validity_origin()),
alice(),
alice_signature().to_vec()
),
Error::<Test>::VestingScheduleExists,
);
// Duplicate Purchasing Account
assert_ok!(
Purchase::create_account(Origin::signed(validity_origin()), bob(), bob_signature().to_vec())
);
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
bob(),
bob_signature().to_vec()
));
assert_noop!(
Purchase::create_account(Origin::signed(validity_origin()), bob(), bob_signature().to_vec()),
Purchase::create_account(
Origin::signed(validity_origin()),
bob(),
bob_signature().to_vec()
),
Error::<Test>::ExistingAccount,
);
});
@@ -791,17 +869,23 @@ mod tests {
fn update_validity_status_handles_basic_errors() {
new_test_ext().execute_with(|| {
// Wrong Origin
assert_noop!(Purchase::update_validity_status(
Origin::signed(alice()),
alice(),
AccountValidity::Pending,
), BadOrigin);
assert_noop!(
Purchase::update_validity_status(
Origin::signed(alice()),
alice(),
AccountValidity::Pending,
),
BadOrigin
);
// Inactive Account
assert_noop!(Purchase::update_validity_status(
Origin::signed(validity_origin()),
alice(),
AccountValidity::Pending,
), Error::<Test>::InvalidAccount);
assert_noop!(
Purchase::update_validity_status(
Origin::signed(validity_origin()),
alice(),
AccountValidity::Pending,
),
Error::<Test>::InvalidAccount
);
// Already Completed
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
@@ -813,11 +897,14 @@ mod tests {
alice(),
AccountValidity::Completed,
));
assert_noop!(Purchase::update_validity_status(
Origin::signed(validity_origin()),
alice(),
AccountValidity::Pending,
), Error::<Test>::AlreadyCompleted);
assert_noop!(
Purchase::update_validity_status(
Origin::signed(validity_origin()),
alice(),
AccountValidity::Pending,
),
Error::<Test>::AlreadyCompleted
);
});
}
@@ -828,8 +915,8 @@ mod tests {
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
alice(),
alice_signature().to_vec())
);
alice_signature().to_vec()
));
// And approved for basic contribution
assert_ok!(Purchase::update_validity_status(
Origin::signed(validity_origin()),
@@ -879,29 +966,32 @@ mod tests {
fn update_balance_handles_basic_errors() {
new_test_ext().execute_with(|| {
// Wrong Origin
assert_noop!(Purchase::update_balance(
Origin::signed(alice()),
alice(),
50,
50,
Permill::zero(),
), BadOrigin);
assert_noop!(
Purchase::update_balance(Origin::signed(alice()), alice(), 50, 50, Permill::zero(),),
BadOrigin
);
// Inactive Account
assert_noop!(Purchase::update_balance(
Origin::signed(validity_origin()),
alice(),
50,
50,
Permill::zero(),
), Error::<Test>::InvalidAccount);
assert_noop!(
Purchase::update_balance(
Origin::signed(validity_origin()),
alice(),
50,
50,
Permill::zero(),
),
Error::<Test>::InvalidAccount
);
// Overflow
assert_noop!(Purchase::update_balance(
Origin::signed(validity_origin()),
alice(),
u64::MAX,
u64::MAX,
Permill::zero(),
), Error::<Test>::InvalidAccount);
assert_noop!(
Purchase::update_balance(
Origin::signed(validity_origin()),
alice(),
u64::MAX,
u64::MAX,
Permill::zero(),
),
Error::<Test>::InvalidAccount
);
});
}
@@ -912,13 +1002,13 @@ mod tests {
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
alice(),
alice_signature().to_vec())
);
alice_signature().to_vec()
));
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
bob(),
bob_signature().to_vec())
);
bob_signature().to_vec()
));
// Alice is approved for basic contribution
assert_ok!(Purchase::update_validity_status(
Origin::signed(validity_origin()),
@@ -947,14 +1037,8 @@ mod tests {
Permill::zero(),
));
// Now we call payout for Alice and Bob.
assert_ok!(Purchase::payout(
Origin::signed(payment_account()),
alice(),
));
assert_ok!(Purchase::payout(
Origin::signed(payment_account()),
bob(),
));
assert_ok!(Purchase::payout(Origin::signed(payment_account()), alice(),));
assert_ok!(Purchase::payout(Origin::signed(payment_account()), bob(),));
// Payment is made.
assert_eq!(<Test as Config>::Currency::free_balance(&payment_account()), 99_650);
assert_eq!(<Test as Config>::Currency::free_balance(&alice()), 100);
@@ -1003,33 +1087,30 @@ mod tests {
fn payout_handles_basic_errors() {
new_test_ext().execute_with(|| {
// Wrong Origin
assert_noop!(Purchase::payout(
Origin::signed(alice()),
alice(),
), BadOrigin);
assert_noop!(Purchase::payout(Origin::signed(alice()), alice(),), BadOrigin);
// Account with Existing Vesting Schedule
assert_ok!(<Test as Config>::VestingSchedule::add_vesting_schedule(
&bob(), 100, 1, 50,
));
assert_noop!(Purchase::payout(
Origin::signed(payment_account()),
bob(),
), Error::<Test>::VestingScheduleExists);
assert_ok!(
<Test as Config>::VestingSchedule::add_vesting_schedule(&bob(), 100, 1, 50,)
);
assert_noop!(
Purchase::payout(Origin::signed(payment_account()), bob(),),
Error::<Test>::VestingScheduleExists
);
// Invalid Account (never created)
assert_noop!(Purchase::payout(
Origin::signed(payment_account()),
alice(),
), Error::<Test>::InvalidAccount);
assert_noop!(
Purchase::payout(Origin::signed(payment_account()), alice(),),
Error::<Test>::InvalidAccount
);
// Invalid Account (created, but not valid)
assert_ok!(Purchase::create_account(
Origin::signed(validity_origin()),
alice(),
alice_signature().to_vec())
alice_signature().to_vec()
));
assert_noop!(
Purchase::payout(Origin::signed(payment_account()), alice(),),
Error::<Test>::InvalidAccount
);
assert_noop!(Purchase::payout(
Origin::signed(payment_account()),
alice(),
), Error::<Test>::InvalidAccount);
// Not enough funds in payment account
assert_ok!(Purchase::update_validity_status(
Origin::signed(validity_origin()),
@@ -1043,10 +1124,10 @@ mod tests {
100_000,
Permill::zero(),
));
assert_noop!(Purchase::payout(
Origin::signed(payment_account()),
alice(),
), BalancesError::<Test, _>::InsufficientBalance);
assert_noop!(
Purchase::payout(Origin::signed(payment_account()), alice(),),
BalancesError::<Test, _>::InsufficientBalance
);
});
}
+10 -1
View File
@@ -17,7 +17,16 @@
//! The `SlotRange` struct which succinctly handles the 36 values that
//! represent all sub ranges between 0 and 7 inclusive.
slot_range_helper::generate_slot_range!(Zero(0), One(1), Two(2), Three(3), Four(4), Five(5), Six(6), Seven(7));
slot_range_helper::generate_slot_range!(
Zero(0),
One(1),
Two(2),
Three(3),
Four(4),
Five(5),
Six(6),
Seven(7)
);
// Will generate:
// pub enum SlotRange {
+10 -14
View File
@@ -209,9 +209,7 @@ pub mod pallet {
// We can try to onboard it.
Some(Some(_lease_info)) => T::Registrar::make_parachain(para)?,
// Otherwise, it does not have a lease.
Some(None) | None => {
return Err(Error::<T>::ParaNotOnboarding.into());
}
Some(None) | None => return Err(Error::<T>::ParaNotOnboarding.into()),
};
Ok(())
}
@@ -232,7 +230,7 @@ impl<T: Config> Pallet<T> {
let mut parachains = Vec::new();
for (para, mut lease_periods) in Leases::<T>::iter() {
if lease_periods.is_empty() {
continue;
continue
}
// ^^ should never be empty since we would have deleted the entry otherwise.
@@ -307,16 +305,15 @@ impl<T: Config> Pallet<T> {
let mut tracker = sp_std::collections::btree_map::BTreeMap::new();
Leases::<T>::get(para).into_iter().for_each(|lease| match lease {
Some((who, amount)) => match tracker.get(&who) {
Some(prev_amount) => {
Some(prev_amount) =>
if amount > *prev_amount {
tracker.insert(who, amount);
}
}
},
None => {
tracker.insert(who, amount);
}
},
},
None => {}
None => {},
});
tracker.into_iter().collect()
@@ -375,7 +372,7 @@ impl<T: Config> Leaser for Pallet<T> {
// attempt.
//
// We bail, not giving any lease and leave it for governance to sort out.
return Err(LeaseError::AlreadyLeased);
return Err(LeaseError::AlreadyLeased)
}
} else if d.len() == i {
// Doesn't exist. This is usual.
@@ -423,13 +420,12 @@ impl<T: Config> Leaser for Pallet<T> {
Leases::<T>::get(para)
.into_iter()
.map(|lease| match lease {
Some((who, amount)) => {
Some((who, amount)) =>
if &who == leaser {
amount
} else {
Zero::zero()
}
}
},
None => Zero::zero(),
})
.max()
@@ -471,7 +467,7 @@ impl<T: Config> Leaser for Pallet<T> {
for slot in offset..=offset + period_count {
if let Some(Some(_)) = leases.get(slot) {
// If there exists any lease period, we exit early and return true.
return true;
return true
}
}
+11 -5
View File
@@ -16,12 +16,12 @@
//! Traits used across pallets for Polkadot.
use sp_std::vec::*;
use primitives::v1::{HeadData, ValidationCode, Id as ParaId};
use frame_support::{
dispatch::DispatchResult,
traits::{Currency, ReservableCurrency},
};
use primitives::v1::{HeadData, Id as ParaId, ValidationCode};
use sp_std::vec::*;
/// Parachain registration API.
pub trait Registrar {
@@ -128,7 +128,10 @@ pub trait Leaser {
/// Return the amount of balance currently held in reserve on `leaser`'s account for leasing `para`. This won't
/// go down outside of a lease period.
fn deposit_held(para: ParaId, leaser: &Self::AccountId) -> <Self::Currency as Currency<Self::AccountId>>::Balance;
fn deposit_held(
para: ParaId,
leaser: &Self::AccountId,
) -> <Self::Currency as Currency<Self::AccountId>>::Balance;
/// The lease period. This is constant, but can't be a `const` due to it being a runtime configurable quantity.
fn lease_period() -> Self::LeasePeriod;
@@ -141,7 +144,7 @@ pub trait Leaser {
fn already_leased(
para_id: ParaId,
first_period: Self::LeasePeriod,
last_period: Self::LeasePeriod
last_period: Self::LeasePeriod,
) -> bool;
}
@@ -204,7 +207,10 @@ pub trait Auctioneer {
/// This can only happen when there isn't already an auction in progress. Accepts the `duration`
/// of this auction and the `lease_period_index` of the initial lease period of the four that
/// are to be auctioned.
fn new_auction(duration: Self::BlockNumber, lease_period_index: Self::LeasePeriod) -> DispatchResult;
fn new_auction(
duration: Self::BlockNumber,
lease_period_index: Self::LeasePeriod,
) -> DispatchResult;
/// Given the current block number, return the current auction status.
fn auction_status(now: Self::BlockNumber) -> AuctionStatus<Self::BlockNumber>;
+8 -4
View File
@@ -17,9 +17,12 @@
//! XCM sender for relay chain.
use parity_scale_codec::Encode;
use sp_std::marker::PhantomData;
use xcm::opaque::{VersionedXcm, v0::{SendXcm, MultiLocation, Junction, Xcm, Result, Error}};
use runtime_parachains::{configuration, dmp};
use sp_std::marker::PhantomData;
use xcm::opaque::{
v0::{Error, Junction, MultiLocation, Result, SendXcm, Xcm},
VersionedXcm,
};
/// XCM sender for relay chain. It only sends downward message.
pub struct ChildParachainRouter<T>(PhantomData<T>);
@@ -34,9 +37,10 @@ impl<T: configuration::Config + dmp::Config> SendXcm for ChildParachainRouter<T>
&config,
id.into(),
VersionedXcm::from(msg).encode(),
).map_err(Into::<Error>::into)?;
)
.map_err(Into::<Error>::into)?;
Ok(())
}
},
d => Err(Error::CannotReachDestination(d, msg)),
}
}