rialo-types 0.1.0

Rialo Types
Documentation
// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use serde_derive::{Deserialize, Serialize};

/// Configuration for oracle duties.
///
/// This struct defines the parameters that control how oracle duties are scheduled,
/// executed, and finalized within the system.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct OracleDutyConfig {
    /// The number of validators assigned to each oracle duty.
    pub validators_per_duty: u32,
    /// The number of consensus rounds to wait before an oracle request is issued.
    pub oracle_request_delay: u32,
    /// The size of the window (in rounds) during which oracle updates are collected.
    /// Must be an odd number.
    pub collection_window_size: u32,
    /// The number of rounds to wait after the proposal round before the duty is considered committed.
    pub commitment_buffer: u32,
    /// Max size of oracle output in bytes.
    pub max_oracle_output_size: u32,
}

impl Default for OracleDutyConfig {
    fn default() -> Self {
        Self {
            // 3-validator committees gives us 99.996% success rate leveraging TEE guarantees
            validators_per_duty: Self::DEFAULT_VALIDATORS_PER_DUTY,
            // Time to execute an oracle, determined experimentally
            oracle_request_delay: 6,
            // ±1 round around proposal round (3 total rounds)
            collection_window_size: 3,
            // 3 rounds (150ms) provide adequate collection time with acceptable latency
            commitment_buffer: 3,
            // Safe size for the default number of validators.
            max_oracle_output_size: Self::DEFAULT_MAX_ORACLE_OUTPUT_SIZE,
        }
    }
}

impl OracleDutyConfig {
    /// Safe max size limit for the default number of validators.
    pub const DEFAULT_MAX_ORACLE_OUTPUT_SIZE: u32 = 10 * 1024;

    /// A reasonably safe value to make one-off oracles succeed with >22 bits of security.
    /// This value is based on the example from the Rialo whitepaper, that is N = 130, D = 43.
    pub const ONE_OFF_VALIDATORS_PER_DUTY: u32 = 13;

    /// A small value for oracles that is reasonably cheap.
    /// Note that by itself it doesn't provide a response reliably enough
    /// and needs retries in case of failure..
    pub const DEFAULT_VALIDATORS_PER_DUTY: u32 = 5;

    /// Most oracles should complete within a few blocks.
    pub const DEFAULT_ORACLE_REQUEST_DELAY: u32 = 6;

    /// The minimum allowed delay for oracle requests, in consensus rounds.
    pub const MIN_ORACLE_REQUEST_DELAY: u32 = 2; // 0.1s = 2 rounds

    /// The maximum allowed delay for oracle requests, in consensus rounds.
    pub const MAX_ORACLE_REQUEST_DELAY: u32 = 4800; // 240s = 4800 rounds

    /// Default maximum number of ASAP duties to process in a single consensus round
    pub const DEFAULT_MAX_ASAP_DUTIES_PER_COMMIT: usize = 5;

    /// Default timeout for ASAP duties in rounds
    pub const DEFAULT_ASAP_TIMEOUT_COMMITS: u32 = 50;

    /// Sets the oracle request delay (in consensus rounds).
    ///
    /// # Arguments
    ///
    /// * `delay` - The number of rounds to wait before issuing an oracle request.
    pub fn set_oracle_request_delay(&mut self, delay: u32) {
        self.oracle_request_delay = delay;
    }

    /// Sets the maximum oracle output size (in bytes).
    ///
    /// # Arguments
    ///
    /// * `max_oracle_output_size` - The maximum size allowed for oracle output data.
    pub fn set_max_output_size(&mut self, max_oracle_output_size: usize) {
        self.max_oracle_output_size = max_oracle_output_size as _;
    }
}

/// Builder for `OracleDutyConfig`.
///
/// Provides a convenient way to construct an `OracleDutyConfig` with custom parameters.
#[derive(Default)]
pub struct OracleDutyConfigBuilder {
    config: OracleDutyConfig,
}

impl OracleDutyConfigBuilder {
    /// Sets the oracle request delay (in consensus rounds) for the config being built.
    pub fn set_oracle_request_delay(mut self, delay: u32) -> Self {
        self.config.oracle_request_delay = delay;
        self
    }

    /// Sets the number of validators to assign per duty.
    pub fn set_validators_per_duty(mut self, validators_per_duty: u32) -> Self {
        self.config.validators_per_duty = validators_per_duty;
        self
    }

    /// Sets the commitment_buffer
    pub fn set_commitment_buffer(mut self, commitment_buffer: u32) -> Self {
        self.config.commitment_buffer = commitment_buffer;
        self
    }

    /// Finalizes and returns the constructed `OracleDutyConfig`.
    pub fn build(self) -> OracleDutyConfig {
        self.config
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_oracle_duty_config_builder() {
        let default_config = OracleDutyConfig::default();

        let config = OracleDutyConfigBuilder::default()
            .set_oracle_request_delay(10)
            .set_validators_per_duty(42)
            .build();

        assert_eq!(config.oracle_request_delay, 10);
        assert_eq!(config.validators_per_duty, 42);
        // Verify other fields use default values
        assert_eq!(
            config.collection_window_size,
            default_config.collection_window_size
        );
        assert_eq!(config.commitment_buffer, default_config.commitment_buffer);

        let config = OracleDutyConfigBuilder::default().build();
        assert_eq!(
            config.oracle_request_delay,
            default_config.oracle_request_delay
        );
        assert_eq!(
            config.validators_per_duty,
            default_config.validators_per_duty
        );
        assert_eq!(
            config.collection_window_size,
            default_config.collection_window_size
        );
        assert_eq!(config.commitment_buffer, default_config.commitment_buffer);
    }
}