mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
Add an optional verifier to crowdloan (#2248)
* Add an optional verifier to crowdloan * add tests * verify signatures * benchmark with signatures * update crowdloan benchmark * try to get keystore working in test * rewrite to avoid traits * Use MultiSignature and MultiSigner * refactor and update benchmarks * optimize check order * fix no_std build Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Generated
+1
@@ -5830,6 +5830,7 @@ dependencies = [
|
|||||||
"sp-inherents",
|
"sp-inherents",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
|
"sp-keystore",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-session",
|
"sp-session",
|
||||||
"sp-staking",
|
"sp-staking",
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ sp-election-providers = { git = "https://github.com/paritytech/substrate", branc
|
|||||||
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
trie-db = "0.22.3"
|
trie-db = "0.22.3"
|
||||||
serde_json = "1.0.61"
|
serde_json = "1.0.61"
|
||||||
libsecp256k1 = "0.3.5"
|
libsecp256k1 = "0.3.5"
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ use frame_support::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use frame_system::ensure_signed;
|
use frame_system::ensure_signed;
|
||||||
use sp_runtime::{ModuleId, DispatchResult,
|
use sp_runtime::{
|
||||||
traits::{AccountIdConversion, Hash, Saturating, Zero, CheckedAdd, Bounded}
|
ModuleId, DispatchResult, MultiSignature, MultiSigner,
|
||||||
|
traits::{
|
||||||
|
AccountIdConversion, Hash, Saturating, Zero, CheckedAdd, Bounded, Verify, IdentifyAccount,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use crate::slots;
|
use crate::slots;
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use parity_scale_codec::{Encode, Decode};
|
||||||
@@ -140,6 +143,8 @@ pub struct FundInfo<AccountId, Balance, Hash, BlockNumber> {
|
|||||||
parachain: Option<ParaId>,
|
parachain: Option<ParaId>,
|
||||||
/// The owning account who placed the deposit.
|
/// The owning account who placed the deposit.
|
||||||
owner: AccountId,
|
owner: AccountId,
|
||||||
|
/// An optional verifier. If exists, contributions must be signed by verifier.
|
||||||
|
verifier: Option<MultiSigner>,
|
||||||
/// The amount of deposit placed.
|
/// The amount of deposit placed.
|
||||||
deposit: Balance,
|
deposit: Balance,
|
||||||
/// The total amount raised.
|
/// The total amount raised.
|
||||||
@@ -256,6 +261,8 @@ decl_error! {
|
|||||||
HasActiveParachain,
|
HasActiveParachain,
|
||||||
/// The retirement period has not ended.
|
/// The retirement period has not ended.
|
||||||
InRetirementPeriod,
|
InRetirementPeriod,
|
||||||
|
/// Invalid signature.
|
||||||
|
InvalidSignature,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +280,8 @@ decl_module! {
|
|||||||
#[compact] cap: BalanceOf<T>,
|
#[compact] cap: BalanceOf<T>,
|
||||||
#[compact] first_slot: T::BlockNumber,
|
#[compact] first_slot: T::BlockNumber,
|
||||||
#[compact] last_slot: T::BlockNumber,
|
#[compact] last_slot: T::BlockNumber,
|
||||||
#[compact] end: T::BlockNumber
|
#[compact] end: T::BlockNumber,
|
||||||
|
verifier: Option<MultiSigner>,
|
||||||
) {
|
) {
|
||||||
let owner = ensure_signed(origin)?;
|
let owner = ensure_signed(origin)?;
|
||||||
|
|
||||||
@@ -291,6 +299,7 @@ decl_module! {
|
|||||||
<Funds<T>>::insert(index, FundInfo {
|
<Funds<T>>::insert(index, FundInfo {
|
||||||
parachain: None,
|
parachain: None,
|
||||||
owner,
|
owner,
|
||||||
|
verifier,
|
||||||
deposit,
|
deposit,
|
||||||
raised: Zero::zero(),
|
raised: Zero::zero(),
|
||||||
end,
|
end,
|
||||||
@@ -307,8 +316,14 @@ decl_module! {
|
|||||||
/// Contribute to a crowd sale. This will transfer some balance over to fund a parachain
|
/// Contribute to a crowd sale. This will transfer some balance over to fund a parachain
|
||||||
/// slot. It will be withdrawable in two instances: the parachain becomes retired; or the
|
/// slot. It will be withdrawable in two instances: the parachain becomes retired; or the
|
||||||
/// slot is unable to be purchased and the timeout expires.
|
/// slot is unable to be purchased and the timeout expires.
|
||||||
|
/// A valid signature maybe required in order to accept the contribution.
|
||||||
#[weight = 0]
|
#[weight = 0]
|
||||||
fn contribute(origin, #[compact] index: FundIndex, #[compact] value: BalanceOf<T>) {
|
fn contribute(
|
||||||
|
origin,
|
||||||
|
#[compact] index: FundIndex,
|
||||||
|
#[compact] value: BalanceOf<T>,
|
||||||
|
signature: Option<MultiSignature>
|
||||||
|
) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
|
|
||||||
ensure!(value >= T::MinContribution::get(), Error::<T>::ContributionTooSmall);
|
ensure!(value >= T::MinContribution::get(), Error::<T>::ContributionTooSmall);
|
||||||
@@ -320,10 +335,18 @@ decl_module! {
|
|||||||
let now = <frame_system::Module<T>>::block_number();
|
let now = <frame_system::Module<T>>::block_number();
|
||||||
ensure!(fund.end > now, Error::<T>::ContributionPeriodOver);
|
ensure!(fund.end > now, Error::<T>::ContributionPeriodOver);
|
||||||
|
|
||||||
|
let old_balance = Self::contribution_get(index, &who);
|
||||||
|
|
||||||
|
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()));
|
||||||
|
ensure!(valid, Error::<T>::InvalidSignature);
|
||||||
|
}
|
||||||
|
|
||||||
T::Currency::transfer(&who, &Self::fund_account_id(index), value, AllowDeath)?;
|
T::Currency::transfer(&who, &Self::fund_account_id(index), value, AllowDeath)?;
|
||||||
|
|
||||||
let balance = Self::contribution_get(index, &who);
|
let balance = old_balance.saturating_add(value);
|
||||||
let balance = balance.saturating_add(value);
|
|
||||||
Self::contribution_put(index, &who, &balance);
|
Self::contribution_put(index, &who, &balance);
|
||||||
|
|
||||||
if <slots::Module<T>>::is_ending(now).is_some() {
|
if <slots::Module<T>>::is_ending(now).is_some() {
|
||||||
@@ -445,7 +468,7 @@ decl_module! {
|
|||||||
/// Withdraw full balance of a contributor to an unsuccessful or off-boarded fund.
|
/// Withdraw full balance of a contributor to an unsuccessful or off-boarded fund.
|
||||||
#[weight = 0]
|
#[weight = 0]
|
||||||
fn withdraw(origin, who: T::AccountId, #[compact] index: FundIndex) {
|
fn withdraw(origin, who: T::AccountId, #[compact] index: FundIndex) {
|
||||||
ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
let mut fund = Self::funds(index).ok_or(Error::<T>::InvalidFundIndex)?;
|
||||||
ensure!(fund.parachain.is_none(), Error::<T>::FundNotRetired);
|
ensure!(fund.parachain.is_none(), Error::<T>::FundNotRetired);
|
||||||
@@ -576,11 +599,32 @@ impl<T: Config> Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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};
|
||||||
|
|
||||||
|
pub fn create_ed25519_pubkey(seed: Vec<u8>) -> MultiSigner {
|
||||||
|
ed25519_generate(0.into(), Some(seed)).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_ed25519_signature(payload: &[u8], pubkey: MultiSigner) -> MultiSignature {
|
||||||
|
let edpubkey = ed25519::Public::try_from(pubkey).unwrap();
|
||||||
|
let edsig = ed25519_sign(0.into(), &edpubkey, payload).unwrap();
|
||||||
|
edsig.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::{collections::HashMap, cell::RefCell};
|
use std::{collections::HashMap, cell::RefCell, sync::Arc};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
assert_ok, assert_noop, parameter_types,
|
assert_ok, assert_noop, parameter_types,
|
||||||
traits::{OnInitialize, OnFinalize},
|
traits::{OnInitialize, OnFinalize},
|
||||||
@@ -593,6 +637,7 @@ mod tests {
|
|||||||
Permill, testing::Header,
|
Permill, testing::Header,
|
||||||
traits::{BlakeTwo256, IdentityLookup},
|
traits::{BlakeTwo256, IdentityLookup},
|
||||||
};
|
};
|
||||||
|
use sp_keystore::{KeystoreExt, testing::KeyStore};
|
||||||
use crate::slots::{self, Registrar};
|
use crate::slots::{self, Registrar};
|
||||||
use crate::crowdloan;
|
use crate::crowdloan;
|
||||||
|
|
||||||
@@ -769,7 +814,10 @@ mod tests {
|
|||||||
pallet_balances::GenesisConfig::<Test>{
|
pallet_balances::GenesisConfig::<Test>{
|
||||||
balances: vec![(1, 1000), (2, 2000), (3, 3000), (4, 4000)],
|
balances: vec![(1, 1000), (2, 2000), (3, 3000), (4, 4000)],
|
||||||
}.assimilate_storage(&mut t).unwrap();
|
}.assimilate_storage(&mut t).unwrap();
|
||||||
t.into()
|
let keystore = KeyStore::new();
|
||||||
|
let mut t: sp_io::TestExternalities = t.into();
|
||||||
|
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||||
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_to_block(n: u64) {
|
fn run_to_block(n: u64) {
|
||||||
@@ -805,12 +853,46 @@ mod tests {
|
|||||||
fn create_works() {
|
fn create_works() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Now try to create a crowdloan campaign
|
// Now try to create a crowdloan campaign
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Crowdloan::fund_count(), 1);
|
assert_eq!(Crowdloan::fund_count(), 1);
|
||||||
// This is what the initial `fund_info` should look like
|
// This is what the initial `fund_info` should look like
|
||||||
let fund_info = FundInfo {
|
let fund_info = FundInfo {
|
||||||
parachain: None,
|
parachain: None,
|
||||||
owner: 1,
|
owner: 1,
|
||||||
|
verifier: None,
|
||||||
|
deposit: 1,
|
||||||
|
raised: 0,
|
||||||
|
// 5 blocks length + 3 block ending period + 1 starting block
|
||||||
|
end: 9,
|
||||||
|
cap: 1000,
|
||||||
|
last_contribution: LastContribution::Never,
|
||||||
|
first_slot: 1,
|
||||||
|
last_slot: 4,
|
||||||
|
deploy_data: None,
|
||||||
|
};
|
||||||
|
assert_eq!(Crowdloan::funds(0), Some(fund_info));
|
||||||
|
// User has deposit removed from their free balance
|
||||||
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
// Deposit is placed in crowdloan free balance
|
||||||
|
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(0)), 1);
|
||||||
|
// No new raise until first contribution
|
||||||
|
let empty: Vec<FundIndex> = Vec::new();
|
||||||
|
assert_eq!(Crowdloan::new_raise(), empty);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_with_verifier_works() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
// Now try to create a crowdloan campaign
|
||||||
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, Some(pubkey.clone())));
|
||||||
|
assert_eq!(Crowdloan::fund_count(), 1);
|
||||||
|
// This is what the initial `fund_info` should look like
|
||||||
|
let fund_info = FundInfo {
|
||||||
|
parachain: None,
|
||||||
|
owner: 1,
|
||||||
|
verifier: Some(pubkey),
|
||||||
deposit: 1,
|
deposit: 1,
|
||||||
raised: 0,
|
raised: 0,
|
||||||
// 5 blocks length + 3 block ending period + 1 starting block
|
// 5 blocks length + 3 block ending period + 1 starting block
|
||||||
@@ -837,17 +919,17 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Cannot create a crowdloan with bad slots
|
// Cannot create a crowdloan with bad slots
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Crowdloan::create(Origin::signed(1), 1000, 4, 1, 9),
|
Crowdloan::create(Origin::signed(1), 1000, 4, 1, 9, None),
|
||||||
Error::<Test>::LastSlotBeforeFirstSlot
|
Error::<Test>::LastSlotBeforeFirstSlot
|
||||||
);
|
);
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Crowdloan::create(Origin::signed(1), 1000, 1, 5, 9),
|
Crowdloan::create(Origin::signed(1), 1000, 1, 5, 9, None),
|
||||||
Error::<Test>::LastSlotTooFarInFuture
|
Error::<Test>::LastSlotTooFarInFuture
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cannot create a crowdloan without some deposit funds
|
// Cannot create a crowdloan without some deposit funds
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Crowdloan::create(Origin::signed(1337), 1000, 1, 3, 9),
|
Crowdloan::create(Origin::signed(1337), 1000, 1, 3, 9, None),
|
||||||
BalancesError::<Test, _>::InsufficientBalance
|
BalancesError::<Test, _>::InsufficientBalance
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -857,7 +939,7 @@ mod tests {
|
|||||||
fn contribute_works() {
|
fn contribute_works() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(0)), 1);
|
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(0)), 1);
|
||||||
|
|
||||||
@@ -865,7 +947,7 @@ mod tests {
|
|||||||
assert_eq!(Crowdloan::contribution_get(0, &1), 0);
|
assert_eq!(Crowdloan::contribution_get(0, &1), 0);
|
||||||
|
|
||||||
// User 1 contributes to their own crowdloan
|
// User 1 contributes to their own crowdloan
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49, None));
|
||||||
// User 1 has spent some funds to do this, transfer fees **are** taken
|
// User 1 has spent some funds to do this, transfer fees **are** taken
|
||||||
assert_eq!(Balances::free_balance(1), 950);
|
assert_eq!(Balances::free_balance(1), 950);
|
||||||
// Contributions are stored in the trie
|
// Contributions are stored in the trie
|
||||||
@@ -883,26 +965,70 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contribute_with_verifier_works() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
// Set up a crowdloan
|
||||||
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, Some(pubkey.clone())));
|
||||||
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(0)), 1);
|
||||||
|
|
||||||
|
// Missing signature
|
||||||
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 49, None), Error::<Test>::InvalidSignature);
|
||||||
|
|
||||||
|
let payload = (0u32, 1u64, 0u64, 49u64);
|
||||||
|
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), 0, 49, Some(invalid_signature)), Error::<Test>::InvalidSignature);
|
||||||
|
|
||||||
|
// Valid signature wrong parameter
|
||||||
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 50, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
|
||||||
|
assert_noop!(Crowdloan::contribute(Origin::signed(2), 0, 49, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
|
||||||
|
|
||||||
|
// Valid signature
|
||||||
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49, Some(valid_signature.clone())));
|
||||||
|
|
||||||
|
// Reuse valid signature
|
||||||
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 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);
|
||||||
|
|
||||||
|
// New valid signature
|
||||||
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 10, Some(valid_signature_2)));
|
||||||
|
|
||||||
|
// Contributions appear in free balance of crowdloan
|
||||||
|
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(0)), 60);
|
||||||
|
|
||||||
|
// Contribution amount is correct
|
||||||
|
let fund = Crowdloan::funds(0).unwrap();
|
||||||
|
assert_eq!(fund.raised, 59);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
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!(Crowdloan::contribute(Origin::signed(1), 0, 49), Error::<Test>::InvalidFundIndex);
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 49, None), Error::<Test>::InvalidFundIndex);
|
||||||
// Cannot contribute below minimum contribution
|
// Cannot contribute below minimum contribution
|
||||||
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 9), Error::<Test>::ContributionTooSmall);
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 9, None), Error::<Test>::ContributionTooSmall);
|
||||||
|
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 101));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 101, None));
|
||||||
|
|
||||||
// Cannot contribute past the limit
|
// Cannot contribute past the limit
|
||||||
assert_noop!(Crowdloan::contribute(Origin::signed(2), 0, 900), Error::<Test>::CapExceeded);
|
assert_noop!(Crowdloan::contribute(Origin::signed(2), 0, 900, None), 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!(Crowdloan::contribute(Origin::signed(1), 0, 49), Error::<Test>::ContributionPeriodOver);
|
assert_noop!(Crowdloan::contribute(Origin::signed(1), 0, 49, None), Error::<Test>::ContributionPeriodOver);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,7 +1036,7 @@ mod tests {
|
|||||||
fn fix_deploy_data_works() {
|
fn fix_deploy_data_works() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Add deploy data
|
// Add deploy data
|
||||||
@@ -940,7 +1066,7 @@ mod tests {
|
|||||||
fn fix_deploy_data_handles_basic_errors() {
|
fn fix_deploy_data_handles_basic_errors() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Cannot set deploy data by non-owner
|
// Cannot set deploy data by non-owner
|
||||||
@@ -988,7 +1114,7 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Add deploy data
|
// Add deploy data
|
||||||
@@ -1001,7 +1127,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Fund crowdloan
|
// Fund crowdloan
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000, None));
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
@@ -1024,11 +1150,11 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Fund crowdloan
|
// Fund crowdloan
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000, None));
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
@@ -1062,7 +1188,7 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Add deploy data
|
// Add deploy data
|
||||||
@@ -1075,7 +1201,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Fund crowdloan
|
// Fund crowdloan
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000, None));
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
@@ -1105,7 +1231,7 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
assert_eq!(Balances::free_balance(1), 999);
|
assert_eq!(Balances::free_balance(1), 999);
|
||||||
|
|
||||||
// Add deploy data
|
// Add deploy data
|
||||||
@@ -1118,7 +1244,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Fund crowdloan
|
// Fund crowdloan
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 1000, None));
|
||||||
|
|
||||||
run_to_block(10);
|
run_to_block(10);
|
||||||
|
|
||||||
@@ -1150,11 +1276,11 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
// Transfer fee is taken here
|
// Transfer fee is taken here
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300));
|
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300, None));
|
||||||
|
|
||||||
// Skip all the way to the end
|
// Skip all the way to the end
|
||||||
run_to_block(50);
|
run_to_block(50);
|
||||||
@@ -1176,9 +1302,9 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
// Transfer fee is taken here
|
// Transfer fee is taken here
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49, None));
|
||||||
assert_eq!(Balances::free_balance(1), 950);
|
assert_eq!(Balances::free_balance(1), 950);
|
||||||
|
|
||||||
run_to_block(5);
|
run_to_block(5);
|
||||||
@@ -1200,11 +1326,11 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
// Transfer fee is taken here
|
// Transfer fee is taken here
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300));
|
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300, None));
|
||||||
|
|
||||||
// Skip all the way to the end
|
// Skip all the way to the end
|
||||||
run_to_block(50);
|
run_to_block(50);
|
||||||
@@ -1238,12 +1364,12 @@ mod tests {
|
|||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 100_000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 100_000, 1, 4, 9, None));
|
||||||
|
|
||||||
// Add lots of contributors, beyond what we can delete in one go.
|
// Add lots of contributors, beyond what we can delete in one go.
|
||||||
for i in 0 .. 30 {
|
for i in 0 .. 30 {
|
||||||
Balances::make_free_balance_be(&i, 300);
|
Balances::make_free_balance_be(&i, 300);
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(i), 0, 100));
|
assert_ok!(Crowdloan::contribute(Origin::signed(i), 0, 100, None));
|
||||||
assert_eq!(Crowdloan::contribution_get(0, &i), 100);
|
assert_eq!(Crowdloan::contribution_get(0, &i), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1302,11 +1428,11 @@ mod tests {
|
|||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Set up a crowdloan
|
// Set up a crowdloan
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
// Transfer fee is taken here
|
// Transfer fee is taken here
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 100, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200));
|
assert_ok!(Crowdloan::contribute(Origin::signed(2), 0, 200, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300));
|
assert_ok!(Crowdloan::contribute(Origin::signed(3), 0, 300, None));
|
||||||
|
|
||||||
// Cannot dissolve an invalid fund index
|
// Cannot dissolve an invalid fund index
|
||||||
assert_noop!(Crowdloan::dissolve(Origin::signed(1), 1), Error::<Test>::InvalidFundIndex);
|
assert_noop!(Crowdloan::dissolve(Origin::signed(1), 1), Error::<Test>::InvalidFundIndex);
|
||||||
@@ -1334,9 +1460,9 @@ mod tests {
|
|||||||
fn fund_before_auction_works() {
|
fn fund_before_auction_works() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Create a crowdloan before an auction is created
|
// Create a crowdloan before an auction is created
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 9, None));
|
||||||
// Users can already contribute
|
// Users can already contribute
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 49, None));
|
||||||
// Fund added to NewRaise
|
// Fund added to NewRaise
|
||||||
assert_eq!(Crowdloan::new_raise(), vec![0]);
|
assert_eq!(Crowdloan::new_raise(), vec![0]);
|
||||||
|
|
||||||
@@ -1376,12 +1502,12 @@ mod tests {
|
|||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
// Create two competing crowdloans, with end dates across multiple auctions
|
// Create two competing crowdloans, with end dates across multiple auctions
|
||||||
// Each crowdloan is competing for the same slots, so only one can win
|
// Each crowdloan is competing for the same slots, so only one can win
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 30));
|
assert_ok!(Crowdloan::create(Origin::signed(1), 1000, 1, 4, 30, None));
|
||||||
assert_ok!(Crowdloan::create(Origin::signed(2), 1000, 1, 4, 30));
|
assert_ok!(Crowdloan::create(Origin::signed(2), 1000, 1, 4, 30, None));
|
||||||
|
|
||||||
// Contribute to all, but more money to 0, less to 1
|
// Contribute to all, but more money to 0, less to 1
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 300));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 0, 300, None));
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 1, 200));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 1, 200, None));
|
||||||
|
|
||||||
// Add deploy data to all
|
// Add deploy data to all
|
||||||
assert_ok!(Crowdloan::fix_deploy_data(
|
assert_ok!(Crowdloan::fix_deploy_data(
|
||||||
@@ -1413,7 +1539,7 @@ mod tests {
|
|||||||
// Create a second auction
|
// Create a second auction
|
||||||
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
assert_ok!(Slots::new_auction(Origin::root(), 5, 1));
|
||||||
// Contribute to existing funds add to NewRaise
|
// Contribute to existing funds add to NewRaise
|
||||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), 1, 10));
|
assert_ok!(Crowdloan::contribute(Origin::signed(1), 1, 10, None));
|
||||||
|
|
||||||
// End the current auction, fund 1 wins!
|
// End the current auction, fund 1 wins!
|
||||||
run_to_block(20);
|
run_to_block(20);
|
||||||
@@ -1464,14 +1590,22 @@ mod benchmarking {
|
|||||||
let caller = account("fund_creator", 0, 0);
|
let caller = account("fund_creator", 0, 0);
|
||||||
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||||
|
|
||||||
assert_ok!(Crowdloan::<T>::create(RawOrigin::Signed(caller).into(), cap, first_slot, last_slot, end));
|
// Assume ed25519 is most complex signature format
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
|
||||||
|
assert_ok!(Crowdloan::<T>::create(RawOrigin::Signed(caller).into(), cap, first_slot, last_slot, end, Some(pubkey)));
|
||||||
FundCount::get() - 1
|
FundCount::get() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contribute_fund<T: Config>(who: &T::AccountId, index: FundIndex) {
|
fn contribute_fund<T: Config>(who: &T::AccountId, index: FundIndex) {
|
||||||
T::Currency::make_free_balance_be(&who, BalanceOf::<T>::max_value());
|
T::Currency::make_free_balance_be(&who, BalanceOf::<T>::max_value());
|
||||||
let value = T::MinContribution::get();
|
let value = T::MinContribution::get();
|
||||||
assert_ok!(Crowdloan::<T>::contribute(RawOrigin::Signed(who.clone()).into(), index, value));
|
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worst_validation_code<T: Config>() -> Vec<u8> {
|
fn worst_validation_code<T: Config>() -> Vec<u8> {
|
||||||
@@ -1540,9 +1674,10 @@ mod benchmarking {
|
|||||||
let end = T::BlockNumber::max_value();
|
let end = T::BlockNumber::max_value();
|
||||||
|
|
||||||
let caller: T::AccountId = whitelisted_caller();
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
|
let verifier = account("verifier", 0, 0);
|
||||||
|
|
||||||
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||||
}: _(RawOrigin::Signed(caller), cap, first_slot, last_slot, end)
|
}: _(RawOrigin::Signed(caller), cap, first_slot, last_slot, end, Some(verifier))
|
||||||
verify {
|
verify {
|
||||||
assert_last_event::<T>(RawEvent::Created(FundCount::get() - 1).into())
|
assert_last_event::<T>(RawEvent::Created(FundCount::get() - 1).into())
|
||||||
}
|
}
|
||||||
@@ -1553,7 +1688,12 @@ mod benchmarking {
|
|||||||
let caller: T::AccountId = whitelisted_caller();
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
let contribution = T::MinContribution::get();
|
let contribution = T::MinContribution::get();
|
||||||
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||||
}: _(RawOrigin::Signed(caller.clone()), fund_index, contribution)
|
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
let payload = (fund_index, &caller, BalanceOf::<T>::default(), contribution);
|
||||||
|
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey);
|
||||||
|
|
||||||
|
}: _(RawOrigin::Signed(caller.clone()), fund_index, contribution, Some(sig))
|
||||||
verify {
|
verify {
|
||||||
// NewRaise is appended to, so we don't need to fill it up for worst case scenario.
|
// NewRaise is appended to, so we don't need to fill it up for worst case scenario.
|
||||||
assert!(!NewRaise::get().is_empty());
|
assert!(!NewRaise::get().is_empty());
|
||||||
@@ -1638,12 +1778,18 @@ mod benchmarking {
|
|||||||
let n in 2 .. 100;
|
let n in 2 .. 100;
|
||||||
let end_block: T::BlockNumber = 100u32.into();
|
let end_block: T::BlockNumber = 100u32.into();
|
||||||
|
|
||||||
|
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
|
||||||
|
|
||||||
for i in 0 .. n {
|
for i in 0 .. n {
|
||||||
let fund_index = create_fund::<T>(end_block);
|
let fund_index = create_fund::<T>(end_block);
|
||||||
let contributor: T::AccountId = account("contributor", i, 0);
|
let contributor: T::AccountId = account("contributor", i, 0);
|
||||||
let contribution = T::MinContribution::get() * (i + 1).into();
|
let contribution = T::MinContribution::get() * (i + 1).into();
|
||||||
T::Currency::make_free_balance_be(&contributor, BalanceOf::<T>::max_value());
|
T::Currency::make_free_balance_be(&contributor, BalanceOf::<T>::max_value());
|
||||||
Crowdloan::<T>::contribute(RawOrigin::Signed(contributor).into(), fund_index, contribution)?;
|
|
||||||
|
let payload = (fund_index, &contributor, BalanceOf::<T>::default(), contribution);
|
||||||
|
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey.clone());
|
||||||
|
|
||||||
|
Crowdloan::<T>::contribute(RawOrigin::Signed(contributor).into(), fund_index, contribution, Some(sig))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lease_period_index = end_block / T::LeasePeriod::get();
|
let lease_period_index = end_block / T::LeasePeriod::get();
|
||||||
|
|||||||
Reference in New Issue
Block a user