pallet_staking_async_parachain_runtime/
staking.rs1use super::*;
20use cumulus_primitives_core::relay_chain::SessionIndex;
21use frame_election_provider_support::{ElectionDataProvider, SequentialPhragmen};
22use frame_support::traits::{ConstU128, EitherOf};
23use pallet_election_provider_multi_block::{self as multi_block, SolutionAccuracyOf};
24use pallet_staking_async::UseValidatorsMap;
25use pallet_staking_async_rc_client as rc_client;
26use polkadot_runtime_common::{prod_or_fast, BalanceToU256, U256ToBalance};
27use sp_core::Get;
28use sp_npos_elections::BalancingConfig;
29use sp_runtime::{
30 traits::Convert, transaction_validity::TransactionPriority, FixedPointNumber, FixedU128,
31 SaturatedConversion,
32};
33use xcm::latest::prelude::*;
34
35pub(crate) fn enable_dot_preset(fast: bool) {
36 Pages::set(&32);
37 MinerPages::set(&4);
38 MaxElectingVoters::set(&22_500);
39 TargetSnapshotPerBlock::set(&2000);
40 if !fast {
41 SignedValidationPhase::set(&(8 * Pages::get()));
42 SignedPhase::set(&(20 * MINUTES));
43 }
44}
45
46pub(crate) fn enable_ksm_preset(fast: bool) {
47 Pages::set(&16);
48 MinerPages::set(&4);
49 MaxElectingVoters::set(&12_500);
50 TargetSnapshotPerBlock::set(&2500);
51 if !fast {
52 SignedValidationPhase::set(&(4 * Pages::get()));
53 SignedPhase::set(&(20 * MINUTES));
54 }
55}
56
57parameter_types! {
69 pub storage Pages: u32 = 4;
83
84 pub storage SignedValidationPhase: u32 = Pages::get() * 2;
91
92 pub storage SignedPhase: u32 = 4 * MINUTES;
106
107 pub storage MinerPages: u32 = 4;
115
116 pub storage UnsignedPhase: u32 = MINUTES;
130
131 pub storage MaxElectingVoters: u32 = 1000;
139
140 pub storage TargetSnapshotPerBlock: u32 = 4000;
148
149 pub OffchainRepeat: u32 = UnsignedPhase::get() / 4;
153
154 pub const MaxValidatorSet: u32 = 1000;
158
159 pub VoterSnapshotPerBlock: u32 = MaxElectingVoters::get() / Pages::get();
164
165 pub const MaxWinnersPerPage: u32 = MaxValidatorSet::get();
167
168 pub MaxBackersPerWinner: u32 = VoterSnapshotPerBlock::get();
173
174 pub MaxBackersPerWinnerFinal: u32 = MaxElectingVoters::get();
178
179 pub const MaxExposurePageSize: u32 = 512;
183
184 pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(1u32, 10_000);
186}
187
188parameter_types! {
190 pub MaxSubmissions: u32 = 8;
197
198 pub DepositBase: Balance = 5 * UNITS;
205
206 pub DepositPerPage: Balance = 1 * UNITS;
211
212 pub InvulnerableDeposit: Balance = UNITS;
218
219 pub BailoutGraceRatio: Perbill = Perbill::from_percent(5);
227
228 pub EjectGraceRatio: Perbill = Perbill::from_percent(50);
236
237 pub RewardBase: Balance = 10 * UNITS;
240}
241
242frame_election_provider_support::generate_solution_type!(
248 #[compact]
249 pub struct NposCompactSolution16::<
250 VoterIndex = u16,
251 TargetIndex = u16,
252 Accuracy = sp_runtime::PerU16,
253 MaxVoters = VoterSnapshotPerBlock,
254 >(16)
255);
256
257#[cfg(feature = "runtime-benchmarks")]
258parameter_types! {
259 pub BenchElectionBounds: frame_election_provider_support::bounds::ElectionBounds =
260 frame_election_provider_support::bounds::ElectionBoundsBuilder::default().build();
261}
262
263#[cfg(feature = "runtime-benchmarks")]
264pub struct OnChainConfig;
265
266#[cfg(feature = "runtime-benchmarks")]
267impl frame_election_provider_support::onchain::Config for OnChainConfig {
268 type Bounds = BenchElectionBounds;
270 type Sort = ConstBool<false>;
273 type DataProvider = Staking;
274 type MaxBackersPerWinner = MaxBackersPerWinner;
275 type MaxWinnersPerPage = MaxWinnersPerPage;
276 type Solver = frame_election_provider_support::SequentialPhragmen<AccountId, Perbill>;
277 type System = Runtime;
278 type WeightInfo = ();
279}
280
281impl multi_block::Config for Runtime {
282 type AreWeDone = multi_block::RevertToSignedIfNotQueuedOf<Self>;
283 type Pages = Pages;
284 type UnsignedPhase = UnsignedPhase;
285 type SignedPhase = SignedPhase;
286 type SignedValidationPhase = SignedValidationPhase;
287 type VoterSnapshotPerBlock = VoterSnapshotPerBlock;
288 type TargetSnapshotPerBlock = TargetSnapshotPerBlock;
289 type AdminOrigin = EnsureRoot<AccountId>;
290 type DataProvider = Staking;
291 #[cfg(not(feature = "runtime-benchmarks"))]
292 type Fallback = multi_block::Continue<Self>;
293 #[cfg(feature = "runtime-benchmarks")]
294 type Fallback = frame_election_provider_support::onchain::OnChainExecution<OnChainConfig>;
295 type MinerConfig = Self;
296 type Verifier = MultiBlockElectionVerifier;
297 type OnRoundRotation = multi_block::CleanRound<Self>;
298 type WeightInfo = multi_block::weights::polkadot::MultiBlockWeightInfo<Self>;
299}
300
301impl multi_block::verifier::Config for Runtime {
302 type MaxWinnersPerPage = MaxWinnersPerPage;
303 type MaxBackersPerWinner = MaxBackersPerWinner;
304 type MaxBackersPerWinnerFinal = MaxBackersPerWinnerFinal;
305 type SolutionDataProvider = MultiBlockElectionSigned;
306 type SolutionImprovementThreshold = SolutionImprovementThreshold;
307 type WeightInfo = multi_block::weights::polkadot::MultiBlockVerifierWeightInfo<Self>;
308}
309
310impl multi_block::signed::Config for Runtime {
311 type Currency = Balances;
312 type BailoutGraceRatio = BailoutGraceRatio;
313 type EjectGraceRatio = EjectGraceRatio;
314 type DepositBase = DepositBase;
315 type DepositPerPage = DepositPerPage;
316 type InvulnerableDeposit = InvulnerableDeposit;
317 type RewardBase = RewardBase;
318 type MaxSubmissions = MaxSubmissions;
319 type EstimateCallFee = TransactionPayment;
320 type WeightInfo = multi_block::weights::polkadot::MultiBlockSignedWeightInfo<Self>;
321}
322
323parameter_types! {
324 pub MinerTxPriority: TransactionPriority = TransactionPriority::max_value() / 2;
326}
327
328pub struct Balancing;
329impl Get<Option<BalancingConfig>> for Balancing {
330 fn get() -> Option<BalancingConfig> {
331 Some(BalancingConfig { iterations: 10, tolerance: 0 })
332 }
333}
334
335impl multi_block::unsigned::Config for Runtime {
336 type MinerPages = MinerPages;
337 type OffchainSolver = SequentialPhragmen<AccountId, SolutionAccuracyOf<Runtime>, Balancing>;
338 type MinerTxPriority = MinerTxPriority;
339 type OffchainRepeat = OffchainRepeat;
340 type OffchainStorage = ConstBool<true>;
341 type WeightInfo = multi_block::weights::polkadot::MultiBlockUnsignedWeightInfo<Self>;
342}
343
344parameter_types! {
345 pub MinerMaxLength: u32 = Perbill::from_rational(75u32, 100) *
347 *RuntimeBlockLength::get()
348 .max
349 .get(DispatchClass::Normal);
350}
351
352impl multi_block::unsigned::miner::MinerConfig for Runtime {
353 type AccountId = AccountId;
354 type Hash = Hash;
355 type MaxBackersPerWinner = <Self as multi_block::verifier::Config>::MaxBackersPerWinner;
356 type MaxBackersPerWinnerFinal =
357 <Self as multi_block::verifier::Config>::MaxBackersPerWinnerFinal;
358 type MaxWinnersPerPage = <Self as multi_block::verifier::Config>::MaxWinnersPerPage;
359 type MaxVotesPerVoter =
360 <<Self as multi_block::Config>::DataProvider as ElectionDataProvider>::MaxVotesPerVoter;
361 type MaxLength = MinerMaxLength;
362 type Solver = <Runtime as multi_block::unsigned::Config>::OffchainSolver;
363 type Pages = Pages;
364 type Solution = NposCompactSolution16;
365 type VoterSnapshotPerBlock = <Runtime as multi_block::Config>::VoterSnapshotPerBlock;
366 type TargetSnapshotPerBlock = <Runtime as multi_block::Config>::TargetSnapshotPerBlock;
367}
368
369parameter_types! {
370 pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS;
371}
372
373type VoterBagsListInstance = pallet_bags_list::Instance1;
374impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
375 type RuntimeEvent = RuntimeEvent;
376 type ScoreProvider = Staking;
377 type WeightInfo = weights::pallet_bags_list::WeightInfo<Runtime>;
378 type BagThresholds = BagThresholds;
379 type Score = sp_npos_elections::VoteWeight;
380 type MaxAutoRebagPerBlock = ();
381}
382
383pub struct EraPayout;
384impl pallet_staking_async::EraPayout<Balance> for EraPayout {
385 fn era_payout(
386 _total_staked: Balance,
387 _total_issuance: Balance,
388 era_duration_millis: u64,
389 ) -> (Balance, Balance) {
390 const MILLISECONDS_PER_YEAR: u64 = (1000 * 3600 * 24 * 36525) / 100;
391 let relative_era_len =
393 FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into());
394
395 let fixed_total_issuance: i128 = 5_216_342_402_773_185_773;
397 let fixed_inflation_rate = FixedU128::from_rational(8, 100);
398 let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance);
399
400 let era_emission = relative_era_len.saturating_mul_int(yearly_emission);
401 let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission);
403 let to_stakers = era_emission.saturating_sub(to_treasury);
404
405 (to_stakers.saturated_into(), to_treasury.saturated_into())
406 }
407}
408
409parameter_types! {
410 pub const SessionsPerEra: SessionIndex = prod_or_fast!(6, 1);
412 pub const RelaySessionDuration: BlockNumber = 10;
414 pub const BondingDuration: sp_staking::EraIndex = 2;
416 pub const SlashDeferDuration: sp_staking::EraIndex = 1;
418 pub const MaxControllersInDeprecationBatch: u32 = 751;
422 pub const MaxNominations: u32 = <NposCompactSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
423 pub const MaxEraDuration: u64 = RelaySessionDuration::get() as u64 * RELAY_CHAIN_SLOT_DURATION_MILLIS as u64 * SessionsPerEra::get() as u64;
427 pub MaxPruningItems: u32 = 100;
428}
429
430impl pallet_staking_async::Config for Runtime {
431 type Filter = ();
432 type OldCurrency = Balances;
433 type Currency = Balances;
434 type CurrencyBalance = Balance;
435 type RuntimeHoldReason = RuntimeHoldReason;
436 type CurrencyToVote = sp_staking::currency_to_vote::SaturatingCurrencyToVote;
437 type RewardRemainder = ();
438 type Slash = ();
439 type Reward = ();
440 type SessionsPerEra = SessionsPerEra;
441 type BondingDuration = BondingDuration;
442 type SlashDeferDuration = SlashDeferDuration;
443 type AdminOrigin = EitherOf<EnsureRoot<AccountId>, StakingAdmin>;
444 type EraPayout = EraPayout;
445 type MaxExposurePageSize = MaxExposurePageSize;
446 type ElectionProvider = MultiBlockElection;
447 type VoterList = VoterList;
448 type TargetList = UseValidatorsMap<Self>;
449 type MaxValidatorSet = MaxValidatorSet;
450 type NominationsQuota = pallet_staking_async::FixedNominationsQuota<{ MaxNominations::get() }>;
451 type MaxUnlockingChunks = frame_support::traits::ConstU32<32>;
452 type HistoryDepth = ConstU32<1>;
453 type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch;
454 type EventListeners = (NominationPools, DelegatedStaking);
455 type WeightInfo = pallet_staking_async::weights::SubstrateWeight<Runtime>;
456 type MaxInvulnerables = frame_support::traits::ConstU32<20>;
457 type MaxEraDuration = MaxEraDuration;
458 type MaxPruningItems = MaxPruningItems;
459 type PlanningEraOffset =
460 pallet_staking_async::PlanningEraOffsetOf<Self, RelaySessionDuration, ConstU32<10>>;
461 type RcClientInterface = StakingRcClient;
462}
463
464impl pallet_staking_async_rc_client::Config for Runtime {
465 type RelayChainOrigin = EnsureRoot<AccountId>;
466 type AHStakingInterface = Staking;
467 type SendToRelayChain = StakingXcmToRelayChain;
468 type MaxValidatorSetRetries = ConstU32<5>;
469}
470
471parameter_types! {
472 pub StakingXcmDestination: Location = Location::parent();
473}
474
475#[derive(Encode, Decode)]
476pub enum RelayChainRuntimePallets {
478 #[codec(index = 67)]
479 AhClient(AhClientCalls),
480}
481
482#[derive(Encode, Decode)]
483pub enum AhClientCalls {
484 #[codec(index = 0)]
485 ValidatorSet(rc_client::ValidatorSetReport<AccountId>),
486}
487
488pub struct ValidatorSetToXcm;
489impl Convert<rc_client::ValidatorSetReport<AccountId>, Xcm<()>> for ValidatorSetToXcm {
490 fn convert(report: rc_client::ValidatorSetReport<AccountId>) -> Xcm<()> {
491 Xcm(vec![
492 Instruction::UnpaidExecution {
493 weight_limit: WeightLimit::Unlimited,
494 check_origin: None,
495 },
496 Instruction::Transact {
497 origin_kind: OriginKind::Native,
498 fallback_max_weight: None,
499 call: RelayChainRuntimePallets::AhClient(AhClientCalls::ValidatorSet(report))
500 .encode()
501 .into(),
502 },
503 ])
504 }
505}
506
507pub struct StakingXcmToRelayChain;
508
509impl rc_client::SendToRelayChain for StakingXcmToRelayChain {
510 type AccountId = AccountId;
511 fn validator_set(report: rc_client::ValidatorSetReport<Self::AccountId>) -> Result<(), ()> {
512 rc_client::XCMSender::<
513 xcm_config::XcmRouter,
514 StakingXcmDestination,
515 rc_client::ValidatorSetReport<Self::AccountId>,
516 ValidatorSetToXcm,
517 >::send(report)
518 }
519}
520
521impl pallet_fast_unstake::Config for Runtime {
522 type RuntimeEvent = RuntimeEvent;
523 type Currency = Balances;
524 type BatchSize = ConstU32<64>;
525 type Deposit = ConstU128<{ UNITS }>;
526 type ControlOrigin = EnsureRoot<AccountId>;
527 type Staking = Staking;
528 type MaxErasToCheckPerBlock = ConstU32<1>;
529 type WeightInfo = weights::pallet_fast_unstake::WeightInfo<Runtime>;
530}
531
532parameter_types! {
533 pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
534 pub const MaxPointsToBalance: u8 = 10;
535}
536
537impl pallet_nomination_pools::Config for Runtime {
538 type Filter = ();
539 type RuntimeEvent = RuntimeEvent;
540 type WeightInfo = weights::pallet_nomination_pools::WeightInfo<Self>;
541 type Currency = Balances;
542 type RuntimeFreezeReason = RuntimeFreezeReason;
543 type RewardCounter = FixedU128;
544 type BalanceToU256 = BalanceToU256;
545 type U256ToBalance = U256ToBalance;
546 type StakeAdapter =
547 pallet_nomination_pools::adapter::DelegateStake<Self, Staking, DelegatedStaking>;
548 type PostUnbondingPoolsWindow = ConstU32<4>;
549 type MaxMetadataLen = ConstU32<256>;
550 type MaxUnbonding = <Self as pallet_staking_async::Config>::MaxUnlockingChunks;
552 type PalletId = PoolsPalletId;
553 type MaxPointsToBalance = MaxPointsToBalance;
554 type AdminOrigin = EitherOf<EnsureRoot<AccountId>, StakingAdmin>;
555 type BlockNumberProvider = RelayChainBlockNumberProvider;
556}
557
558parameter_types! {
559 pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk");
560 pub const SlashRewardFraction: Perbill = Perbill::from_percent(1);
561}
562
563impl pallet_delegated_staking::Config for Runtime {
564 type RuntimeEvent = RuntimeEvent;
565 type PalletId = DelegatedStakingPalletId;
566 type Currency = Balances;
567 type OnSlash = ();
568 type SlashRewardFraction = SlashRewardFraction;
569 type RuntimeHoldReason = RuntimeHoldReason;
570 type CoreStaking = Staking;
571}
572
573pub type SignedPayload = generic::SignedPayload<RuntimeCall, TxExtension>;
575pub type UncheckedExtrinsic =
577 generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
578
579impl frame_system::offchain::SigningTypes for Runtime {
580 type Public = <Signature as Verify>::Signer;
581 type Signature = Signature;
582}
583
584impl<C> frame_system::offchain::CreateTransactionBase<C> for Runtime
585where
586 RuntimeCall: From<C>,
587{
588 type RuntimeCall = RuntimeCall;
589 type Extrinsic = UncheckedExtrinsic;
590}
591
592impl<LocalCall> frame_system::offchain::CreateTransaction<LocalCall> for Runtime
593where
594 RuntimeCall: From<LocalCall>,
595{
596 type Extension = TxExtension;
597
598 fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic {
599 UncheckedExtrinsic::new_transaction(call, extension)
600 }
601}
602
603impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
606where
607 RuntimeCall: From<LocalCall>,
608{
609 fn create_signed_transaction<
610 C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>,
611 >(
612 call: RuntimeCall,
613 public: <Signature as Verify>::Signer,
614 account: AccountId,
615 nonce: <Runtime as frame_system::Config>::Nonce,
616 ) -> Option<UncheckedExtrinsic> {
617 use sp_runtime::traits::StaticLookup;
618 let period =
620 BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
621
622 let current_block = System::block_number()
623 .saturated_into::<u64>()
624 .saturating_sub(1);
627 let tip = 0;
628 let tx_ext = TxExtension::from((
629 frame_system::CheckNonZeroSender::<Runtime>::new(),
630 frame_system::CheckSpecVersion::<Runtime>::new(),
631 frame_system::CheckTxVersion::<Runtime>::new(),
632 frame_system::CheckGenesis::<Runtime>::new(),
633 frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
634 frame_system::CheckNonce::<Runtime>::from(nonce),
635 frame_system::CheckWeight::<Runtime>::new(),
636 pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::<Runtime>::from(tip, None),
637 frame_metadata_hash_extension::CheckMetadataHash::<Runtime>::new(true),
638 ));
639 let raw_payload = SignedPayload::new(call, tx_ext)
640 .map_err(|e| {
641 log::warn!("Unable to create signed payload: {:?}", e);
642 })
643 .ok()?;
644 let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
645 let (call, tx_ext, _) = raw_payload.deconstruct();
646 let address = <Runtime as frame_system::Config>::Lookup::unlookup(account);
647 let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext);
648 Some(transaction)
649 }
650}
651
652impl<LocalCall> frame_system::offchain::CreateInherent<LocalCall> for Runtime
653where
654 RuntimeCall: From<LocalCall>,
655{
656 fn create_bare(call: RuntimeCall) -> UncheckedExtrinsic {
657 UncheckedExtrinsic::new_bare(call)
658 }
659}
660
661#[cfg(test)]
662mod tests {
663 use super::*;
664 use frame_election_provider_support::ElectionProvider;
665 use frame_support::weights::constants::{WEIGHT_PROOF_SIZE_PER_KB, WEIGHT_REF_TIME_PER_MILLIS};
666 use pallet_election_provider_multi_block::{
667 self as mb, signed::WeightInfo as _, unsigned::WeightInfo as _,
668 };
669 use remote_externalities::{
670 Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport,
671 };
672 use std::env::var;
673
674 fn weight_diff(block: Weight, op: Weight) {
675 log::info!(
676 target: "runtime",
677 "ref_time: {:?}ms {:.4} of total",
678 op.ref_time() / WEIGHT_REF_TIME_PER_MILLIS,
679 op.ref_time() as f64 / block.ref_time() as f64
680 );
681 log::info!(
682 target: "runtime",
683 "proof_size: {:?}kb {:.4} of total",
684 op.proof_size() / WEIGHT_PROOF_SIZE_PER_KB,
685 op.proof_size() as f64 / block.proof_size() as f64
686 );
687 }
688
689 #[test]
690 fn signed_weight_ratios() {
691 sp_tracing::try_init_simple();
692 let block_weight = <Runtime as frame_system::Config>::BlockWeights::get().max_block;
693 let polkadot_signed_submission =
694 mb::weights::polkadot::MultiBlockSignedWeightInfo::<Runtime>::submit_page();
695 let kusama_signed_submission =
696 mb::weights::kusama::MultiBlockSignedWeightInfo::<Runtime>::submit_page();
697
698 log::info!(target: "runtime", "Polkadot:");
699 weight_diff(block_weight, polkadot_signed_submission);
700 log::info!(target: "runtime", "Kusama:");
701 weight_diff(block_weight, kusama_signed_submission);
702 }
703
704 #[test]
705 fn election_duration() {
706 sp_tracing::try_init_simple();
707 sp_io::TestExternalities::default().execute_with(|| {
708 super::enable_dot_preset(false);
709 let duration = mb::Pallet::<Runtime>::average_election_duration();
710 let polkadot_session = 6 * HOURS;
711 log::info!(
712 target: "runtime",
713 "Polkadot election duration: {:?}, session: {:?} ({} sessions)",
714 duration,
715 polkadot_session,
716 duration / polkadot_session
717 );
718 });
719
720 sp_io::TestExternalities::default().execute_with(|| {
721 super::enable_ksm_preset(false);
722 let duration = mb::Pallet::<Runtime>::average_election_duration();
723 let kusama_session = 1 * HOURS;
724 log::info!(
725 target: "runtime",
726 "Kusama election duration: {:?}, session: {:?} ({} sessions)",
727 duration,
728 kusama_session,
729 duration / kusama_session
730 );
731 });
732 }
733
734 #[test]
735 fn max_ocw_miner_pages_as_per_weights() {
736 sp_tracing::try_init_simple();
737 for p in 1..=32 {
738 log::info!(
739 target: "runtime",
740 "exec_time of polkadot miner in WASM with {} pages is {:?}ms",
741 p,
742 mb::weights::polkadot::MultiBlockUnsignedWeightInfo::<Runtime>::mine_solution(p).ref_time() / WEIGHT_REF_TIME_PER_MILLIS
743 );
744 }
745 for p in 1..=16 {
746 log::info!(
747 target: "runtime",
748 "exec_time of kusama miner in WASM with {} pages is {:?}ms",
749 p,
750 mb::weights::kusama::MultiBlockUnsignedWeightInfo::<Runtime>::mine_solution(p).ref_time() / WEIGHT_REF_TIME_PER_MILLIS
751 );
752 }
753 }
754
755 #[tokio::test]
770 async fn run_election_with_pages() {
771 if var("REMOTE_TESTS").is_err() {
772 return;
773 }
774 sp_tracing::try_init_simple();
775
776 let transport: Transport =
777 var("WS").unwrap_or("wss://westend-rpc.polkadot.io:443".to_string()).into();
778 let maybe_state_snapshot: Option<SnapshotConfig> = var("SNAP").map(|s| s.into()).ok();
779
780 let mut ext = Builder::<Block>::default()
781 .mode(if let Some(state_snapshot) = maybe_state_snapshot {
782 Mode::OfflineOrElseOnline(
783 OfflineConfig { state_snapshot: state_snapshot.clone() },
784 OnlineConfig {
785 transport,
786 hashed_prefixes: vec![vec![]],
787 state_snapshot: Some(state_snapshot),
788 ..Default::default()
789 },
790 )
791 } else {
792 Mode::Online(OnlineConfig {
793 hashed_prefixes: vec![vec![]],
794 transport,
795 ..Default::default()
796 })
797 })
798 .build()
799 .await
800 .unwrap();
801 ext.execute_with(|| {
802 sp_core::crypto::set_default_ss58_version(1u8.into());
803 super::enable_dot_preset(true);
804
805 mb::Pallet::<Runtime>::asap();
807 for page in 1..=32 {
808 mb::unsigned::miner::OffchainWorkerMiner::<Runtime>::mine_solution(page, true)
809 .inspect(|p| log::info!(target: "runtime", "{:?}", p.score.pretty("DOT", 10)))
810 .unwrap();
811 }
812 });
813 }
814}