pub struct Cluster {Show 14 fields
pub config: ClusterConfig,
scenario: ClusterScenarioRun,
available_ports: Box<dyn Iterator<Item = u16> + Send>,
account_sec_keys: BTreeMap<AccountPublicKey, AccountSecretKey>,
nodes: Vec<Node>,
ocaml_nodes: Vec<Option<OcamlNode>>,
initial_time: Option<Timestamp>,
rpc_counter: usize,
ocaml_libp2p_keypair_i: usize,
verifier_srs: Arc<VerifierSRS>,
block_verifier_index: BlockVerifier,
work_verifier_index: TransactionVerifier,
debugger: Option<Debugger>,
invariants_state: Arc<Mutex<InvariantsState>>,
}Expand description
Manages a cluster of Mina nodes for testing scenarios.
The Cluster struct coordinates multiple node instances, handling
resource allocation, configuration, and lifecycle management. It supports
both Rust and OCaml node implementations for comprehensive testing.
§Default Behaviors
- Port allocation: Automatically assigns available ports from the configured range, testing availability before assignment
- Keypair management: Uses deterministic keypairs for Rust nodes and rotates through predefined keypairs for OCaml nodes
- Resource isolation: Each node gets isolated temporary directories
- Verifier indices: Shared verifier SRS and indices across all nodes
- Network debugging: Optional debugger integration for CI environments
§Node Addition
The cluster provides specialized methods for adding different node types:
- Rust nodes via
add_rust_node - OCaml nodes via
add_ocaml_node
Fields§
§config: ClusterConfigCluster-wide configuration settings
scenario: ClusterScenarioRunCurrent scenario execution state
available_ports: Box<dyn Iterator<Item = u16> + Send>Iterator over available ports for node allocation
account_sec_keys: BTreeMap<AccountPublicKey, AccountSecretKey>Registry of account secret keys for deterministic testing
nodes: Vec<Node>Collection of active Rust nodes
ocaml_nodes: Vec<Option<OcamlNode>>Collection of active OCaml nodes (Option for lifecycle management)
initial_time: Option<Timestamp>Genesis timestamp for deterministic time progression
rpc_counter: usizeCounter for generating unique RPC request IDs
ocaml_libp2p_keypair_i: usizeIndex for rotating OCaml LibP2P keypairs
verifier_srs: Arc<VerifierSRS>Shared verifier SRS for proof verification
block_verifier_index: BlockVerifierBlock verifier index for consensus validation
work_verifier_index: TransactionVerifierTransaction verifier index for transaction validation
debugger: Option<Debugger>Optional network traffic debugger
invariants_state: Arc<Mutex<InvariantsState>>Shared state for invariant checking across nodes
Implementations§
Source§impl Cluster
impl Cluster
pub fn new(config: ClusterConfig) -> Self
pub fn available_port(&mut self) -> Option<u16>
pub fn add_account_sec_key(&mut self, sec_key: AccountSecretKey)
pub fn get_account_sec_key( &self, pub_key: &AccountPublicKey, ) -> Option<&AccountSecretKey>
pub fn set_initial_time(&mut self, initial_time: Timestamp)
pub fn get_initial_time(&self) -> Option<Timestamp>
Sourcepub fn add_rust_node(
&mut self,
testing_config: RustNodeTestingConfig,
) -> ClusterNodeId
pub fn add_rust_node( &mut self, testing_config: RustNodeTestingConfig, ) -> ClusterNodeId
Add a new Rust implementation node to the cluster.
Creates and configures a Rust Mina node with the specified testing configuration. This method handles all aspects of node initialization including port allocation, key generation, service setup, and state initialization.
§Default Behaviors
- Port allocation: HTTP and LibP2P ports automatically assigned from available port range
- Peer identity: Deterministic LibP2P keypair based on node index
- Work directory: Isolated temporary directory per node
- Invariants: Automatic invariant checking enabled
- HTTP server: Spawned on separate thread for API access
- Proof verification: Shared verifier indices and SRS
§Configuration Options
peer_id: Deterministic or custom LibP2P identitylibp2p_port: Custom P2P port (auto-assigned if None)initial_peers: Peer connection targets (supports node references)block_producer: Optional block production configurationgenesis: Genesis ledger and protocol constantssnark_worker: SNARK work generation settings
§Returns
Returns a ClusterNodeId that can be used to reference this node
in scenarios and for inter-node connections.
§Panics
Panics if:
- No available ports in the configured range
- Node service initialization fails
- Invalid genesis configuration
Sourcepub fn add_ocaml_node(
&mut self,
testing_config: OcamlNodeTestingConfig,
) -> ClusterOcamlNodeId
pub fn add_ocaml_node( &mut self, testing_config: OcamlNodeTestingConfig, ) -> ClusterOcamlNodeId
Add a new OCaml implementation node to the cluster.
Creates and spawns an OCaml Mina daemon process with the specified configuration. This method handles process spawning, port allocation, directory setup, and daemon configuration.
§Default Behaviors
- Executable selection: Automatically detects local binary or falls back to default Docker image
- Port allocation: LibP2P, GraphQL, and client ports automatically assigned from available range
- Keypair rotation: Uses predefined LibP2P keypairs, rotating through the set for each new node
- Process management: Spawns daemon with proper environment variables and argument configuration
- Logging: Stdout/stderr forwarded with port-based prefixes
- Docker support: Automatic container management when using Docker
§Configuration Options
initial_peers: List of peer connection targetsdaemon_json: Genesis configuration (file path or in-memory JSON)block_producer: Optional block production key
§Docker vs Local Execution
The method automatically determines execution mode:
- Attempts to use locally installed
minabinary - Falls back to Docker with default image if binary not found
- Custom Docker images supported via configuration
§Returns
Returns a ClusterOcamlNodeId for referencing this OCaml node
in scenarios and peer connections.
§Panics
Panics if:
- No available ports in the configured range
- Temporary directory creation fails
- OCaml daemon process spawn fails
pub async fn start(&mut self, scenario: Scenario) -> Result<(), Error>
pub async fn reload_scenarios(&mut self) -> Result<(), Error>
pub fn next_scenario_and_step(&self) -> Option<(&ScenarioId, usize)>
pub fn target_scenario(&self) -> Option<&ScenarioId>
pub fn nodes_iter(&self) -> impl Iterator<Item = (ClusterNodeId, &Node)>
pub fn ocaml_nodes_iter( &self, ) -> impl Iterator<Item = (ClusterOcamlNodeId, &OcamlNode)>
pub fn node(&self, node_id: ClusterNodeId) -> Option<&Node>
pub fn node_by_peer_id(&self, peer_id: PeerId) -> Option<&Node>
pub fn node_mut(&mut self, node_id: ClusterNodeId) -> Option<&mut Node>
pub fn ocaml_node(&self, node_id: ClusterOcamlNodeId) -> Option<&OcamlNode>
pub fn ocaml_node_by_peer_id(&self, peer_id: PeerId) -> Option<&OcamlNode>
pub fn pending_events( &mut self, poll: bool, ) -> impl Iterator<Item = (ClusterNodeId, &State, impl Iterator<Item = (PendingEventId, &Event)>)>
pub fn node_pending_events( &mut self, node_id: ClusterNodeId, poll: bool, ) -> Result<(&State, impl Iterator<Item = (PendingEventId, &Event)>), Error>
pub async fn wait_for_pending_events(&mut self)
pub async fn wait_for_pending_events_with_timeout( &mut self, timeout: Duration, ) -> bool
pub async fn wait_for_pending_event( &mut self, node_id: ClusterNodeId, event_pattern: &str, ) -> Result<PendingEventId>
pub async fn wait_for_event_and_dispatch( &mut self, node_id: ClusterNodeId, event_pattern: &str, ) -> Result<bool>
pub async fn add_steps_and_save( &mut self, steps: impl IntoIterator<Item = ScenarioStep>, )
pub async fn exec_to_end(&mut self) -> Result<(), Error>
pub async fn exec_until( &mut self, target_scenario: ScenarioId, step_i: Option<usize>, ) -> Result<(), Error>
pub async fn exec_next(&mut self) -> Result<bool, Error>
pub async fn exec_step(&mut self, step: ScenarioStep) -> Result<bool>
pub fn debugger(&self) -> Option<&Debugger>
Auto Trait Implementations§
impl Freeze for Cluster
impl !RefUnwindSafe for Cluster
impl Send for Cluster
impl !Sync for Cluster
impl Unpin for Cluster
impl !UnwindSafe for Cluster
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.