//! A deterministic runtime that randomly selects tasks to run based on a seed //! //! # Panics //! //! Unless configured otherwise, any task panic will lead to a runtime panic. //! //! # External Processes //! //! When testing an application that interacts with some external process, it can appear to //! the runtime that progress has stalled because no pending tasks can make progress and/or //! that futures resolve at variable latency (which in turn triggers non-deterministic execution). //! //! To support such applications, the runtime can be built with the `external` feature to both //! sleep for each [Config::cycle] (opting to wait if all futures are pending) and to constrain //! the resolution latency of any future (with `pace()`). //! //! **Applications that do not interact with external processes (or are able to mock them) should never //! need to enable this feature. It is commonly used when testing consensus with external execution environments //! that use their own runtime (but are deterministic over some set of inputs).** //! //! # Metrics //! //! This runtime enforces metrics are unique and well-formed: //! - Labels must start with `[a-zA-Z]` and contain only `[a-zA-Z0-9_]` //! - Re-registering the same metric key reuses the existing metric handle when the type matches //! //! # Example //! //! ```rust //! use commonware_runtime::{Spawner, Runner, deterministic, Metrics, Supervisor}; //! //! let executor = deterministic::Runner::default(); //! executor.start(|context| async move { //! println!("Parent started"); //! let result = context.child("child").spawn(|_| async move { //! println!("Child started"); //! "hello" //! }); //! println!("Child result: {:?}", result.await); //! println!("Parent exited"); //! println!("Auditor state: {}", context.auditor().state()); //! }); //! ``` pub use crate::storage::faulty::Config as FaultConfig; use crate::{ child_label, network::{ audited::Network as AuditedNetwork, deterministic::Network as DeterministicNetwork, metered::Network as MeteredNetwork, }, prefixed_name, storage::{ audited::Storage as AuditedStorage, faulty::Storage as FaultyStorage, memory::Storage as MemStorage, metered::Storage as MeteredStorage, }, telemetry::metrics::{ add_attribute, raw, task::Label, validate_label, Counter, CounterFamily, GaugeFamily, Metric, Register, Registered, Registry, }, utils::{ signal::{Signal, Stopper}, supervision::Tree, Panicker, }, BufferPool, BufferPoolConfig, Clock, Error, Execution, Handle, ListenerOf, Name, Panicked, Spawner as _, Supervisor as _, METRICS_PREFIX, }; #[cfg(feature = "external")] use crate::{Blocker, Pacer}; use commonware_codec::Encode; use commonware_formatting::hex; use commonware_macros::select; use commonware_parallel::ThreadPool; use commonware_utils::{ sync::{Mutex, RwLock}, time::SYSTEM_TIME_PRECISION, SystemTimeExt, }; #[cfg(feature = "external")] use futures::task::noop_waker; use futures::{ future::Either, task::{waker, ArcWake}, Future, }; use governor::clock::{Clock as GClock, ReasonablyRealtime}; #[cfg(feature = "external")] use pin_project::pin_project; use rand::{prelude::SliceRandom, rngs::StdRng, CryptoRng, RngCore, SeedableRng}; use rand_core::CryptoRngCore; use rayon::{ThreadPoolBuildError, ThreadPoolBuilder}; use sha2::{Digest as _, Sha256}; use std::{ collections::{BTreeMap, BinaryHeap, HashMap}, mem::{replace, take}, net::{IpAddr, SocketAddr}, num::NonZeroUsize, panic::{catch_unwind, resume_unwind, AssertUnwindSafe}, pin::Pin, sync::{Arc, Weak}, task::{self, Poll, Waker}, time::{Duration, SystemTime, UNIX_EPOCH}, }; use tracing::{info_span, trace, Instrument}; use tracing_opentelemetry::OpenTelemetrySpanExt; #[derive(Debug)] struct Metrics { iterations: Counter, tasks_spawned: CounterFamily