mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 09:21:04 +00:00
Use decl_error in common runtime modules (#796)
* use decl_error in common runtime modules * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
5621c18632
commit
f50d0c6505
@@ -21,7 +21,9 @@
|
|||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use frame_support::{decl_storage, decl_module, ensure, dispatch::DispatchResult, traits::Get};
|
use frame_support::{
|
||||||
|
decl_storage, decl_module, decl_error, ensure, dispatch::DispatchResult, traits::Get
|
||||||
|
};
|
||||||
|
|
||||||
use primitives::{Hash, parachain::{AttestedCandidate, CandidateReceipt, Id as ParaId}};
|
use primitives::{Hash, parachain::{AttestedCandidate, CandidateReceipt, Id as ParaId}};
|
||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
@@ -106,13 +108,22 @@ decl_storage! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// More attestations can be added only once in a block.
|
||||||
|
TooManyAttestations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
/// Parachain-attestations module.
|
/// Parachain-attestations module.
|
||||||
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
/// Provide candidate receipts for parachains, in ascending order by id.
|
/// Provide candidate receipts for parachains, in ascending order by id.
|
||||||
fn more_attestations(origin, _more: MoreAttestations) -> DispatchResult {
|
fn more_attestations(origin, _more: MoreAttestations) -> DispatchResult {
|
||||||
ensure_none(origin)?;
|
ensure_none(origin)?;
|
||||||
ensure!(!<DidUpdate>::exists(), "More attestations can be added only once in a block.");
|
ensure!(!<DidUpdate>::exists(), Error::<T>::TooManyAttestations);
|
||||||
<DidUpdate>::put(true);
|
<DidUpdate>::put(true);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
use sp_io::{hashing::keccak_256, crypto::secp256k1_ecdsa_recover};
|
use sp_io::{hashing::keccak_256, crypto::secp256k1_ecdsa_recover};
|
||||||
use frame_support::{decl_event, decl_storage, decl_module};
|
use frame_support::{decl_event, decl_storage, decl_module, decl_error};
|
||||||
use frame_support::weights::SimpleDispatchInfo;
|
use frame_support::weights::SimpleDispatchInfo;
|
||||||
use frame_support::traits::{Currency, Get, VestingCurrency};
|
use frame_support::traits::{Currency, Get, VestingCurrency};
|
||||||
use system::{ensure_root, ensure_none};
|
use system::{ensure_root, ensure_none};
|
||||||
@@ -102,6 +102,15 @@ decl_event!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// Invalid Ethereum signature.
|
||||||
|
InvalidEthereumSignature,
|
||||||
|
/// Ethereum address has no claim.
|
||||||
|
SignerHasNoClaim,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_storage! {
|
decl_storage! {
|
||||||
// A macro for the Storage trait, and its implementation, for this module.
|
// A macro for the Storage trait, and its implementation, for this module.
|
||||||
// This allows for type-safe usage of the Substrate storage database, so you can
|
// This allows for type-safe usage of the Substrate storage database, so you can
|
||||||
@@ -126,6 +135,8 @@ decl_storage! {
|
|||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
/// The Prefix that is used in signed Ethereum messages for this network
|
/// The Prefix that is used in signed Ethereum messages for this network
|
||||||
const Prefix: &[u8] = T::Prefix::get();
|
const Prefix: &[u8] = T::Prefix::get();
|
||||||
|
|
||||||
@@ -139,10 +150,10 @@ decl_module! {
|
|||||||
|
|
||||||
let data = dest.using_encoded(to_ascii_hex);
|
let data = dest.using_encoded(to_ascii_hex);
|
||||||
let signer = Self::eth_recover(ðereum_signature, &data)
|
let signer = Self::eth_recover(ðereum_signature, &data)
|
||||||
.ok_or("Invalid Ethereum signature")?;
|
.ok_or(Error::<T>::InvalidEthereumSignature)?;
|
||||||
|
|
||||||
let balance_due = <Claims<T>>::get(&signer)
|
let balance_due = <Claims<T>>::get(&signer)
|
||||||
.ok_or("Ethereum address has no claim")?;
|
.ok_or(Error::<T>::SignerHasNoClaim)?;
|
||||||
|
|
||||||
// Check if this claim should have a vesting schedule.
|
// Check if this claim should have a vesting schedule.
|
||||||
if let Some(vs) = <Vesting<T>>::get(&signer) {
|
if let Some(vs) = <Vesting<T>>::get(&signer) {
|
||||||
@@ -415,7 +426,7 @@ mod tests {
|
|||||||
assert_eq!(Balances::free_balance(&42), 0);
|
assert_eq!(Balances::free_balance(&42), 0);
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())),
|
Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())),
|
||||||
"Ethereum address has no claim"
|
Error::<Test>::SignerHasNoClaim
|
||||||
);
|
);
|
||||||
assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, None));
|
assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, None));
|
||||||
assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())));
|
assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())));
|
||||||
@@ -434,7 +445,7 @@ mod tests {
|
|||||||
assert_eq!(Balances::free_balance(&42), 0);
|
assert_eq!(Balances::free_balance(&42), 0);
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())),
|
Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())),
|
||||||
"Ethereum address has no claim"
|
Error::<Test>::SignerHasNoClaim
|
||||||
);
|
);
|
||||||
assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, Some((50, 10, 1))));
|
assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, Some((50, 10, 1))));
|
||||||
assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())));
|
assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())));
|
||||||
@@ -459,7 +470,10 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
assert_eq!(Balances::free_balance(&42), 0);
|
assert_eq!(Balances::free_balance(&42), 0);
|
||||||
assert_ok!(Claims::claim(Origin::NONE, 42, sig(&alice(), &42u64.encode())));
|
assert_ok!(Claims::claim(Origin::NONE, 42, sig(&alice(), &42u64.encode())));
|
||||||
assert_noop!(Claims::claim(Origin::NONE, 42, sig(&alice(), &42u64.encode())), "Ethereum address has no claim");
|
assert_noop!(
|
||||||
|
Claims::claim(Origin::NONE, 42, sig(&alice(), &42u64.encode())),
|
||||||
|
Error::<Test>::SignerHasNoClaim
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +481,10 @@ mod tests {
|
|||||||
fn non_sender_sig_doesnt_work() {
|
fn non_sender_sig_doesnt_work() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
assert_eq!(Balances::free_balance(&42), 0);
|
assert_eq!(Balances::free_balance(&42), 0);
|
||||||
assert_noop!(Claims::claim(Origin::NONE, 42, sig(&alice(), &69u64.encode())), "Ethereum address has no claim");
|
assert_noop!(
|
||||||
|
Claims::claim(Origin::NONE, 42, sig(&alice(), &69u64.encode())),
|
||||||
|
Error::<Test>::SignerHasNoClaim
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +492,10 @@ mod tests {
|
|||||||
fn non_claimant_doesnt_work() {
|
fn non_claimant_doesnt_work() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
assert_eq!(Balances::free_balance(&42), 0);
|
assert_eq!(Balances::free_balance(&42), 0);
|
||||||
assert_noop!(Claims::claim(Origin::NONE, 42, sig(&bob(), &69u64.encode())), "Ethereum address has no claim");
|
assert_noop!(
|
||||||
|
Claims::claim(Origin::NONE, 42, sig(&bob(), &69u64.encode())),
|
||||||
|
Error::<Test>::SignerHasNoClaim
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
//! funds ultimately end up in module's fund sub-account.
|
//! funds ultimately end up in module's fund sub-account.
|
||||||
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_module, decl_storage, decl_event, storage::child, ensure, traits::{
|
decl_module, decl_storage, decl_event, decl_error, storage::child, ensure, traits::{
|
||||||
Currency, Get, OnUnbalanced, WithdrawReason, ExistenceRequirement::AllowDeath
|
Currency, Get, OnUnbalanced, WithdrawReason, ExistenceRequirement::AllowDeath
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -187,8 +187,56 @@ decl_event! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// Last slot must be greater than first slot.
|
||||||
|
LastSlotBeforeFirstSlot,
|
||||||
|
/// The last slot cannot be more then 3 slots after the first slot.
|
||||||
|
LastSlotTooFarInFuture,
|
||||||
|
/// The campaign ends before the current block number. The end must be in the future.
|
||||||
|
CannotEndInPast,
|
||||||
|
/// There was an overflow.
|
||||||
|
Overflow,
|
||||||
|
/// The contribution was below the minimum, `MinContribution`.
|
||||||
|
ContributionTooSmall,
|
||||||
|
/// Invalid fund index.
|
||||||
|
InvalidFundIndex,
|
||||||
|
/// Contributions exceed maximum amount.
|
||||||
|
CapExceeded,
|
||||||
|
/// The contribution period has already ended.
|
||||||
|
ContributionPeriodOver,
|
||||||
|
/// The origin of this call is invalid.
|
||||||
|
InvalidOrigin,
|
||||||
|
/// Deployment data for a fund can only be set once. The deployment data for this fund
|
||||||
|
/// already exists.
|
||||||
|
ExistingDeployData,
|
||||||
|
/// Deployment data has not been set for this fund.
|
||||||
|
UnsetDeployData,
|
||||||
|
/// This fund has already been onboarded.
|
||||||
|
AlreadyOnboard,
|
||||||
|
/// This crowdfund does not correspond to a parachain.
|
||||||
|
NotParachain,
|
||||||
|
/// This parachain still has its deposit. Implies that it has already been offboarded.
|
||||||
|
ParaHasDeposit,
|
||||||
|
/// Funds have not yet been returned.
|
||||||
|
FundsNotReturned,
|
||||||
|
/// Fund has not yet retired.
|
||||||
|
FundNotRetired,
|
||||||
|
/// The crowdfund has not yet ended.
|
||||||
|
FundNotEnded,
|
||||||
|
/// There are no contributions stored in this crowdfund.
|
||||||
|
NoContributions,
|
||||||
|
/// This crowdfund has an active parachain and cannot be dissolved.
|
||||||
|
HasActiveParachain,
|
||||||
|
/// The retirement period has not ended.
|
||||||
|
InRetirementPeriod,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
fn deposit_event() = default;
|
fn deposit_event() = default;
|
||||||
|
|
||||||
/// Create a new crowdfunding campaign for a parachain slot deposit for the current auction.
|
/// Create a new crowdfunding campaign for a parachain slot deposit for the current auction.
|
||||||
@@ -201,16 +249,16 @@ decl_module! {
|
|||||||
) {
|
) {
|
||||||
let owner = ensure_signed(origin)?;
|
let owner = ensure_signed(origin)?;
|
||||||
|
|
||||||
ensure!(first_slot < last_slot, "last slot must be greater than first slot");
|
ensure!(first_slot < last_slot, Error::<T>::LastSlotBeforeFirstSlot);
|
||||||
ensure!(last_slot <= first_slot + 3.into(), "last slot cannot be more then 3 more than first slot");
|
ensure!(last_slot <= first_slot + 3.into(), Error::<T>::LastSlotTooFarInFuture);
|
||||||
ensure!(end > <system::Module<T>>::block_number(), "end must be in the future");
|
ensure!(end > <system::Module<T>>::block_number(), Error::<T>::CannotEndInPast);
|
||||||
|
|
||||||
let deposit = T::SubmissionDeposit::get();
|
let deposit = T::SubmissionDeposit::get();
|
||||||
let transfer = WithdrawReason::Transfer.into();
|
let transfer = WithdrawReason::Transfer.into();
|
||||||
let imb = T::Currency::withdraw(&owner, deposit, transfer, AllowDeath)?;
|
let imb = T::Currency::withdraw(&owner, deposit, transfer, AllowDeath)?;
|
||||||
|
|
||||||
let index = FundCount::get();
|
let index = FundCount::get();
|
||||||
let next_index = index.checked_add(1).ok_or("overflow when adding fund")?;
|
let next_index = index.checked_add(1).ok_or(Error::<T>::Overflow)?;
|
||||||
FundCount::put(next_index);
|
FundCount::put(next_index);
|
||||||
|
|
||||||
// No fees are paid here if we need to create this account; that's why we don't just
|
// No fees are paid here if we need to create this account; that's why we don't just
|
||||||
@@ -239,14 +287,14 @@ decl_module! {
|
|||||||
fn contribute(origin, #[compact] index: FundIndex, #[compact] value: BalanceOf<T>) {
|
fn contribute(origin, #[compact] index: FundIndex, #[compact] value: BalanceOf<T>) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
|
|
||||||
ensure!(value >= T::MinContribution::get(), "contribution too small");
|
ensure!(value >= T::MinContribution::get(), Error::<T>::ContributionTooSmall);
|
||||||
let mut fund = Self::funds(index).ok_or("invalid fund index")?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
fund.raised = fund.raised.checked_add(&value).ok_or("overflow when adding new funds")?;
|
fund.raised = fund.raised.checked_add(&value).ok_or(Error::<T>::Overflow)?;
|
||||||
ensure!(fund.raised <= fund.cap, "contributions exceed cap");
|
ensure!(fund.raised <= fund.cap, Error::<T>::CapExceeded);
|
||||||
|
|
||||||
// Make sure crowdfund has not ended
|
// Make sure crowdfund has not ended
|
||||||
let now = <system::Module<T>>::block_number();
|
let now = <system::Module<T>>::block_number();
|
||||||
ensure!(fund.end > now, "contribution period ended");
|
ensure!(fund.end > now, Error::<T>::ContributionPeriodOver);
|
||||||
|
|
||||||
T::Currency::transfer(&who, &Self::fund_account_id(index), value, AllowDeath)?;
|
T::Currency::transfer(&who, &Self::fund_account_id(index), value, AllowDeath)?;
|
||||||
|
|
||||||
@@ -301,9 +349,9 @@ decl_module! {
|
|||||||
) {
|
) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
|
|
||||||
let mut fund = Self::funds(index).ok_or("invalid fund index")?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
ensure!(fund.owner == who, "origin must be fund owner");
|
ensure!(fund.owner == who, Error::<T>::InvalidOrigin); // must be fund owner
|
||||||
ensure!(fund.deploy_data.is_none(), "deploy data already set");
|
ensure!(fund.deploy_data.is_none(), Error::<T>::ExistingDeployData);
|
||||||
|
|
||||||
fund.deploy_data = Some((code_hash, initial_head_data));
|
fund.deploy_data = Some((code_hash, initial_head_data));
|
||||||
|
|
||||||
@@ -324,9 +372,9 @@ decl_module! {
|
|||||||
) {
|
) {
|
||||||
let _ = ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
let mut fund = Self::funds(index).ok_or("invalid fund index")?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
let (code_hash, initial_head_data) = fund.clone().deploy_data.ok_or("deploy data not fixed")?;
|
let (code_hash, initial_head_data) = fund.clone().deploy_data.ok_or(Error::<T>::UnsetDeployData)?;
|
||||||
ensure!(fund.parachain.is_none(), "fund already onboarded");
|
ensure!(fund.parachain.is_none(), Error::<T>::AlreadyOnboard);
|
||||||
fund.parachain = Some(para_id);
|
fund.parachain = Some(para_id);
|
||||||
|
|
||||||
let fund_origin = system::RawOrigin::Signed(Self::fund_account_id(index)).into();
|
let fund_origin = system::RawOrigin::Signed(Self::fund_account_id(index)).into();
|
||||||
@@ -341,13 +389,13 @@ decl_module! {
|
|||||||
fn begin_retirement(origin, #[compact] index: FundIndex) {
|
fn begin_retirement(origin, #[compact] index: FundIndex) {
|
||||||
let _ = ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
let mut fund = Self::funds(index).ok_or("invalid fund index")?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
let parachain_id = fund.parachain.take().ok_or("fund has no parachain")?;
|
let parachain_id = fund.parachain.take().ok_or(Error::<T>::NotParachain)?;
|
||||||
// No deposit information implies the parachain was off-boarded
|
// No deposit information implies the parachain was off-boarded
|
||||||
ensure!(<slots::Module<T>>::deposits(parachain_id).len() == 0, "parachain still has deposit");
|
ensure!(<slots::Module<T>>::deposits(parachain_id).len() == 0, Error::<T>::ParaHasDeposit);
|
||||||
let account = Self::fund_account_id(index);
|
let account = Self::fund_account_id(index);
|
||||||
// Funds should be returned at the end of off-boarding
|
// Funds should be returned at the end of off-boarding
|
||||||
ensure!(T::Currency::free_balance(&account) >= fund.raised, "funds not yet returned");
|
ensure!(T::Currency::free_balance(&account) >= fund.raised, Error::<T>::FundsNotReturned);
|
||||||
|
|
||||||
// This fund just ended. Withdrawal period begins.
|
// This fund just ended. Withdrawal period begins.
|
||||||
let now = <system::Module<T>>::block_number();
|
let now = <system::Module<T>>::block_number();
|
||||||
@@ -362,15 +410,15 @@ decl_module! {
|
|||||||
fn withdraw(origin, #[compact] index: FundIndex) {
|
fn withdraw(origin, #[compact] index: FundIndex) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
|
|
||||||
let mut fund = Self::funds(index).ok_or("invalid fund index")?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
ensure!(fund.parachain.is_none(), "fund has not retired");
|
ensure!(fund.parachain.is_none(), Error::<T>::FundNotRetired);
|
||||||
let now = <system::Module<T>>::block_number();
|
let now = <system::Module<T>>::block_number();
|
||||||
|
|
||||||
// `fund.end` can represent the end of a failed crowdsale or the beginning of retirement
|
// `fund.end` can represent the end of a failed crowdsale or the beginning of retirement
|
||||||
ensure!(now >= fund.end, "fund has not ended");
|
ensure!(now >= fund.end, Error::<T>::FundNotEnded);
|
||||||
|
|
||||||
let balance = Self::contribution_get(index, &who);
|
let balance = Self::contribution_get(index, &who);
|
||||||
ensure!(balance > Zero::zero(), "no contributions stored");
|
ensure!(balance > Zero::zero(), Error::<T>::NoContributions);
|
||||||
|
|
||||||
// Avoid using transfer to ensure we don't pay any fees.
|
// Avoid using transfer to ensure we don't pay any fees.
|
||||||
let fund_account = &Self::fund_account_id(index);
|
let fund_account = &Self::fund_account_id(index);
|
||||||
@@ -392,12 +440,12 @@ decl_module! {
|
|||||||
fn dissolve(origin, #[compact] index: FundIndex) {
|
fn dissolve(origin, #[compact] index: FundIndex) {
|
||||||
let _ = ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
let fund = Self::funds(index).ok_or("invalid fund index")?;
|
let fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
ensure!(fund.parachain.is_none(), "cannot dissolve fund with active parachain");
|
ensure!(fund.parachain.is_none(), Error::<T>::HasActiveParachain);
|
||||||
let now = <system::Module<T>>::block_number();
|
let now = <system::Module<T>>::block_number();
|
||||||
ensure!(
|
ensure!(
|
||||||
now >= fund.end.saturating_add(T::RetirementPeriod::get()),
|
now >= fund.end.saturating_add(T::RetirementPeriod::get()),
|
||||||
"retirement period not over"
|
Error::<T>::InRetirementPeriod
|
||||||
);
|
);
|
||||||
|
|
||||||
let account = Self::fund_account_id(index);
|
let account = Self::fund_account_id(index);
|
||||||
@@ -673,6 +721,7 @@ mod tests {
|
|||||||
type Crowdfund = Module<Test>;
|
type Crowdfund = Module<Test>;
|
||||||
type RandomnessCollectiveFlip = randomness_collective_flip::Module<Test>;
|
type RandomnessCollectiveFlip = randomness_collective_flip::Module<Test>;
|
||||||
use balances::Error as BalancesError;
|
use balances::Error as BalancesError;
|
||||||
|
use slots::Error as SlotsError;
|
||||||
|
|
||||||
// This function basically just builds a genesis storage key/value store according to
|
// This function basically just builds a genesis storage key/value store according to
|
||||||
// our desired mockup.
|
// our desired mockup.
|
||||||
@@ -749,11 +798,20 @@ mod tests {
|
|||||||
fn create_handles_basic_errors() {
|
fn create_handles_basic_errors() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Cannot create a crowdfund with bad slots
|
// Cannot create a crowdfund with bad slots
|
||||||
assert_noop!(Crowdfund::create(Origin::signed(1), 1000, 4, 1, 9), "last slot must be greater than first slot");
|
assert_noop!(
|
||||||
assert_noop!(Crowdfund::create(Origin::signed(1), 1000, 1, 5, 9), "last slot cannot be more then 3 more than first slot");
|
Crowdfund::create(Origin::signed(1), 1000, 4, 1, 9),
|
||||||
|
Error::<Test>::LastSlotBeforeFirstSlot
|
||||||
|
);
|
||||||
|
assert_noop!(
|
||||||
|
Crowdfund::create(Origin::signed(1), 1000, 1, 5, 9),
|
||||||
|
Error::<Test>::LastSlotTooFarInFuture
|
||||||
|
);
|
||||||
|
|
||||||
// Cannot create a crowdfund without some deposit funds
|
// Cannot create a crowdfund without some deposit funds
|
||||||
assert_noop!(Crowdfund::create(Origin::signed(1337), 1000, 1, 3, 9), BalancesError::<Test, _>::InsufficientBalance);
|
assert_noop!(
|
||||||
|
Crowdfund::create(Origin::signed(1337), 1000, 1, 3, 9),
|
||||||
|
BalancesError::<Test, _>::InsufficientBalance
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,22 +849,22 @@ mod tests {
|
|||||||
fn contribute_handles_basic_errors() {
|
fn contribute_handles_basic_errors() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Cannot contribute to non-existing fund
|
// Cannot contribute to non-existing fund
|
||||||
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 49), "invalid fund index");
|
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 49), Error::<Test>::InvalidFundIndex);
|
||||||
// Cannot contribute below minimum contribution
|
// Cannot contribute below minimum contribution
|
||||||
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 9), "contribution too small");
|
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 9), Error::<Test>::ContributionTooSmall);
|
||||||
|
|
||||||
// Set up a crowdfund
|
// Set up a crowdfund
|
||||||
assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
|
||||||
assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 101));
|
assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 101));
|
||||||
|
|
||||||
// Cannot contribute past the limit
|
// Cannot contribute past the limit
|
||||||
assert_noop!(Crowdfund::contribute(Origin::signed(2), 0, 900), "contributions exceed cap");
|
assert_noop!(Crowdfund::contribute(Origin::signed(2), 0, 900), Error::<Test>::CapExceeded);
|
||||||
|
|
||||||
// Move past end date
|
// Move past end date
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
// Cannot contribute to ended fund
|
// Cannot contribute to ended fund
|
||||||
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 49), "contribution period ended");
|
assert_noop!(Crowdfund::contribute(Origin::signed(1), 0, 49), Error::<Test>::ContributionPeriodOver);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,7 +903,7 @@ mod tests {
|
|||||||
0,
|
0,
|
||||||
<Test as system::Trait>::Hash::default(),
|
<Test as system::Trait>::Hash::default(),
|
||||||
vec![0]),
|
vec![0]),
|
||||||
"origin must be fund owner"
|
Error::<Test>::InvalidOrigin
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cannot set deploy data to an invalid index
|
// Cannot set deploy data to an invalid index
|
||||||
@@ -854,7 +912,7 @@ mod tests {
|
|||||||
1,
|
1,
|
||||||
<Test as system::Trait>::Hash::default(),
|
<Test as system::Trait>::Hash::default(),
|
||||||
vec![0]),
|
vec![0]),
|
||||||
"invalid fund index"
|
Error::<Test>::InvalidFundIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cannot set deploy data after it already has been set
|
// Cannot set deploy data after it already has been set
|
||||||
@@ -870,7 +928,7 @@ mod tests {
|
|||||||
0,
|
0,
|
||||||
<Test as system::Trait>::Hash::default(),
|
<Test as system::Trait>::Hash::default(),
|
||||||
vec![1]),
|
vec![1]),
|
||||||
"deploy data already set"
|
Error::<Test>::ExistingDeployData
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -924,9 +982,9 @@ mod tests {
|
|||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
// Cannot onboard invalid fund index
|
// Cannot onboard invalid fund index
|
||||||
assert_noop!(Crowdfund::onboard(Origin::signed(1), 1, 0.into()), "invalid fund index");
|
assert_noop!(Crowdfund::onboard(Origin::signed(1), 1, 0.into()), Error::<Test>::InvalidFundIndex);
|
||||||
// Cannot onboard crowdfund without deploy data
|
// Cannot onboard crowdfund without deploy data
|
||||||
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()), "deploy data not fixed");
|
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()), Error::<Test>::UnsetDeployData);
|
||||||
|
|
||||||
// Add deploy data
|
// Add deploy data
|
||||||
assert_ok!(Crowdfund::fix_deploy_data(
|
assert_ok!(Crowdfund::fix_deploy_data(
|
||||||
@@ -937,13 +995,13 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Cannot onboard fund with incorrect parachain id
|
// Cannot onboard fund with incorrect parachain id
|
||||||
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 1.into()), "parachain id not in onboarding");
|
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 1.into()), SlotsError::<Test>::ParaNotOnboarding);
|
||||||
|
|
||||||
// Onboard crowdfund
|
// Onboard crowdfund
|
||||||
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
||||||
|
|
||||||
// Cannot onboard fund again
|
// Cannot onboard fund again
|
||||||
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()), "fund already onboarded");
|
assert_noop!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()), Error::<Test>::AlreadyOnboard);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,7 +1069,7 @@ mod tests {
|
|||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
// Cannot retire fund that is not onboarded
|
// Cannot retire fund that is not onboarded
|
||||||
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), "fund has no parachain");
|
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), Error::<Test>::NotParachain);
|
||||||
|
|
||||||
// Onboard crowdfund
|
// Onboard crowdfund
|
||||||
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
||||||
@@ -1020,16 +1078,16 @@ mod tests {
|
|||||||
assert_eq!(fund.parachain, Some(0.into()));
|
assert_eq!(fund.parachain, Some(0.into()));
|
||||||
|
|
||||||
// Cannot retire fund whose deposit has not been returned
|
// Cannot retire fund whose deposit has not been returned
|
||||||
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), "parachain still has deposit");
|
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), Error::<Test>::ParaHasDeposit);
|
||||||
|
|
||||||
run_to_block(50);
|
run_to_block(50);
|
||||||
|
|
||||||
// Cannot retire invalid fund index
|
// Cannot retire invalid fund index
|
||||||
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 1), "invalid fund index");
|
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 1), Error::<Test>::InvalidFundIndex);
|
||||||
|
|
||||||
// Cannot retire twice
|
// Cannot retire twice
|
||||||
assert_ok!(Crowdfund::begin_retirement(Origin::signed(1), 0));
|
assert_ok!(Crowdfund::begin_retirement(Origin::signed(1), 0));
|
||||||
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), "fund has no parachain");
|
assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), Error::<Test>::NotParachain);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,14 +1130,14 @@ mod tests {
|
|||||||
run_to_block(5);
|
run_to_block(5);
|
||||||
|
|
||||||
// Cannot withdraw before fund ends
|
// Cannot withdraw before fund ends
|
||||||
assert_noop!(Crowdfund::withdraw(Origin::signed(1), 0), "fund has not ended");
|
assert_noop!(Crowdfund::withdraw(Origin::signed(1), 0), Error::<Test>::FundNotEnded);
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
// Cannot withdraw if they did not contribute
|
// Cannot withdraw if they did not contribute
|
||||||
assert_noop!(Crowdfund::withdraw(Origin::signed(2), 0), "no contributions stored");
|
assert_noop!(Crowdfund::withdraw(Origin::signed(2), 0), Error::<Test>::NoContributions);
|
||||||
// Cannot withdraw from a non-existent fund
|
// Cannot withdraw from a non-existent fund
|
||||||
assert_noop!(Crowdfund::withdraw(Origin::signed(1), 1), "invalid fund index");
|
assert_noop!(Crowdfund::withdraw(Origin::signed(1), 1), Error::<Test>::InvalidFundIndex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1130,9 +1188,9 @@ mod tests {
|
|||||||
assert_ok!(Crowdfund::contribute(Origin::signed(3), 0, 300));
|
assert_ok!(Crowdfund::contribute(Origin::signed(3), 0, 300));
|
||||||
|
|
||||||
// Cannot dissolve an invalid fund index
|
// Cannot dissolve an invalid fund index
|
||||||
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 1), "invalid fund index");
|
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 1), Error::<Test>::InvalidFundIndex);
|
||||||
// Cannot dissolve a fund in progress
|
// Cannot dissolve a fund in progress
|
||||||
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), "retirement period not over");
|
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), Error::<Test>::InRetirementPeriod);
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
@@ -1146,7 +1204,7 @@ mod tests {
|
|||||||
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
|
||||||
|
|
||||||
// Cannot dissolve an active fund
|
// Cannot dissolve an active fund
|
||||||
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), "cannot dissolve fund with active parachain");
|
assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), Error::<Test>::HasActiveParachain);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ use primitives::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
Parameter, dispatch::DispatchResult, decl_storage, decl_module, ensure,
|
Parameter, dispatch::DispatchResult, decl_storage, decl_module, decl_error, ensure,
|
||||||
traits::{Currency, Get, WithdrawReason, ExistenceRequirement, Randomness},
|
traits::{Currency, Get, WithdrawReason, ExistenceRequirement, Randomness},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,10 +182,10 @@ decl_storage! {
|
|||||||
/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
|
/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
|
||||||
NeedsDispatch: Vec<ParaId>;
|
NeedsDispatch: Vec<ParaId>;
|
||||||
|
|
||||||
/// Some if the parachain heads get updated in this block, along with the parachain IDs that
|
/// `Some` if the parachain heads get updated in this block, along with the parachain IDs
|
||||||
/// did update. Ordered in the same way as `registrar::Active` (i.e. by ParaId).
|
/// that did update. Ordered in the same way as `registrar::Active` (i.e. by ParaId).
|
||||||
///
|
///
|
||||||
/// None if not yet updated.
|
/// `None` if not yet updated.
|
||||||
pub DidUpdate: Option<Vec<ParaId>>;
|
pub DidUpdate: Option<Vec<ParaId>>;
|
||||||
}
|
}
|
||||||
add_extra_genesis {
|
add_extra_genesis {
|
||||||
@@ -194,19 +194,60 @@ decl_storage! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// Parachain heads must be updated only once in the block.
|
||||||
|
TooManyHeadUpdates,
|
||||||
|
/// Too many parachain candidates.
|
||||||
|
TooManyParaCandidates,
|
||||||
|
/// Proposed heads must be ascending order by parachain ID without duplicate.
|
||||||
|
HeadsOutOfOrder,
|
||||||
|
/// Candidate is for an unregistered parachain.
|
||||||
|
UnregisteredPara,
|
||||||
|
/// Invalid collator.
|
||||||
|
InvalidCollator,
|
||||||
|
/// The message queue is full. Messages will be added when there is space.
|
||||||
|
QueueFull,
|
||||||
|
/// The message origin is invalid.
|
||||||
|
InvalidMessageOrigin,
|
||||||
|
/// Egress routes should be in ascending order by parachain ID without duplicates.
|
||||||
|
EgressOutOfOrder,
|
||||||
|
/// A parachain cannot route a message to itself.
|
||||||
|
SelfAddressed,
|
||||||
|
/// The trie root cannot be empty.
|
||||||
|
EmptyTrieRoot,
|
||||||
|
/// Cannot route to a non-existing parachain.
|
||||||
|
DestinationDoesNotExist,
|
||||||
|
/// No validator group for parachain.
|
||||||
|
NoValidatorGroup,
|
||||||
|
/// Not enough validity votes for candidate.
|
||||||
|
NotEnoughValidityVotes,
|
||||||
|
/// The number of attestations exceeds the number of authorities.
|
||||||
|
VotesExceedsAuthorities,
|
||||||
|
/// Attesting validator not on this chain's validation duty.
|
||||||
|
WrongValidatorAttesting,
|
||||||
|
/// Invalid signature from attester.
|
||||||
|
InvalidSignature,
|
||||||
|
/// Extra untagged validity votes along with candidate.
|
||||||
|
UntaggedVotes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
/// Parachains module.
|
/// Parachains module.
|
||||||
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
/// Provide candidate receipts for parachains, in ascending order by id.
|
/// Provide candidate receipts for parachains, in ascending order by id.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
||||||
pub fn set_heads(origin, heads: Vec<AttestedCandidate>) -> DispatchResult {
|
pub fn set_heads(origin, heads: Vec<AttestedCandidate>) -> DispatchResult {
|
||||||
ensure_none(origin)?;
|
ensure_none(origin)?;
|
||||||
ensure!(!<DidUpdate>::exists(), "Parachain heads must be updated only once in the block");
|
ensure!(!<DidUpdate>::exists(), Error::<T>::TooManyHeadUpdates);
|
||||||
|
|
||||||
let active_parachains = Self::active_parachains();
|
let active_parachains = Self::active_parachains();
|
||||||
|
|
||||||
let parachain_count = active_parachains.len();
|
let parachain_count = active_parachains.len();
|
||||||
ensure!(heads.len() <= parachain_count, "Too many parachain candidates");
|
ensure!(heads.len() <= parachain_count, Error::<T>::TooManyParaCandidates);
|
||||||
|
|
||||||
let mut proceeded = Vec::with_capacity(heads.len());
|
let mut proceeded = Vec::with_capacity(heads.len());
|
||||||
|
|
||||||
@@ -221,15 +262,15 @@ decl_module! {
|
|||||||
// proposed heads must be ascending order by parachain ID without duplicate.
|
// proposed heads must be ascending order by parachain ID without duplicate.
|
||||||
ensure!(
|
ensure!(
|
||||||
last_id.as_ref().map_or(true, |x| x < &id),
|
last_id.as_ref().map_or(true, |x| x < &id),
|
||||||
"candidate out of order"
|
Error::<T>::HeadsOutOfOrder
|
||||||
);
|
);
|
||||||
|
|
||||||
// must be unknown since active parachains are always sorted.
|
// must be unknown since active parachains are always sorted.
|
||||||
let (_, maybe_required_collator) = iter.find(|para| para.0 == id)
|
let (_, maybe_required_collator) = iter.find(|para| para.0 == id)
|
||||||
.ok_or("candidate for unregistered parachain {}")?;
|
.ok_or(Error::<T>::UnregisteredPara)?;
|
||||||
|
|
||||||
if let Some((required_collator, _)) = maybe_required_collator {
|
if let Some((required_collator, _)) = maybe_required_collator {
|
||||||
ensure!(required_collator == &head.candidate.collator, "invalid collator");
|
ensure!(required_collator == &head.candidate.collator, Error::<T>::InvalidCollator);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::check_upward_messages(
|
Self::check_upward_messages(
|
||||||
@@ -371,11 +412,11 @@ impl<T: Trait> Module<T> {
|
|||||||
.fold(size as usize, |a, x| a + x.data.len())
|
.fold(size as usize, |a, x| a + x.data.len())
|
||||||
<= watermark_queue_size
|
<= watermark_queue_size
|
||||||
),
|
),
|
||||||
"Messages added when queue full"
|
Error::<T>::QueueFull
|
||||||
);
|
);
|
||||||
if !id.is_system() {
|
if !id.is_system() {
|
||||||
for m in upward_messages.iter() {
|
for m in upward_messages.iter() {
|
||||||
ensure!(m.origin != ParachainDispatchOrigin::Root, "bad message origin");
|
ensure!(m.origin != ParachainDispatchOrigin::Root, Error::<T>::InvalidMessageOrigin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,25 +666,25 @@ impl<T: Trait> Module<T> {
|
|||||||
// egress routes should be ascending order by parachain ID without duplicate.
|
// egress routes should be ascending order by parachain ID without duplicate.
|
||||||
ensure!(
|
ensure!(
|
||||||
last_egress_id.as_ref().map_or(true, |x| x < &egress_para_id),
|
last_egress_id.as_ref().map_or(true, |x| x < &egress_para_id),
|
||||||
"Egress routes out of order by ID",
|
Error::<T>::EgressOutOfOrder,
|
||||||
);
|
);
|
||||||
|
|
||||||
// a parachain can't route to self
|
// a parachain can't route to self
|
||||||
ensure!(
|
ensure!(
|
||||||
*egress_para_id != head.candidate.parachain_index,
|
*egress_para_id != head.candidate.parachain_index,
|
||||||
"Parachain routing to self",
|
Error::<T>::SelfAddressed,
|
||||||
);
|
);
|
||||||
|
|
||||||
// no empty trie roots
|
// no empty trie roots
|
||||||
ensure!(
|
ensure!(
|
||||||
*root != EMPTY_TRIE_ROOT.into(),
|
*root != EMPTY_TRIE_ROOT.into(),
|
||||||
"Empty trie root included",
|
Error::<T>::EmptyTrieRoot,
|
||||||
);
|
);
|
||||||
|
|
||||||
// can't route to a parachain which doesn't exist
|
// can't route to a parachain which doesn't exist
|
||||||
ensure!(
|
ensure!(
|
||||||
iter.find(|x| x == egress_para_id).is_some(),
|
iter.find(|x| x == egress_para_id).is_some(),
|
||||||
"Routing to non-existent parachain",
|
Error::<T>::DestinationDoesNotExist,
|
||||||
);
|
);
|
||||||
|
|
||||||
last_egress_id = Some(egress_para_id)
|
last_egress_id = Some(egress_para_id)
|
||||||
@@ -737,16 +778,16 @@ impl<T: Trait> Module<T> {
|
|||||||
for candidate in attested_candidates {
|
for candidate in attested_candidates {
|
||||||
let para_id = candidate.parachain_index();
|
let para_id = candidate.parachain_index();
|
||||||
let validator_group = validator_groups.group_for(para_id)
|
let validator_group = validator_groups.group_for(para_id)
|
||||||
.ok_or("no validator group for parachain")?;
|
.ok_or(Error::<T>::NoValidatorGroup)?;
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
candidate.validity_votes.len() >= majority_of(validator_group.len()),
|
candidate.validity_votes.len() >= majority_of(validator_group.len()),
|
||||||
"Not enough validity attestations",
|
Error::<T>::NotEnoughValidityVotes,
|
||||||
);
|
);
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
candidate.validity_votes.len() <= authorities.len(),
|
candidate.validity_votes.len() <= authorities.len(),
|
||||||
"The number of attestations exceeds the number of authorities",
|
Error::<T>::VotesExceedsAuthorities,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fees = candidate.candidate().fees;
|
let fees = candidate.candidate().fees;
|
||||||
@@ -764,7 +805,7 @@ impl<T: Trait> Module<T> {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let validity_attestation = match candidate.validity_votes.get(vote_index) {
|
let validity_attestation = match candidate.validity_votes.get(vote_index) {
|
||||||
None => Err("Not enough validity votes")?,
|
None => Err(Error::<T>::NotEnoughValidityVotes)?,
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
expected_votes_len = vote_index + 1;
|
expected_votes_len = vote_index + 1;
|
||||||
v
|
v
|
||||||
@@ -772,7 +813,7 @@ impl<T: Trait> Module<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if validator_group.iter().find(|&(idx, _)| *idx == auth_index).is_none() {
|
if validator_group.iter().find(|&(idx, _)| *idx == auth_index).is_none() {
|
||||||
Err("Attesting validator not on this chain's validation duty.")?
|
Err(Error::<T>::WrongValidatorAttesting)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let (payload, sig) = match validity_attestation {
|
let (payload, sig) = match validity_attestation {
|
||||||
@@ -798,7 +839,7 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
sig.verify(&payload[..], &authorities[auth_index]),
|
sig.verify(&payload[..], &authorities[auth_index]),
|
||||||
"Candidate validity attestation signature is bad.",
|
Error::<T>::InvalidSignature,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,7 +847,7 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
candidate.validity_votes.len() == expected_votes_len,
|
candidate.validity_votes.len() == expected_votes_len,
|
||||||
"Extra untagged validity votes along with candidate",
|
Error::<T>::UntaggedVotes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -915,7 +956,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use keyring::Sr25519Keyring;
|
use keyring::Sr25519Keyring;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
|
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, assert_noop, parameter_types,
|
||||||
};
|
};
|
||||||
use crate::parachains;
|
use crate::parachains;
|
||||||
use crate::registrar;
|
use crate::registrar;
|
||||||
@@ -1447,7 +1488,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full"
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
|
|
||||||
// too many messages.
|
// too many messages.
|
||||||
@@ -1458,7 +1499,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full"
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1480,7 +1521,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full"
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1501,7 +1542,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full"
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1522,7 +1563,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full",
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1543,7 +1584,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_err!(
|
assert_err!(
|
||||||
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
Parachains::check_upward_messages(0.into(), &messages, 2, 3),
|
||||||
"Messages added when queue full",
|
Error::<Test>::QueueFull
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1968,12 +2009,10 @@ mod tests {
|
|||||||
|
|
||||||
make_attestations(&mut candidate);
|
make_attestations(&mut candidate);
|
||||||
|
|
||||||
let result = Parachains::dispatch(
|
assert_noop!(
|
||||||
set_heads(vec![candidate.clone()]),
|
Parachains::set_heads(Origin::NONE, vec![candidate.clone()]),
|
||||||
Origin::NONE,
|
Error::<Test>::DestinationDoesNotExist
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Err("Routing to non-existent parachain".into()), result);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1993,12 +2032,10 @@ mod tests {
|
|||||||
|
|
||||||
make_attestations(&mut candidate);
|
make_attestations(&mut candidate);
|
||||||
|
|
||||||
let result = Parachains::dispatch(
|
assert_noop!(
|
||||||
set_heads(vec![candidate.clone()]),
|
Parachains::set_heads(Origin::NONE, vec![candidate.clone()]),
|
||||||
Origin::NONE,
|
Error::<Test>::SelfAddressed
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Err("Parachain routing to self".into()), result);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2018,12 +2055,10 @@ mod tests {
|
|||||||
|
|
||||||
make_attestations(&mut candidate);
|
make_attestations(&mut candidate);
|
||||||
|
|
||||||
let result = Parachains::dispatch(
|
assert_noop!(
|
||||||
set_heads(vec![candidate.clone()]),
|
Parachains::set_heads(Origin::NONE, vec![candidate.clone()]),
|
||||||
Origin::NONE,
|
Error::<Test>::EgressOutOfOrder
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Err("Egress routes out of order by ID".into()), result);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2043,12 +2078,10 @@ mod tests {
|
|||||||
|
|
||||||
make_attestations(&mut candidate);
|
make_attestations(&mut candidate);
|
||||||
|
|
||||||
let result = Parachains::dispatch(
|
assert_noop!(
|
||||||
set_heads(vec![candidate.clone()]),
|
Parachains::set_heads(Origin::NONE, vec![candidate.clone()]),
|
||||||
Origin::NONE,
|
Error::<Test>::EmptyTrieRoot
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Err("Empty trie root included".into()), result);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use sp_runtime::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_storage, decl_module, decl_event, ensure,
|
decl_storage, decl_module, decl_event, decl_error, ensure,
|
||||||
dispatch::{DispatchResult, IsSubType}, traits::{Get, Currency, ReservableCurrency},
|
dispatch::{DispatchResult, IsSubType}, traits::{Get, Currency, ReservableCurrency},
|
||||||
weights::{SimpleDispatchInfo, DispatchInfo},
|
weights::{SimpleDispatchInfo, DispatchInfo},
|
||||||
};
|
};
|
||||||
@@ -70,11 +70,11 @@ impl<T: Trait> Registrar<T::AccountId> for Module<T> {
|
|||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
initial_head_data: Vec<u8>,
|
initial_head_data: Vec<u8>,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
ensure!(!Paras::exists(id), "Parachain already exists");
|
ensure!(!Paras::exists(id), Error::<T>::ParaAlreadyExists);
|
||||||
if let Scheduling::Always = info.scheduling {
|
if let Scheduling::Always = info.scheduling {
|
||||||
Parachains::mutate(|parachains|
|
Parachains::mutate(|parachains|
|
||||||
match parachains.binary_search(&id) {
|
match parachains.binary_search(&id) {
|
||||||
Ok(_) => Err("Parachain already exists"),
|
Ok(_) => Err(Error::<T>::ParaAlreadyExists),
|
||||||
Err(idx) => {
|
Err(idx) => {
|
||||||
parachains.insert(idx, id);
|
parachains.insert(idx, id);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -88,12 +88,12 @@ impl<T: Trait> Registrar<T::AccountId> for Module<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deregister_para(id: ParaId) -> DispatchResult {
|
fn deregister_para(id: ParaId) -> DispatchResult {
|
||||||
let info = Paras::take(id).ok_or("Invalid id")?;
|
let info = Paras::take(id).ok_or(Error::<T>::InvalidChainId)?;
|
||||||
if let Scheduling::Always = info.scheduling {
|
if let Scheduling::Always = info.scheduling {
|
||||||
Parachains::mutate(|parachains|
|
Parachains::mutate(|parachains|
|
||||||
parachains.binary_search(&id)
|
parachains.binary_search(&id)
|
||||||
.map(|index| parachains.remove(index))
|
.map(|index| parachains.remove(index))
|
||||||
.map_err(|_| "Invalid id")
|
.map_err(|_| Error::<T>::InvalidChainId)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
<parachains::Module<T>>::cleanup_para(id);
|
<parachains::Module<T>>::cleanup_para(id);
|
||||||
@@ -214,9 +214,22 @@ pub fn swap_ordered_existence<T: PartialOrd + Ord + Copy>(ids: &mut [T], one: T,
|
|||||||
ids.sort();
|
ids.sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// Parachain already exists.
|
||||||
|
ParaAlreadyExists,
|
||||||
|
/// Invalid parachain ID.
|
||||||
|
InvalidChainId,
|
||||||
|
/// Invalid parathread ID.
|
||||||
|
InvalidThreadId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
/// Parachains module.
|
/// Parachains module.
|
||||||
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
fn deposit_event() = default;
|
fn deposit_event() = default;
|
||||||
|
|
||||||
/// Register a parachain with given code.
|
/// Register a parachain with given code.
|
||||||
@@ -299,8 +312,8 @@ decl_module! {
|
|||||||
fn deregister_parathread(origin) {
|
fn deregister_parathread(origin) {
|
||||||
let id = parachains::ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
let id = parachains::ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||||
|
|
||||||
let info = Paras::get(id).ok_or("invalid id")?;
|
let info = Paras::get(id).ok_or(Error::<T>::InvalidChainId)?;
|
||||||
if let Scheduling::Dynamic = info.scheduling {} else { Err("invalid parathread id")? }
|
if let Scheduling::Dynamic = info.scheduling {} else { Err(Error::<T>::InvalidThreadId)? }
|
||||||
|
|
||||||
<Self as Registrar<T::AccountId>>::deregister_para(id)?;
|
<Self as Registrar<T::AccountId>>::deregister_para(id)?;
|
||||||
Self::force_unschedule(|i| i == id);
|
Self::force_unschedule(|i| i == id);
|
||||||
@@ -494,7 +507,7 @@ impl<T: Trait + Send + Sync> rstd::fmt::Debug for LimitParathreadCommits<T> wher
|
|||||||
|
|
||||||
/// Custom validity errors used in Polkadot while validating transactions.
|
/// Custom validity errors used in Polkadot while validating transactions.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Error {
|
pub enum ValidityError {
|
||||||
/// Parathread ID has already been submitted for this block.
|
/// Parathread ID has already been submitted for this block.
|
||||||
Duplicate = 0,
|
Duplicate = 0,
|
||||||
/// Parathread ID does not identify a parathread.
|
/// Parathread ID does not identify a parathread.
|
||||||
@@ -527,7 +540,7 @@ impl<T: Trait + Send + Sync> SignedExtension for LimitParathreadCommits<T> where
|
|||||||
if let Some(local_call) = call.is_sub_type() {
|
if let Some(local_call) = call.is_sub_type() {
|
||||||
if let Call::select_parathread(id, collator, hash) = local_call {
|
if let Call::select_parathread(id, collator, hash) = local_call {
|
||||||
// ensure that the para ID is actually a parathread.
|
// ensure that the para ID is actually a parathread.
|
||||||
let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::InvalidId as u8));
|
let e = TransactionValidityError::from(InvalidTransaction::Custom(ValidityError::InvalidId as u8));
|
||||||
<Module<T>>::ensure_thread_id(*id).ok_or(e)?;
|
<Module<T>>::ensure_thread_id(*id).ok_or(e)?;
|
||||||
|
|
||||||
// ensure that we haven't already had a full complement of selected parathreads.
|
// ensure that we haven't already had a full complement of selected parathreads.
|
||||||
@@ -544,14 +557,14 @@ impl<T: Trait + Send + Sync> SignedExtension for LimitParathreadCommits<T> where
|
|||||||
);
|
);
|
||||||
|
|
||||||
// ensure that this is not selecting a duplicate parathread ID
|
// ensure that this is not selecting a duplicate parathread ID
|
||||||
let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::Duplicate as u8));
|
let e = TransactionValidityError::from(InvalidTransaction::Custom(ValidityError::Duplicate as u8));
|
||||||
let pos = selected_threads
|
let pos = selected_threads
|
||||||
.binary_search_by(|&(ref other_id, _)| other_id.cmp(id))
|
.binary_search_by(|&(ref other_id, _)| other_id.cmp(id))
|
||||||
.err()
|
.err()
|
||||||
.ok_or(e)?;
|
.ok_or(e)?;
|
||||||
|
|
||||||
// ensure that this is a live bid (i.e. that the thread's chain head matches)
|
// ensure that this is a live bid (i.e. that the thread's chain head matches)
|
||||||
let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::InvalidId as u8));
|
let e = TransactionValidityError::from(InvalidTransaction::Custom(ValidityError::InvalidId as u8));
|
||||||
let head = <parachains::Module<T>>::parachain_head(id).ok_or(e)?;
|
let head = <parachains::Module<T>>::parachain_head(id).ok_or(e)?;
|
||||||
let actual = T::Hashing::hash(&head);
|
let actual = T::Hashing::hash(&head);
|
||||||
ensure!(&actual == hash, InvalidTransaction::Stale);
|
ensure!(&actual == hash, InvalidTransaction::Stale);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use sp_runtime::traits::{
|
|||||||
use frame_support::weights::SimpleDispatchInfo;
|
use frame_support::weights::SimpleDispatchInfo;
|
||||||
use codec::{Encode, Decode, Codec};
|
use codec::{Encode, Decode, Codec};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_module, decl_storage, decl_event, ensure, dispatch::DispatchResult,
|
decl_module, decl_storage, decl_event, decl_error, ensure, dispatch::DispatchResult,
|
||||||
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get, Randomness},
|
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get, Randomness},
|
||||||
};
|
};
|
||||||
use primitives::parachain::{
|
use primitives::parachain::{
|
||||||
@@ -224,8 +224,37 @@ decl_event!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
decl_error! {
|
||||||
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// This auction is already in progress.
|
||||||
|
AuctionInProgress,
|
||||||
|
/// The lease period is in the past.
|
||||||
|
LeasePeriodInPast,
|
||||||
|
/// The origin for this call must be a parachain.
|
||||||
|
NotParaOrigin,
|
||||||
|
/// The parachain ID is not onboarding.
|
||||||
|
ParaNotOnboarding,
|
||||||
|
/// The origin for this call must be the origin who registered the parachain.
|
||||||
|
InvalidOrigin,
|
||||||
|
/// Parachain is already registered.
|
||||||
|
AlreadyRegistered,
|
||||||
|
/// The code must correspond to the hash.
|
||||||
|
InvalidCode,
|
||||||
|
/// Deployment data has not been set for this parachain.
|
||||||
|
UnsetDeployData,
|
||||||
|
/// The bid must overlap all intersecting ranges.
|
||||||
|
NonIntersectingRange,
|
||||||
|
/// Not a current auction.
|
||||||
|
NotCurrentAuction,
|
||||||
|
/// Not an auction.
|
||||||
|
NotAuction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||||
|
type Error = Error<T>;
|
||||||
|
|
||||||
fn deposit_event() = default;
|
fn deposit_event() = default;
|
||||||
|
|
||||||
fn on_initialize(n: T::BlockNumber) {
|
fn on_initialize(n: T::BlockNumber) {
|
||||||
@@ -274,8 +303,8 @@ decl_module! {
|
|||||||
#[compact] lease_period_index: LeasePeriodOf<T>
|
#[compact] lease_period_index: LeasePeriodOf<T>
|
||||||
) {
|
) {
|
||||||
ensure_root(origin)?;
|
ensure_root(origin)?;
|
||||||
ensure!(!Self::is_in_progress(), "auction already in progress");
|
ensure!(!Self::is_in_progress(), Error::<T>::AuctionInProgress);
|
||||||
ensure!(lease_period_index >= Self::lease_period_index(), "lease period in past");
|
ensure!(lease_period_index >= Self::lease_period_index(), Error::<T>::LeasePeriodInPast);
|
||||||
|
|
||||||
// Bump the counter.
|
// Bump the counter.
|
||||||
let n = <AuctionCounter>::mutate(|n| { *n += 1; *n });
|
let n = <AuctionCounter>::mutate(|n| { *n += 1; *n });
|
||||||
@@ -340,7 +369,7 @@ decl_module! {
|
|||||||
) {
|
) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
let para_id = <ParaId>::try_from_account(&who)
|
let para_id = <ParaId>::try_from_account(&who)
|
||||||
.ok_or("account is not a parachain")?;
|
.ok_or(Error::<T>::NotParaOrigin)?;
|
||||||
let bidder = Bidder::Existing(para_id);
|
let bidder = Bidder::Existing(para_id);
|
||||||
Self::handle_bid(bidder, auction_index, first_slot, last_slot, amount)?;
|
Self::handle_bid(bidder, auction_index, first_slot, last_slot, amount)?;
|
||||||
}
|
}
|
||||||
@@ -355,7 +384,7 @@ decl_module! {
|
|||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
let dest = T::Lookup::lookup(dest)?;
|
let dest = T::Lookup::lookup(dest)?;
|
||||||
let para_id = <ParaId>::try_from_account(&who)
|
let para_id = <ParaId>::try_from_account(&who)
|
||||||
.ok_or("not a parachain origin")?;
|
.ok_or(Error::<T>::NotParaOrigin)?;
|
||||||
<Offboarding<T>>::insert(para_id, dest);
|
<Offboarding<T>>::insert(para_id, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,11 +404,11 @@ decl_module! {
|
|||||||
) {
|
) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
||||||
.ok_or("parachain id not in onboarding")?;
|
.ok_or(Error::<T>::ParaNotOnboarding)?;
|
||||||
if let IncomingParachain::Unset(ref nb) = details {
|
if let IncomingParachain::Unset(ref nb) = details {
|
||||||
ensure!(nb.who == who && nb.sub == sub, "parachain not registered by origin");
|
ensure!(nb.who == who && nb.sub == sub, Error::<T>::InvalidOrigin);
|
||||||
} else {
|
} else {
|
||||||
Err("already registered")?
|
Err(Error::<T>::AlreadyRegistered)?
|
||||||
}
|
}
|
||||||
let item = (starts, IncomingParachain::Fixed{code_hash, initial_head_data});
|
let item = (starts, IncomingParachain::Fixed{code_hash, initial_head_data});
|
||||||
<Onboarding<T>>::insert(¶_id, item);
|
<Onboarding<T>>::insert(¶_id, item);
|
||||||
@@ -400,9 +429,9 @@ decl_module! {
|
|||||||
#[weight = SimpleDispatchInfo::FixedNormal(5_000_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(5_000_000)]
|
||||||
pub fn elaborate_deploy_data(_origin, #[compact] para_id: ParaId, code: Vec<u8>) -> DispatchResult {
|
pub fn elaborate_deploy_data(_origin, #[compact] para_id: ParaId, code: Vec<u8>) -> DispatchResult {
|
||||||
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
||||||
.ok_or("parachain id not in onboarding")?;
|
.ok_or(Error::<T>::ParaNotOnboarding)?;
|
||||||
if let IncomingParachain::Fixed{code_hash, initial_head_data} = details {
|
if let IncomingParachain::Fixed{code_hash, initial_head_data} = details {
|
||||||
ensure!(<T as system::Trait>::Hashing::hash(&code) == code_hash, "code not doesn't correspond to hash");
|
ensure!(<T as system::Trait>::Hashing::hash(&code) == code_hash, Error::<T>::InvalidCode);
|
||||||
if starts > Self::lease_period_index() {
|
if starts > Self::lease_period_index() {
|
||||||
// Hasn't yet begun. Replace the on-boarding entry with the new information.
|
// Hasn't yet begun. Replace the on-boarding entry with the new information.
|
||||||
let item = (starts, IncomingParachain::Deploy{code, initial_head_data});
|
let item = (starts, IncomingParachain::Deploy{code, initial_head_data});
|
||||||
@@ -417,7 +446,7 @@ decl_module! {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err("deploy data not yet fixed".into())
|
Err(Error::<T>::UnsetDeployData)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -684,9 +713,9 @@ impl<T: Trait> Module<T> {
|
|||||||
amount: BalanceOf<T>
|
amount: BalanceOf<T>
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
// Bidding on latest auction.
|
// Bidding on latest auction.
|
||||||
ensure!(auction_index == <AuctionCounter>::get(), "not current auction");
|
ensure!(auction_index == <AuctionCounter>::get(), Error::<T>::NotCurrentAuction);
|
||||||
// Assume it's actually an auction (this should never fail because of above).
|
// Assume it's actually an auction (this should never fail because of above).
|
||||||
let (first_lease_period, _) = <AuctionInfo<T>>::get().ok_or("not an auction")?;
|
let (first_lease_period, _) = <AuctionInfo<T>>::get().ok_or(Error::<T>::NotAuction)?;
|
||||||
|
|
||||||
// Our range.
|
// Our range.
|
||||||
let range = SlotRange::new_bounded(first_lease_period, first_slot, last_slot)?;
|
let range = SlotRange::new_bounded(first_lease_period, first_slot, last_slot)?;
|
||||||
@@ -708,7 +737,7 @@ impl<T: Trait> Module<T> {
|
|||||||
.expect("array has SLOT_RANGE_COUNT items; index never reaches that value; qed")
|
.expect("array has SLOT_RANGE_COUNT items; index never reaches that value; qed")
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
"bidder winning non-intersecting range",
|
Error::<T>::NonIntersectingRange,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ok; we are the new winner of this range - reserve the additional amount and record.
|
// Ok; we are the new winner of this range - reserve the additional amount and record.
|
||||||
@@ -1205,7 +1234,7 @@ mod tests {
|
|||||||
assert_ok!(Slots::bid(Origin::signed(1), 0, 1, 2, 2, 1));
|
assert_ok!(Slots::bid(Origin::signed(1), 0, 1, 2, 2, 1));
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Slots::bid(Origin::signed(1), 0, 1, 3, 3, 1),
|
Slots::bid(Origin::signed(1), 0, 1, 3, 3, 1),
|
||||||
"bidder winning non-intersecting range"
|
Error::<Test>::NonIntersectingRange
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user