1use alloy_primitives::B256;
2use std::sync::{
3 Arc,
4 atomic::{AtomicBool, Ordering},
5};
6
7pub(crate) fn mine_salt<T, F>(salt: B256, n_threads: usize, check: F) -> Option<T>
12where
13 T: Send + 'static,
14 F: FnMut(B256) -> Option<T> + Clone + Send + 'static,
15{
16 let found = Arc::new(AtomicBool::new(false));
17 let mut handles = Vec::with_capacity(n_threads);
18
19 for i in 0..n_threads {
20 let increment = n_threads;
21 let found = Arc::clone(&found);
22 let mut check = check.clone();
23
24 handles.push(std::thread::spawn(move || {
25 #[repr(C)]
26 struct B256Aligned(B256, [usize; 0]);
27
28 let mut salt = B256Aligned(salt, []);
29 let salt_word = unsafe {
31 &mut *salt.0.as_mut_ptr().add(32 - usize::BITS as usize / 8).cast::<usize>()
32 };
33 *salt_word = salt_word.wrapping_add(i);
35
36 loop {
37 if found.load(Ordering::Relaxed) {
38 break None;
39 }
40
41 if let Some(result) = check(salt.0) {
42 found.store(true, Ordering::Relaxed);
43 break Some(result);
44 }
45
46 *salt_word = salt_word.wrapping_add(increment);
47 }
48 }));
49 }
50
51 handles.into_iter().find_map(|h| h.join().ok().flatten())
52}