Skip to content

Commit

Permalink
fix: fallback to default flags if rxcache initialization fails (#3087)
Browse files Browse the repository at this point in the history
  • Loading branch information
stringhandler committed Jul 14, 2021
2 parents 043f27d + b8d8418 commit eace2ff
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 34 deletions.
4 changes: 2 additions & 2 deletions applications/tari_base_node/src/builder.rs
Expand Up @@ -31,7 +31,7 @@ use tari_core::{
chain_storage::{create_lmdb_database, BlockchainDatabase, BlockchainDatabaseConfig, LMDBDatabase, Validators},
consensus::ConsensusManager,
mempool::{service::LocalMempoolService, Mempool, MempoolConfig},
proof_of_work::randomx_factory::{RandomXConfig, RandomXFactory},
proof_of_work::randomx_factory::RandomXFactory,
transactions::types::CryptoFactories,
validation::{
block_validators::{BodyOnlyValidator, OrphanBlockValidator},
Expand Down Expand Up @@ -201,7 +201,7 @@ async fn build_node_context(

let rules = ConsensusManager::builder(config.network).build();
let factories = CryptoFactories::default();
let randomx_factory = RandomXFactory::new(RandomXConfig::default(), config.max_randomx_vms);
let randomx_factory = RandomXFactory::new(config.max_randomx_vms);
let validators = Validators::new(
BodyOnlyValidator::default(),
HeaderValidator::new(rules.clone()),
Expand Down
4 changes: 2 additions & 2 deletions applications/tari_base_node/src/recovery.rs
Expand Up @@ -42,7 +42,7 @@ use tari_core::{
Validators,
},
consensus::ConsensusManager,
proof_of_work::randomx_factory::{RandomXConfig, RandomXFactory},
proof_of_work::randomx_factory::RandomXFactory,
transactions::types::CryptoFactories,
validation::{
block_validators::{BodyOnlyValidator, OrphanBlockValidator},
Expand Down Expand Up @@ -94,7 +94,7 @@ pub async fn run_recovery(node_config: &GlobalConfig) -> Result<(), anyhow::Erro
};
let rules = ConsensusManager::builder(node_config.network).build();
let factories = CryptoFactories::default();
let randomx_factory = RandomXFactory::new(RandomXConfig::default(), node_config.max_randomx_vms);
let randomx_factory = RandomXFactory::new(node_config.max_randomx_vms);
let validators = Validators::new(
BodyOnlyValidator::default(),
HeaderValidator::new(rules.clone()),
Expand Down
Expand Up @@ -34,7 +34,7 @@ use crate::{
},
chain_storage::{async_db::AsyncBlockchainDb, BlockchainBackend},
consensus::ConsensusManager,
proof_of_work::randomx_factory::{RandomXConfig, RandomXFactory},
proof_of_work::randomx_factory::RandomXFactory,
transactions::types::CryptoFactories,
};
use log::*;
Expand Down Expand Up @@ -112,7 +112,7 @@ where B: BlockchainBackend + 'static
sync_validators,
status_event_sender,
state_event_publisher,
RandomXFactory::new(RandomXConfig::default(), max_randomx_vms),
RandomXFactory::new(max_randomx_vms),
rules,
handles.get_shutdown_signal(),
);
Expand Down
89 changes: 61 additions & 28 deletions base_layer/core/src/proof_of_work/randomx_factory.rs
Expand Up @@ -9,38 +9,38 @@ use std::{

const LOG_TARGET: &str = "c::pow::randomx_factory";

#[derive(Default)]
pub struct RandomXConfig {
pub use_large_pages: bool,
}

impl From<&RandomXConfig> for RandomXFlag {
fn from(source: &RandomXConfig) -> Self {
let mut result = RandomXFlag::get_recommended_flags();
if source.use_large_pages {
result |= RandomXFlag::FLAG_LARGE_PAGES
}
result
}
}

#[derive(Clone)]
pub struct RandomXVMInstance {
// Note: If the cache and dataset drops, the vm will be wonky, so have to store all
// three for now
instance: Arc<Mutex<(RandomXVM, RandomXCache, RandomXDataset)>>,
flags: RandomXFlag,
}

impl RandomXVMInstance {
// Note: Can maybe even get more gains by creating a new VM and sharing the dataset and cache
pub fn new(key: &[u8]) -> Result<Self, RandomXError> {
let flags = RandomXFlag::get_recommended_flags();
let cache = RandomXCache::new(flags, key)?;
fn create(key: &[u8], flags: RandomXFlag) -> Result<Self, RandomXError> {
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)
},
};

let dataset = RandomXDataset::new(flags, &cache, 0)?;
let vm = RandomXVM::new(flags, Some(&cache), Some(&dataset))?;

Ok(Self {
instance: Arc::new(Mutex::new((vm, cache, dataset))),
flags,
})
}

Expand All @@ -60,14 +60,14 @@ pub struct RandomXFactory {

impl Default for RandomXFactory {
fn default() -> Self {
Self::new(RandomXConfig::default(), 2)
Self::new(2)
}
}

impl RandomXFactory {
pub fn new(config: RandomXConfig, max_vms: usize) -> Self {
pub fn new(max_vms: usize) -> Self {
Self {
inner: Arc::new(RwLock::new(RandomXFactoryInner::new(config, max_vms))),
inner: Arc::new(RwLock::new(RandomXFactoryInner::new(max_vms))),
}
}

Expand All @@ -82,16 +82,20 @@ impl RandomXFactory {
}

struct RandomXFactoryInner {
// config: RandomXConfig,
flags: RandomXFlag,
vms: HashMap<Vec<u8>, (Instant, RandomXVMInstance)>,
max_vms: usize,
}

impl RandomXFactoryInner {
pub fn new(_config: RandomXConfig, max_vms: usize) -> Self {
debug!(target: LOG_TARGET, "RandomX factory started with {} max VMs", max_vms);
pub fn new(max_vms: usize) -> Self {
let flags = RandomXFlag::get_recommended_flags();
debug!(
target: LOG_TARGET,
"RandomX factory started with {} max VMs and flags = {:?}", max_vms, flags
);
Self {
// config,
flags,
vms: Default::default(),
max_vms,
}
Expand All @@ -118,12 +122,41 @@ impl RandomXFactoryInner {
}
}

// TODO: put config in.

let vm = RandomXVMInstance::new(&key)?;
let vm = RandomXVMInstance::create(&key, self.flags)?;

self.vms.insert(Vec::from(key), (Instant::now(), vm.clone()));

Ok(vm)
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn basic_initialization_and_hash() {
let factory = RandomXFactory::new(2);

let key = b"some-key";
let vm = factory.create(&key[..]).unwrap();
let preimage = b"hashme";
let hash1 = vm.calculate_hash(&preimage[..]).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[..]).unwrap();
assert_ne!(vm.calculate_hash(&preimage[..]).unwrap(), hash1);
}

#[test]
fn large_page_fallback() {
// This only tests the fallback branch on platforms that do not support large pages (e.g. MacOS)
let factory = RandomXFactory::new(1);
factory.inner.write().unwrap().flags = RandomXFlag::FLAG_LARGE_PAGES;
let key = "highly-imaginative-key-name";
let vm = factory.create(key.as_bytes()).unwrap();
vm.calculate_hash("hashme".as_bytes()).unwrap();
}
}

0 comments on commit eace2ff

Please sign in to comment.