@@ -107,6 +107,61 @@ impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
107
107
}
108
108
}
109
109
110
+ /// Splits candidate solutions into a collection of accepted ones and aborted ones.
111
+ pub fn split_candidate_solutions < T , F > (
112
+ mut candidate_solutions : Vec < T > ,
113
+ max_solutions : usize ,
114
+ verification_fn : F ,
115
+ ) -> ( Vec < T > , Vec < T > )
116
+ where
117
+ T : Sized + Send ,
118
+ F : Fn ( & T ) -> bool + Send + Sync ,
119
+ {
120
+ // Separate the candidate solutions into valid and aborted solutions.
121
+ let mut valid_candidate_solutions = Vec :: with_capacity ( max_solutions) ;
122
+ let mut aborted_candidate_solutions = Vec :: new ( ) ;
123
+ // Reverse the candidate solutions in order to be able to chunk them more efficiently.
124
+ candidate_solutions. reverse ( ) ;
125
+ // Verify the candidate solutions in chunks. This is done so that we can potentially
126
+ // perform these operations in parallel while keeping the end result deterministic.
127
+ let chunk_size = 16 ;
128
+ while !candidate_solutions. is_empty ( ) {
129
+ // Check if the collection of valid solutions is full.
130
+ if valid_candidate_solutions. len ( ) >= max_solutions {
131
+ // If that's the case, mark the rest of the candidates as aborted.
132
+ aborted_candidate_solutions. extend ( candidate_solutions. into_iter ( ) . rev ( ) ) ;
133
+ break ;
134
+ }
135
+
136
+ // Split off a chunk of the candidate solutions.
137
+ let candidates_chunk = if candidate_solutions. len ( ) > chunk_size {
138
+ candidate_solutions. split_off ( candidate_solutions. len ( ) - chunk_size)
139
+ } else {
140
+ std:: mem:: take ( & mut candidate_solutions)
141
+ } ;
142
+
143
+ // Verify the solutions in the chunk.
144
+ let verification_results: Vec < _ > = cfg_into_iter ! ( candidates_chunk)
145
+ . rev ( )
146
+ . map ( |solution| {
147
+ let verified = verification_fn ( & solution) ;
148
+ ( solution, verified)
149
+ } )
150
+ . collect ( ) ;
151
+
152
+ // Process the results of the verification.
153
+ for ( solution, is_valid) in verification_results. into_iter ( ) {
154
+ if is_valid && valid_candidate_solutions. len ( ) < max_solutions {
155
+ valid_candidate_solutions. push ( solution) ;
156
+ } else {
157
+ aborted_candidate_solutions. push ( solution) ;
158
+ }
159
+ }
160
+ }
161
+
162
+ ( valid_candidate_solutions, aborted_candidate_solutions)
163
+ }
164
+
110
165
impl < N : Network , C : ConsensusStorage < N > > Ledger < N , C > {
111
166
/// Constructs a block template for the next block in the ledger.
112
167
#[ allow( clippy:: type_complexity) ]
@@ -127,28 +182,14 @@ impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
127
182
let coinbase_verifying_key = self . coinbase_puzzle . coinbase_verifying_key ( ) ;
128
183
// Retrieve the latest epoch challenge.
129
184
let latest_epoch_challenge = self . latest_epoch_challenge ( ) ?;
130
- // TODO: For mainnet - Add `aborted_solution_ids` to the block. And optimize this logic.
131
- // Verify the candidate solutions.
132
- let verification_results: Vec < _ > = cfg_into_iter ! ( candidate_solutions)
133
- . map ( |solution| {
134
- (
135
- solution,
136
- solution
137
- . verify ( coinbase_verifying_key, & latest_epoch_challenge, self . latest_proof_target ( ) )
138
- . unwrap_or ( false ) ,
139
- )
140
- } )
141
- . collect ( ) ;
185
+ // TODO: For mainnet - Add `aborted_solution_ids` to the block.
142
186
// Separate the candidate solutions into valid and aborted solutions.
143
- let mut valid_candidate_solutions = Vec :: with_capacity ( N :: MAX_SOLUTIONS ) ;
144
- let mut aborted_candidate_solutions = Vec :: new ( ) ;
145
- for ( solution, is_valid) in verification_results. into_iter ( ) {
146
- if is_valid && valid_candidate_solutions. len ( ) < N :: MAX_SOLUTIONS {
147
- valid_candidate_solutions. push ( solution) ;
148
- } else {
149
- aborted_candidate_solutions. push ( solution) ;
150
- }
151
- }
187
+ let ( valid_candidate_solutions, _aborted_candidate_solutions) =
188
+ split_candidate_solutions ( candidate_solutions, N :: MAX_SOLUTIONS , |solution| {
189
+ solution
190
+ . verify ( coinbase_verifying_key, & latest_epoch_challenge, self . latest_proof_target ( ) )
191
+ . unwrap_or ( false )
192
+ } ) ;
152
193
153
194
// Check if there are any valid solutions.
154
195
match valid_candidate_solutions. is_empty ( ) {
0 commit comments