casper-devnet 0.10.0

Launcher for local Casper Network development networks.
Documentation
use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};
use std::path::Path;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::UnixStream;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "command", rename_all = "snake_case")]
pub enum ControlRequest {
    RuntimeStatus,
    StageProtocol {
        #[serde(default, skip_serializing_if = "Option::is_none")]
        asset: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        custom_asset: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        asset_name: Option<String>,
        protocol_version: String,
        activation_point: u64,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        chainspec_overrides: Vec<String>,
        restart_sidecars: bool,
        rust_log: Option<String>,
    },
    AddNodes {
        count: u32,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum ControlResponse {
    Ok { result: ControlResult },
    Error { error: String },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "command", rename_all = "snake_case")]
pub enum ControlResult {
    RuntimeStatus {
        running_node_ids: Vec<u32>,
        last_block_height: Option<u64>,
    },
    StageProtocol {
        live_mode: bool,
        staged_nodes: u32,
        restarted_sidecars: Vec<u32>,
    },
    AddNodes {
        added_node_ids: Vec<u32>,
        total_nodes: u32,
        started_processes: u32,
    },
}

pub async fn send_request(socket_path: &Path, request: &ControlRequest) -> Result<ControlResponse> {
    let mut stream = UnixStream::connect(socket_path).await?;
    let request_bytes = serde_json::to_vec(request)?;
    stream.write_all(&request_bytes).await?;
    stream.shutdown().await?;

    let mut response_bytes = Vec::new();
    stream.read_to_end(&mut response_bytes).await?;
    if response_bytes.is_empty() {
        return Err(anyhow!(
            "empty control response from {}",
            socket_path.display()
        ));
    }

    let response = serde_json::from_slice::<ControlResponse>(&response_bytes)?;
    Ok(response)
}