@@ -247,10 +247,7 @@ use sp_arithmetic::{
247
247
traits:: { CheckedAdd , Zero } ,
248
248
UpperOf ,
249
249
} ;
250
- use sp_npos_elections:: {
251
- assignment_ratio_to_staked_normalized, BoundedSupports , ElectionScore , EvaluateSupport ,
252
- Supports , VoteWeight ,
253
- } ;
250
+ use sp_npos_elections:: { BoundedSupports , ElectionScore , IdentifierT , Supports , VoteWeight } ;
254
251
use sp_runtime:: {
255
252
transaction_validity:: {
256
253
InvalidTransaction , TransactionPriority , TransactionSource , TransactionValidity ,
@@ -430,13 +427,17 @@ impl<C: Default> Default for RawSolution<C> {
430
427
DefaultNoBound ,
431
428
scale_info:: TypeInfo ,
432
429
) ]
433
- #[ scale_info( skip_type_params( T ) ) ]
434
- pub struct ReadySolution < T : Config > {
430
+ #[ scale_info( skip_type_params( AccountId , MaxWinners ) ) ]
431
+ pub struct ReadySolution < AccountId , MaxWinners >
432
+ where
433
+ AccountId : IdentifierT ,
434
+ MaxWinners : Get < u32 > ,
435
+ {
435
436
/// The final supports of the solution.
436
437
///
437
438
/// This is target-major vector, storing each winners, total backing, and each individual
438
439
/// backer.
439
- pub supports : BoundedSupports < T :: AccountId , T :: MaxWinners > ,
440
+ pub supports : BoundedSupports < AccountId , MaxWinners > ,
440
441
/// The score of the solution.
441
442
///
442
443
/// This is needed to potentially challenge the solution.
@@ -451,11 +452,11 @@ pub struct ReadySolution<T: Config> {
451
452
/// These are stored together because they are often accessed together.
452
453
#[ derive( PartialEq , Eq , Clone , Encode , Decode , RuntimeDebug , Default , TypeInfo ) ]
453
454
#[ scale_info( skip_type_params( T ) ) ]
454
- pub struct RoundSnapshot < T : Config > {
455
+ pub struct RoundSnapshot < AccountId , DataProvider > {
455
456
/// All of the voters.
456
- pub voters : Vec < VoterOf < T > > ,
457
+ pub voters : Vec < DataProvider > ,
457
458
/// All of the targets.
458
- pub targets : Vec < T :: AccountId > ,
459
+ pub targets : Vec < AccountId > ,
459
460
}
460
461
461
462
/// Encodes the length of a solution or a snapshot.
@@ -614,6 +615,7 @@ pub mod pallet {
614
615
type MinerConfig : crate :: unsigned:: MinerConfig <
615
616
AccountId = Self :: AccountId ,
616
617
MaxVotesPerVoter = <Self :: DataProvider as ElectionDataProvider >:: MaxVotesPerVoter ,
618
+ MaxWinners = Self :: MaxWinners ,
617
619
> ;
618
620
619
621
/// Maximum number of signed submissions that can be queued.
@@ -733,6 +735,11 @@ pub mod pallet {
733
735
fn max_votes_per_voter ( ) -> u32 {
734
736
<T :: MinerConfig as MinerConfig >:: MaxVotesPerVoter :: get ( )
735
737
}
738
+
739
+ #[ pallet:: constant_name( MinerMaxWinners ) ]
740
+ fn max_winners ( ) -> u32 {
741
+ <T :: MinerConfig as MinerConfig >:: MaxWinners :: get ( )
742
+ }
736
743
}
737
744
738
745
#[ pallet:: hooks]
@@ -1247,14 +1254,15 @@ pub mod pallet {
1247
1254
/// Current best solution, signed or unsigned, queued to be returned upon `elect`.
1248
1255
#[ pallet:: storage]
1249
1256
#[ pallet:: getter( fn queued_solution) ]
1250
- pub type QueuedSolution < T : Config > = StorageValue < _ , ReadySolution < T > > ;
1257
+ pub type QueuedSolution < T : Config > =
1258
+ StorageValue < _ , ReadySolution < T :: AccountId , T :: MaxWinners > > ;
1251
1259
1252
1260
/// Snapshot data of the round.
1253
1261
///
1254
1262
/// This is created at the beginning of the signed phase and cleared upon calling `elect`.
1255
1263
#[ pallet:: storage]
1256
1264
#[ pallet:: getter( fn snapshot) ]
1257
- pub type Snapshot < T : Config > = StorageValue < _ , RoundSnapshot < T > > ;
1265
+ pub type Snapshot < T : Config > = StorageValue < _ , RoundSnapshot < T :: AccountId , VoterOf < T > > > ;
1258
1266
1259
1267
/// Desired number of targets to elect for this round.
1260
1268
///
@@ -1385,7 +1393,7 @@ impl<T: Config> Pallet<T> {
1385
1393
// instead of using storage APIs, we do a manual encoding into a fixed-size buffer.
1386
1394
// `encoded_size` encodes it without storing it anywhere, this should not cause any
1387
1395
// allocation.
1388
- let snapshot = RoundSnapshot :: < T > { voters, targets } ;
1396
+ let snapshot = RoundSnapshot :: < T :: AccountId , VoterOf < T > > { voters, targets } ;
1389
1397
let size = snapshot. encoded_size ( ) ;
1390
1398
log ! ( debug, "snapshot pre-calculated size {:?}" , size) ;
1391
1399
let mut buffer = Vec :: with_capacity ( size) ;
@@ -1479,89 +1487,22 @@ impl<T: Config> Pallet<T> {
1479
1487
pub fn feasibility_check (
1480
1488
raw_solution : RawSolution < SolutionOf < T :: MinerConfig > > ,
1481
1489
compute : ElectionCompute ,
1482
- ) -> Result < ReadySolution < T > , FeasibilityError > {
1483
- let RawSolution { solution, score, round } = raw_solution;
1484
-
1485
- // First, check round.
1486
- ensure ! ( Self :: round( ) == round, FeasibilityError :: InvalidRound ) ;
1487
-
1488
- // Winners are not directly encoded in the solution.
1489
- let winners = solution. unique_targets ( ) ;
1490
-
1490
+ ) -> Result < ReadySolution < T :: AccountId , T :: MaxWinners > , FeasibilityError > {
1491
1491
let desired_targets =
1492
1492
Self :: desired_targets ( ) . ok_or ( FeasibilityError :: SnapshotUnavailable ) ?;
1493
1493
1494
- ensure ! ( winners. len( ) as u32 == desired_targets, FeasibilityError :: WrongWinnerCount ) ;
1495
- // Fail early if targets requested by data provider exceed maximum winners supported.
1496
- ensure ! (
1497
- desired_targets <= <T as pallet:: Config >:: MaxWinners :: get( ) ,
1498
- FeasibilityError :: TooManyDesiredTargets
1499
- ) ;
1500
-
1501
- // Ensure that the solution's score can pass absolute min-score.
1502
- let submitted_score = raw_solution. score ;
1503
- ensure ! (
1504
- Self :: minimum_untrusted_score( ) . map_or( true , |min_score| {
1505
- submitted_score. strict_threshold_better( min_score, Perbill :: zero( ) )
1506
- } ) ,
1507
- FeasibilityError :: UntrustedScoreTooLow
1508
- ) ;
1509
-
1510
- // Read the entire snapshot.
1511
- let RoundSnapshot { voters : snapshot_voters, targets : snapshot_targets } =
1512
- Self :: snapshot ( ) . ok_or ( FeasibilityError :: SnapshotUnavailable ) ?;
1513
-
1514
- // ----- Start building. First, we need some closures.
1515
- let cache = helpers:: generate_voter_cache :: < T :: MinerConfig > ( & snapshot_voters) ;
1516
- let voter_at = helpers:: voter_at_fn :: < T :: MinerConfig > ( & snapshot_voters) ;
1517
- let target_at = helpers:: target_at_fn :: < T :: MinerConfig > ( & snapshot_targets) ;
1518
- let voter_index = helpers:: voter_index_fn_usize :: < T :: MinerConfig > ( & cache) ;
1519
-
1520
- // Then convert solution -> assignment. This will fail if any of the indices are gibberish,
1521
- // namely any of the voters or targets.
1522
- let assignments = solution
1523
- . into_assignment ( voter_at, target_at)
1524
- . map_err :: < FeasibilityError , _ > ( Into :: into) ?;
1525
-
1526
- // Ensure that assignments is correct.
1527
- let _ = assignments. iter ( ) . try_for_each ( |assignment| {
1528
- // Check that assignment.who is actually a voter (defensive-only).
1529
- // NOTE: while using the index map from `voter_index` is better than a blind linear
1530
- // search, this *still* has room for optimization. Note that we had the index when
1531
- // we did `solution -> assignment` and we lost it. Ideal is to keep the index
1532
- // around.
1533
-
1534
- // Defensive-only: must exist in the snapshot.
1535
- let snapshot_index =
1536
- voter_index ( & assignment. who ) . ok_or ( FeasibilityError :: InvalidVoter ) ?;
1537
- // Defensive-only: index comes from the snapshot, must exist.
1538
- let ( _voter, _stake, targets) =
1539
- snapshot_voters. get ( snapshot_index) . ok_or ( FeasibilityError :: InvalidVoter ) ?;
1540
-
1541
- // Check that all of the targets are valid based on the snapshot.
1542
- if assignment. distribution . iter ( ) . any ( |( d, _) | !targets. contains ( d) ) {
1543
- return Err ( FeasibilityError :: InvalidVote )
1544
- }
1545
- Ok ( ( ) )
1546
- } ) ?;
1547
-
1548
- // ----- Start building support. First, we need one more closure.
1549
- let stake_of = helpers:: stake_of_fn :: < T :: MinerConfig > ( & snapshot_voters, & cache) ;
1550
-
1551
- // This might fail if the normalization fails. Very unlikely. See `integrity_test`.
1552
- let staked_assignments = assignment_ratio_to_staked_normalized ( assignments, stake_of)
1553
- . map_err :: < FeasibilityError , _ > ( Into :: into) ?;
1554
- let supports = sp_npos_elections:: to_supports ( & staked_assignments) ;
1555
-
1556
- // Finally, check that the claimed score was indeed correct.
1557
- let known_score = supports. evaluate ( ) ;
1558
- ensure ! ( known_score == score, FeasibilityError :: InvalidScore ) ;
1559
-
1560
- // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`.
1561
- let supports = supports
1562
- . try_into ( )
1563
- . defensive_map_err ( |_| FeasibilityError :: BoundedConversionFailed ) ?;
1564
- Ok ( ReadySolution { supports, compute, score } )
1494
+ let snapshot = Self :: snapshot ( ) . ok_or ( FeasibilityError :: SnapshotUnavailable ) ?;
1495
+ let round = Self :: round ( ) ;
1496
+ let minimum_untrusted_score = Self :: minimum_untrusted_score ( ) ;
1497
+
1498
+ Miner :: < T :: MinerConfig > :: feasibility_check (
1499
+ raw_solution,
1500
+ compute,
1501
+ desired_targets,
1502
+ snapshot,
1503
+ round,
1504
+ minimum_untrusted_score,
1505
+ )
1565
1506
}
1566
1507
1567
1508
/// Perform the tasks to be done after a new `elect` has been triggered:
0 commit comments