Skip to content

Commit c5cec1a

Browse files
authored
Merge pull request #1071 from elnosh/runtime-err-check
Require a multithreaded runtime when setting up the node
2 parents c54d971 + fd1a5e6 commit c5cec1a

1 file changed

Lines changed: 52 additions & 6 deletions

File tree

‎src/builder.rs‎

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,18 @@ impl NodeBuilder {
369369
///
370370
/// If not provided, the node will spawn its own runtime or reuse any outer runtime context it
371371
/// can detect.
372+
///
373+
/// Note we require the given runtime to be of the `multithreaded` flavor.
372374
#[cfg_attr(feature = "uniffi", allow(dead_code))]
373-
pub fn set_runtime(&mut self, runtime_handle: tokio::runtime::Handle) -> &mut Self {
375+
pub fn set_runtime(
376+
&mut self, runtime_handle: tokio::runtime::Handle,
377+
) -> Result<&mut Self, BuildError> {
378+
if runtime_handle.runtime_flavor() != tokio::runtime::RuntimeFlavor::MultiThread {
379+
return Err(BuildError::RuntimeSetupFailed);
380+
}
381+
374382
self.runtime_handle = Some(runtime_handle);
375-
self
383+
Ok(self)
376384
}
377385

378386
/// Configures the [`Node`] instance to source its chain data from the given Esplora server.
@@ -912,14 +920,24 @@ impl NodeBuilder {
912920
}
913921

914922
fn setup_runtime(&self, logger: &Arc<Logger>) -> Result<Arc<Runtime>, BuildError> {
915-
if let Some(handle) = self.runtime_handle.as_ref() {
916-
Ok(Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(logger))))
923+
let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
924+
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(logger)))
917925
} else {
918-
Ok(Arc::new(Runtime::new(Arc::clone(logger)).map_err(|e| {
926+
Arc::new(Runtime::new(Arc::clone(logger)).map_err(|e| {
919927
log_error!(logger, "Failed to setup tokio runtime: {}", e);
920928
BuildError::RuntimeSetupFailed
921-
})?))
929+
})?)
930+
};
931+
932+
if runtime.handle().runtime_flavor() != tokio::runtime::RuntimeFlavor::MultiThread {
933+
log_error!(
934+
logger,
935+
"Failed to setup tokio runtime: we require a multithreaded runtime."
936+
);
937+
return Err(BuildError::RuntimeSetupFailed);
922938
}
939+
940+
Ok(runtime)
923941
}
924942

925943
fn build_with_store_and_logger<S: PaginatedKVStore + Send + Sync + 'static>(
@@ -2706,4 +2724,32 @@ mod tests {
27062724
let node = sanitize_alias(alias);
27072725
assert_eq!(node.err().unwrap(), BuildError::InvalidNodeAlias);
27082726
}
2727+
2728+
#[test]
2729+
fn rejects_non_multithreaded_runtimes() {
2730+
let logger = Arc::new(Logger::new_log_facade());
2731+
let current_thread_runtime =
2732+
tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
2733+
2734+
let mut builder = NodeBuilder::new();
2735+
assert_eq!(
2736+
builder.set_runtime(current_thread_runtime.handle().clone()).err(),
2737+
Some(BuildError::RuntimeSetupFailed),
2738+
"a current-thread runtime given via `set_runtime` should be rejected"
2739+
);
2740+
2741+
current_thread_runtime.block_on(async {
2742+
assert_eq!(
2743+
NodeBuilder::new().setup_runtime(&logger).err(),
2744+
Some(BuildError::RuntimeSetupFailed),
2745+
"a detected outer current-thread runtime context should be rejected"
2746+
);
2747+
});
2748+
2749+
let multi_thread_runtime =
2750+
tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
2751+
let mut builder = NodeBuilder::new();
2752+
builder.set_runtime(multi_thread_runtime.handle().clone()).unwrap();
2753+
assert!(builder.setup_runtime(&logger).is_ok(), "a multi-threaded runtime should be used");
2754+
}
27092755
}

0 commit comments

Comments
 (0)