Skip to main content

StateMachine

Trait StateMachine 

Source
pub trait StateMachine:
    Send
    + Sync
    + Clone {
    type Command: Send + Sync + Clone;
    type Response: Send + Sync + Clone;
    type State: Send + Sync + Clone;

    // Required methods
    fn apply_command<'life0, 'async_trait>(
        &'life0 mut self,
        command: Self::Command,
    ) -> Pin<Box<dyn Future<Output = Self::Response> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get_state(&self) -> Self::State;
    fn set_state(&mut self, state: Self::State);
    fn serialize_state(&self) -> Vec<u8> ;
    fn deserialize_state(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>>;

    // Provided methods
    fn apply_commands<'life0, 'async_trait>(
        &'life0 mut self,
        commands: Vec<Self::Command>,
    ) -> Pin<Box<dyn Future<Output = Vec<Self::Response>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait { ... }
    fn is_deterministic(&self) -> bool { ... }
}
Expand description

Re-export commonly used types for convenience Core trait for State Machine Replication in Rabia consensus.

This trait defines the interface that any state machine must implement to be used with the Rabia consensus protocol. The trait ensures that state machines are deterministic and can be safely replicated across multiple nodes.

§Example Implementation

use rabia_core::smr::StateMachine;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};

#[derive(Clone, Serialize, Deserialize)]
pub struct CounterCommand {
    pub operation: String, // "increment", "decrement", "get"
    pub value: i64,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct CounterResponse {
    pub value: i64,
    pub success: bool,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct CounterState {
    pub value: i64,
}

#[derive(Clone)]
pub struct CounterStateMachine {
    state: CounterState,
}

#[async_trait]
impl StateMachine for CounterStateMachine {
    type Command = CounterCommand;
    type Response = CounterResponse;
    type State = CounterState;

    async fn apply_command(&mut self, command: Self::Command) -> Self::Response {
        match command.operation.as_str() {
            "increment" => {
                self.state.value += command.value;
                CounterResponse { value: self.state.value, success: true }
            }
            "decrement" => {
                self.state.value -= command.value;
                CounterResponse { value: self.state.value, success: true }
            }
            "get" => {
                CounterResponse { value: self.state.value, success: true }
            }
            _ => CounterResponse { value: self.state.value, success: false }
        }
    }

    fn get_state(&self) -> Self::State {
        self.state.clone()
    }

    fn set_state(&mut self, state: Self::State) {
        self.state = state;
    }

    fn serialize_state(&self) -> Vec<u8> {
        bincode::serialize(&self.state).unwrap_or_default()
    }

    fn deserialize_state(&mut self, data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
        self.state = bincode::deserialize(data)?;
        Ok(())
    }
}

Required Associated Types§

Source

type Command: Send + Sync + Clone

The command type that this state machine can process

Source

type Response: Send + Sync + Clone

The response type returned after applying commands

Source

type State: Send + Sync + Clone

The state type representing the current state of the machine

Required Methods§

Source

fn apply_command<'life0, 'async_trait>( &'life0 mut self, command: Self::Command, ) -> Pin<Box<dyn Future<Output = Self::Response> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Apply a single command to the state machine.

This method must be deterministic - given the same state and command, it must always produce the same response and resulting state.

§Arguments
  • command - The command to apply to the state machine
§Returns

The response generated by applying the command

Source

fn get_state(&self) -> Self::State

Get the current state of the state machine.

This method should return a snapshot of the current state that can be used for state transfer or debugging.

Source

fn set_state(&mut self, state: Self::State)

Set the state of the state machine.

This method is used during state transfer operations to restore the state machine to a specific state.

§Arguments
  • state - The state to restore
Source

fn serialize_state(&self) -> Vec<u8>

Serialize the current state to bytes.

This method is used for persistence and state transfer operations. The serialized data should contain all information necessary to restore the state machine to its current state.

§Returns

A byte vector containing the serialized state

Source

fn deserialize_state(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>>

Deserialize state from bytes and restore it.

This method is used during recovery and state transfer operations to restore the state machine from serialized data.

§Arguments
  • data - The serialized state data
§Returns

Result indicating success or failure of deserialization

Provided Methods§

Source

fn apply_commands<'life0, 'async_trait>( &'life0 mut self, commands: Vec<Self::Command>, ) -> Pin<Box<dyn Future<Output = Vec<Self::Response>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Apply multiple commands in sequence.

Default implementation applies commands one by one. State machines can override this for batch optimization if needed.

§Arguments
  • commands - Vector of commands to apply
§Returns

Vector of responses corresponding to each command

Source

fn is_deterministic(&self) -> bool

Check if this state machine is deterministic.

All state machines used with Rabia consensus MUST be deterministic. This method is provided for validation and debugging purposes.

§Returns

true if the state machine is deterministic (should always return true)

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§