seda_sdk_rs/
tally.rs

1//! This module provides functionality to retrieve and process reveals from the command line arguments
2//! of a data request report in the Seda runtime SDK.
3//!
4//! It defines the [`RevealBody`] and [`RevealResult`] structs to represent the reveal data,
5//! and provides functions to retrieve unfiltered reveals and filtered reveals that are in consensus
6//! via the functions [`get_unfiltered_reveals`] and [`get_reveals`], respectively.
7
8use anyhow::{Error, Result};
9use serde::{Deserialize, Serialize};
10
11use crate::Process;
12
13const REVEALS_ARGUMENT_POSITION: usize = 2;
14const CONSENSUS_ARGUMENT_POSITION: usize = 3;
15
16/// Represents the body of a reveal body of a data request report.
17#[derive(Serialize, Deserialize, Clone, Debug)]
18pub struct RevealBody {
19    /// The block height the data request was posted.
20    pub dr_block_height: u64,
21    /// The exit code of the data request's execution VM.
22    pub exit_code: u8,
23    /// The gas used by the data request's execution VM.
24    pub gas_used: u64,
25    /// The data returned by the data request's execution VM.
26    pub reveal: Vec<u8>,
27}
28
29/// Represents a reveal body of a data request report.
30#[derive(Serialize, Deserialize, Clone, Debug)]
31pub struct RevealResult {
32    /// The body of the reveal.
33    pub body: RevealBody,
34    /// Whether the reveal is in consensus or not.
35    pub in_consensus: bool,
36}
37
38/// Retrieves the unfiltered reveals from the command line arguments.
39///
40/// # Errors
41///
42/// This function will return an error if:
43/// - The expected arguments are not found in the command line arguments.
44/// - The number of reveals does not match the number of consensus reports.
45/// - The JSON deserialization fails for either the reveals or the consensus reports.
46///
47/// # Examples
48///
49/// ```no_run
50/// use seda_sdk_rs::get_unfiltered_reveals;
51/// match get_unfiltered_reveals() {
52///     Ok(reveals) => {
53///        for reveal in reveals {
54///            // Process each reveal
55///        }
56///     },
57///     Err(err) => {
58///         eprintln!("Error retrieving unfiltered reveals: {}", err);
59///     }
60/// }
61/// ```
62pub fn get_unfiltered_reveals() -> Result<Vec<RevealResult>> {
63    let args = Process::args();
64
65    let encoded_reveals = args
66        .get(REVEALS_ARGUMENT_POSITION)
67        .ok_or(Error::msg(format!("Expected argument at {REVEALS_ARGUMENT_POSITION}",)))?;
68
69    let encoded_consensus = args.get(CONSENSUS_ARGUMENT_POSITION).ok_or(Error::msg(format!(
70        "Expected argument at {CONSENSUS_ARGUMENT_POSITION}"
71    )))?;
72
73    let reveals: Vec<RevealBody> = serde_json::from_str(encoded_reveals)?;
74    let consensus: Vec<u8> = serde_json::from_str(encoded_consensus)?;
75
76    if reveals.len() != consensus.len() {
77        return Err(Error::msg(format!(
78            "Number of reveals ({}) does not equal number of consensus reports ({}).",
79            reveals.len(),
80            consensus.len()
81        )));
82    }
83
84    let mut reveal_results: Vec<RevealResult> = Vec::new();
85
86    for (index, reveal) in reveals.iter().enumerate() {
87        let consensus_info = consensus
88            .get(index)
89            .ok_or(Error::msg("Unreachable, could not find index"))?;
90
91        reveal_results.push(RevealResult {
92            body: reveal.clone(),
93            in_consensus: *consensus_info == 0,
94        });
95    }
96
97    Ok(reveal_results)
98}
99
100/// Retrieves the reveals that are in consensus from the command line arguments.
101///
102/// # Errors
103/// This function will return an error if the unfiltered reveals cannot be retrieved see [`get_unfiltered_reveals`]
104/// for more information.
105///
106/// # Examples
107/// ```no_run
108/// use seda_sdk_rs::get_reveals;
109/// match get_reveals() {
110///    Ok(reveals) => {
111///       for reveal in reveals {
112///           // Process each reveal that is in consensus
113///       }
114///   },
115///   Err(err) => {
116///       eprintln!("Error retrieving reveals: {}", err);
117///   }
118/// }
119/// ```
120pub fn get_reveals() -> Result<Vec<RevealResult>> {
121    let unfiltered_reveals = get_unfiltered_reveals()?;
122
123    Ok(unfiltered_reveals
124        .into_iter()
125        .filter(|reveal| reveal.in_consensus)
126        .collect())
127}