mx-core 0.1.0

Core utilities for MultiversX Rust services.
Documentation
//! Shared WebSocket wire-format types for relayer ↔ stress communication.
//!
//! These types define the JSON contract between `mx-relayer` (serializer) and
//! `mx-stress` (deserializer). Both crates MUST use these types instead of
//! defining their own — this prevents silent field-name divergence (e.g.
//! `camelCase` vs `snake_case`) that causes runtime parse failures.

use serde::{Deserialize, Serialize};

// ─────────────────────────────────────────────────────────────────────────────
// Proto broadcast (binary WebSocket frame path)
// ─────────────────────────────────────────────────────────────────────────────

/// Response to a proto-encoded binary broadcast via WebSocket.
///
/// Sent by the relayer after processing a binary frame of protobuf-encoded
/// transaction batches. Deserialized by stress tooling to track success/failure.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProtoBroadcastResponse {
    pub action: String,
    pub status: String,
    pub success_count: usize,
    pub failure_count: usize,
}

impl ProtoBroadcastResponse {
    /// Convenience constructor for the relayer (avoids `.into()` noise at call sites).
    pub fn completed(success_count: usize, failure_count: usize) -> Self {
        Self {
            action: "broadcast_proto".into(),
            status: "completed".into(),
            success_count,
            failure_count,
        }
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// JSON broadcast (text WebSocket frame path)
// ─────────────────────────────────────────────────────────────────────────────

/// Response to a JSON-encoded transaction broadcast via WebSocket.
///
/// Two-phase protocol:
/// - Phase 1: `status: "accepted"` with `batch_size` (immediate ack)
/// - Phase 2: `status: "completed"` | `"partial"` | `"failed"` with `hashes` and `failed`
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BatchBroadcastResponse {
    pub action: String,
    pub status: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub request_id: Option<String>,
    /// Batch size (present in "accepted" ack)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub batch_size: Option<usize>,
    /// Transaction hashes (present in final response)
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub hashes: Vec<String>,
    /// Failed transactions (present in final response)
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub failed: Vec<TxErrorResponse>,
}

/// Error details for a single failed transaction in a batch response.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxErrorResponse {
    pub index: usize,
    pub reason: String,
}