darkfi/validator/
randomx_factory.rs1use std::{
21 collections::HashMap,
22 fmt,
23 sync::{Arc, RwLock},
24 time::Instant,
25};
26
27use randomx::{RandomXCache, RandomXFlags, RandomXVM};
28use tracing::{debug, warn};
29
30use crate::Result;
31
32#[derive(Clone)]
35pub struct RandomXVMInstance {
36 instance: Arc<RwLock<RandomXVM>>,
37}
38
39impl RandomXVMInstance {
40 fn create(key: &[u8]) -> Result<Self> {
43 let flags = RandomXFlags::get_recommended_flags();
44 let (flags, cache) = match RandomXCache::new(flags, key) {
45 Ok(cache) => (flags, cache),
46 Err(err) => {
47 warn!(target: "validator::randomx", "[VALIDATOR] Error initializing RandomX cache with flags {flags:?}: {err}");
48 warn!(target: "validator::randomx", "[VALIDATOR] Falling back to default flags");
49 let flags = RandomXFlags::DEFAULT;
50 let cache = RandomXCache::new(flags, key)?;
51 (flags, cache)
52 }
53 };
54
55 let vm = RandomXVM::new(flags, Some(cache), None)?;
56 debug!(target: "validator::randomx", "[VALIDATOR] RandomX VM started with flags = {flags:?}");
57
58 Ok(Self { instance: Arc::new(RwLock::new(vm)) })
59 }
60
61 pub fn calculate_hash(&self, input: &[u8]) -> Result<Vec<u8>> {
63 let lock = self.instance.write().unwrap();
64 Ok(lock.calculate_hash(input)?)
65 }
66}
67
68unsafe impl Send for RandomXVMInstance {}
69unsafe impl Sync for RandomXVMInstance {}
70
71#[derive(Clone, Debug)]
73pub struct RandomXFactory {
74 inner: Arc<RwLock<RandomXFactoryInner>>,
76}
77
78impl Default for RandomXFactory {
79 fn default() -> Self {
80 Self::new(2)
81 }
82}
83
84impl RandomXFactory {
85 pub fn new(max_vms: usize) -> Self {
87 Self { inner: Arc::new(RwLock::new(RandomXFactoryInner::new(max_vms))) }
88 }
89
90 pub fn create(&self, key: &[u8]) -> Result<RandomXVMInstance> {
92 let res;
93 {
94 let mut inner = self.inner.write().unwrap();
95 res = inner.create(key)?;
96 }
97 Ok(res)
98 }
99
100 pub fn get_count(&self) -> Result<usize> {
103 let inner = self.inner.read().unwrap();
104 Ok(inner.get_count())
105 }
106}
107
108struct RandomXFactoryInner {
109 vms: HashMap<Vec<u8>, (Instant, RandomXVMInstance)>,
110 max_vms: usize,
111}
112
113impl RandomXFactoryInner {
114 pub(crate) fn new(max_vms: usize) -> Self {
116 debug!(target: "validator::randomx", "[VALIDATOR] RandomXFactory started with {max_vms} max VMs");
117 Self { vms: Default::default(), max_vms }
118 }
119
120 pub(crate) fn create(&mut self, key: &[u8]) -> Result<RandomXVMInstance> {
122 if let Some(entry) = self.vms.get_mut(key) {
123 let vm = entry.1.clone();
124 entry.0 = Instant::now();
125 return Ok(vm)
126 }
127
128 if self.vms.len() >= self.max_vms {
129 if let Some(oldest_key) =
130 self.vms.iter().min_by_key(|(_, (i, _))| *i).map(|(k, _)| k.clone())
131 {
132 self.vms.remove(&oldest_key);
133 }
134 }
135
136 let vm = RandomXVMInstance::create(key)?;
137 self.vms.insert(Vec::from(key), (Instant::now(), vm.clone()));
138 Ok(vm)
139 }
140
141 pub(crate) fn get_count(&self) -> usize {
143 self.vms.len()
144 }
145}
146
147impl fmt::Debug for RandomXFactoryInner {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.debug_struct("RandomXFactory").field("max_vms", &self.max_vms).finish()
150 }
151}