diff --git a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs index 100e09c4b7..5b0dae7ea6 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs @@ -65,7 +65,7 @@ pub fn randomx_difficulty( let monero_pow_data = verify_header(header, genesis_block_hash, consensus)?; trace!(target: LOG_TARGET, "Valid Monero data: {}", monero_pow_data); let blockhashing_blob = monero_pow_data.to_blockhashing_blob(); - let vm = randomx_factory.create(monero_pow_data.randomx_key(), None, None)?; + let vm = randomx_factory.create(monero_pow_data.randomx_key())?; get_random_x_difficulty(&blockhashing_blob, &vm).map(|(diff, _)| diff) } @@ -1245,7 +1245,7 @@ mod test { let key = from_hex("2aca6501719a5c7ab7d4acbc7cc5d277b57ad8c27c6830788c2d5a596308e5b1").unwrap(); let rx = RandomXFactory::default(); - let (difficulty, hash) = get_random_x_difficulty(&input, &rx.create(&key, None, None).unwrap()).unwrap(); + let (difficulty, hash) = get_random_x_difficulty(&input, &rx.create(&key).unwrap()).unwrap(); assert_eq!( hash.to_hex(), "f68fbc8cc85bde856cd1323e9f8e6f024483038d728835de2f8c014ff6260000" diff --git a/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs b/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs index 93184fa968..faaeeba537 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs @@ -423,7 +423,7 @@ mod test { fn randomx_hash(input: &[u8], key: &str) -> String { let key = from_hex(key).unwrap(); RandomXFactory::default() - .create(&key, None, None) + .create(&key) .unwrap() .calculate_hash(input) .unwrap() diff --git a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs index 23b9131967..14ebf802e0 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs @@ -47,7 +47,7 @@ use crate::{ proof_of_work::monero_rx::helpers::create_block_hashing_blob, }; -/// This is a struct to deserialize the data from the pow field into data required for the randomX Monero merged mine +/// This is a struct to deserialize the data from he pow field into data required for the randomX Monero merged mine /// pow. #[derive(Clone, Debug)] pub struct MoneroPowData { diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index 4f96871f0f..fb4889d3fa 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -9,7 +9,7 @@ use std::{ }; use log::*; -use randomx_rs::{RandomXCache, RandomXDataset, RandomXError, RandomXFlag, RandomXVM}; +use randomx_rs::{RandomXCache, RandomXError, RandomXFlag, RandomXVM}; const LOG_TARGET: &str = "c::pow::randomx_factory"; @@ -35,21 +35,32 @@ pub struct RandomXVMInstance { } impl RandomXVMInstance { - fn create( - key: &[u8], - flags: RandomXFlag, - cache: Option, - dataset: Option, - ) -> Result { + fn create(key: &[u8], flags: RandomXFlag) -> Result { + let (flags, cache) = match RandomXCache::new(flags, key) { + Ok(cache) => (flags, cache), + Err(err) => { + warn!( + target: LOG_TARGET, + "Error initializing RandomX cache with flags {:?}. {:?}. Fallback to default flags", flags, err + ); + // This is informed by how RandomX falls back on any cache allocation failure + // https://github.com/xmrig/xmrig/blob/02b2b87bb685ab83b132267aa3c2de0766f16b8b/src/crypto/rx/RxCache.cpp#L88 + let flags = RandomXFlag::FLAG_DEFAULT; + let cache = RandomXCache::new(flags, key)?; + (flags, cache) + }, + }; + // Note: Memory required per VM in light mode is 256MB + let vm = RandomXVM::new(flags, Some(cache), None)?; + + // Note: No dataset is initialized here because we want to run in light mode. Only a cache + // is required by the VM for verification, giving it a dataset will only make the VM + // consume more memory than necessary. Dataset is currently an optional value as it may be + // useful at some point in future. // Note: RandomXFlag::FULL_MEM and RandomXFlag::LARGE_PAGES are incompatible with // light mode. These are not set by RandomX automatically even in fast mode. - let cache = match cache { - Some(c) => c, - None => RandomXCache::new(flags, key)?, - }; - let vm = RandomXVM::new(flags, Some(cache), dataset)?; Ok(Self { #[allow(clippy::arc_with_non_send_sync)] @@ -95,26 +106,15 @@ impl RandomXFactory { } } - pub fn new_with_flags(max_vms: usize, flags: RandomXFlag) -> Self { - Self { - inner: Arc::new(RwLock::new(RandomXFactoryInner::new_with_flags(max_vms, flags))), - } - } - /// Create a new RandomX VM instance with the specified key - pub fn create( - &self, - key: &[u8], - cache: Option, - dataset: Option, - ) -> Result { + pub fn create(&self, key: &[u8]) -> Result { let res; { let mut inner = self .inner .write() .map_err(|_| RandomXVMFactoryError::PoisonedLockError)?; - res = inner.create(key, cache, dataset)?; + res = inner.create(key)?; } Ok(res) } @@ -158,25 +158,8 @@ impl RandomXFactoryInner { } } - pub(crate) fn new_with_flags(max_vms: usize, flags: RandomXFlag) -> Self { - debug!( - target: LOG_TARGET, - "RandomX factory started with {} max VMs and recommended flags = {:?}", max_vms, flags - ); - Self { - flags, - vms: Default::default(), - max_vms, - } - } - /// Create a new RandomXVMInstance - pub(crate) fn create( - &mut self, - key: &[u8], - cache: Option, - dataset: Option, - ) -> Result { + pub(crate) fn create(&mut self, key: &[u8]) -> Result { if let Some(entry) = self.vms.get_mut(key) { let vm = entry.1.clone(); entry.0 = Instant::now(); @@ -184,12 +167,20 @@ impl RandomXFactoryInner { } if self.vms.len() >= self.max_vms { - if let Some(oldest_key) = self.vms.iter().min_by_key(|(_, (i, _))| *i).map(|(k, _)| k.clone()) { - self.vms.remove(&oldest_key); + let mut oldest_value = Instant::now(); + let mut oldest_key = None; + for (k, v) in &self.vms { + if v.0 < oldest_value { + oldest_key = Some(k.clone()); + oldest_value = v.0; + } + } + if let Some(k) = oldest_key { + self.vms.remove(&k); } } - let vm = RandomXVMInstance::create(key, self.flags, cache, dataset)?; + let vm = RandomXVMInstance::create(key, self.flags)?; self.vms.insert(Vec::from(key), (Instant::now(), vm.clone())); @@ -225,14 +216,14 @@ mod test { let factory = RandomXFactory::new(2); let key = b"some-key"; - let vm = factory.create(&key[..], None, None).unwrap(); + let vm = factory.create(&key[..]).unwrap(); let preimage = b"hashme"; let hash1 = vm.calculate_hash(&preimage[..]).unwrap(); - let vm = factory.create(&key[..], None, None).unwrap(); + let vm = factory.create(&key[..]).unwrap(); assert_eq!(vm.calculate_hash(&preimage[..]).unwrap(), hash1); let key = b"another-key"; - let vm = factory.create(&key[..], None, None).unwrap(); + let vm = factory.create(&key[..]).unwrap(); assert_ne!(vm.calculate_hash(&preimage[..]).unwrap(), hash1); } @@ -245,7 +236,7 @@ mod test { let factory = factory.clone(); threads.push(tokio::spawn(async move { let key = b"some-key"; - let vm = factory.create(&key[..], None, None).unwrap(); + let vm = factory.create(&key[..]).unwrap(); let preimage = b"hashme"; let _hash = vm.calculate_hash(&preimage[..]).unwrap(); }));