@@ -133,21 +133,92 @@ impl Solution {
133
133
#[ allow( clippy:: unwrap_in_result) ]
134
134
pub fn solve < F > (
135
135
mut header : Header ,
136
- mut _cancel_fn : F ,
136
+ mut cancel_fn : F ,
137
137
) -> Result < AtLeastOne < Header > , SolverCancelled >
138
138
where
139
139
F : FnMut ( ) -> Result < ( ) , SolverCancelled > ,
140
140
{
141
- // TODO: Function code was removed as part of https://github.com/ZcashFoundation/zebra/issues/8180
142
- // Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/src/work/equihash.rs#L115-L166
143
- // Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183
144
- header. solution = Solution :: for_proposal ( ) ;
145
- Ok ( AtLeastOne :: from_one ( header) )
141
+ use crate :: shutdown:: is_shutting_down;
142
+
143
+ let mut input = Vec :: new ( ) ;
144
+ header
145
+ . zcash_serialize ( & mut input)
146
+ . expect ( "serialization into a vec can't fail" ) ;
147
+ // Take the part of the header before the nonce and solution.
148
+ // This data is kept constant for this solver run.
149
+ let input = & input[ 0 ..Solution :: INPUT_LENGTH ] ;
150
+
151
+ while !is_shutting_down ( ) {
152
+ // Don't run the solver if we'd just cancel it anyway.
153
+ cancel_fn ( ) ?;
154
+
155
+ let solutions = equihash:: tromp:: solve_200_9 ( input, || {
156
+ // Cancel the solver if we have a new template.
157
+ if cancel_fn ( ) . is_err ( ) {
158
+ return None ;
159
+ }
160
+
161
+ // This skips the first nonce, which doesn't matter in practice.
162
+ Self :: next_nonce ( & mut header. nonce ) ;
163
+ Some ( * header. nonce )
164
+ } ) ;
165
+
166
+ let mut valid_solutions = Vec :: new ( ) ;
167
+
168
+ // If we got any solutions, try submitting them, because the new template might just
169
+ // contain some extra transactions. Mining extra transactions is optional.
170
+ for solution in & solutions {
171
+ header. solution = Self :: from_bytes ( solution)
172
+ . expect ( "unexpected invalid solution: incorrect length" ) ;
173
+
174
+ // TODO: work out why we sometimes get invalid solutions here
175
+ if let Err ( error) = header. solution . check ( & header) {
176
+ info ! ( ?error, "found invalid solution for header" ) ;
177
+ continue ;
178
+ }
179
+
180
+ if Self :: difficulty_is_valid ( & header) {
181
+ valid_solutions. push ( header) ;
182
+ }
183
+ }
184
+
185
+ match valid_solutions. try_into ( ) {
186
+ Ok ( at_least_one_solution) => return Ok ( at_least_one_solution) ,
187
+ Err ( _is_empty_error) => debug ! (
188
+ solutions = ?solutions. len( ) ,
189
+ "found valid solutions which did not pass the validity or difficulty checks"
190
+ ) ,
191
+ }
192
+ }
193
+
194
+ Err ( SolverCancelled )
146
195
}
147
196
148
- // TODO: Some methods were removed as part of https://github.com/ZcashFoundation/zebra/issues/8180
149
- // Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/src/work/equihash.rs#L171-L196
150
- // Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183
197
+ /// Returns `true` if the `nonce` and `solution` in `header` meet the difficulty threshold.
198
+ ///
199
+ /// Assumes that the difficulty threshold in the header is valid.
200
+ #[ cfg( feature = "internal-miner" ) ]
201
+ fn difficulty_is_valid ( header : & Header ) -> bool {
202
+ // Simplified from zebra_consensus::block::check::difficulty_is_valid().
203
+ let difficulty_threshold = header
204
+ . difficulty_threshold
205
+ . to_expanded ( )
206
+ . expect ( "unexpected invalid header template: invalid difficulty threshold" ) ;
207
+
208
+ // TODO: avoid calculating this hash multiple times
209
+ let hash = header. hash ( ) ;
210
+
211
+ // Note: this comparison is a u256 integer comparison, like zcashd and bitcoin. Greater
212
+ // values represent *less* work.
213
+ hash <= difficulty_threshold
214
+ }
215
+
216
+ /// Modifies `nonce` to be the next integer in big-endian order.
217
+ /// Wraps to zero if the next nonce would overflow.
218
+ #[ cfg( feature = "internal-miner" ) ]
219
+ fn next_nonce ( nonce : & mut [ u8 ; 32 ] ) {
220
+ let _ignore_overflow = crate :: primitives:: byte_array:: increment_big_endian ( & mut nonce[ ..] ) ;
221
+ }
151
222
}
152
223
153
224
impl PartialEq < Solution > for Solution {
0 commit comments