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}