rialo_oracle_processor_interface/
instruction.rs1use rialo_s_instruction::{AccountMeta, Instruction};
9use rialo_s_program::system_program;
10use rialo_s_pubkey::Pubkey;
11use rialo_types::{Nonce, OracleId};
12use serde::{Deserialize, Serialize};
13
14pub use crate::state::OracleUpdate;
15
16pub const ORACLE_REPORT_SEED: &[u8] = b"oracle_report";
18
19pub const ORACLE_REPORT_PAYER_SEED: &[u8] = b"report_payer";
21
22pub const ORACLE_UPDATE_PAYER: Pubkey =
24 Pubkey::from_str_const("Qrac1eUpdatePayer11111111111111111111111111");
25
26#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
29pub enum OracleProcessorInstruction {
30 Report {
32 oracle_id: OracleId,
34 updates: Vec<OracleUpdate>,
36 },
37}
38
39impl OracleProcessorInstruction {
40 pub fn report(
70 payer: Pubkey,
71 aggregators: Vec<(String, Pubkey)>,
72 oracle_id: OracleId,
73 updates: Vec<OracleUpdate>,
74 ) -> Vec<Instruction> {
75 let (report_key, _bump) = derive_report_address(&oracle_id.creator, oracle_id.nonce);
77
78 let aggregators = if updates.is_empty() {
79 vec![]
81 } else {
82 aggregators
83 };
84
85 let mut itxs = Vec::with_capacity(1 + aggregators.len());
88
89 itxs.push(Instruction::new_with_bincode(
90 crate::id(),
91 &OracleProcessorInstruction::Report { oracle_id, updates },
92 vec![
93 AccountMeta::new(payer, true),
94 AccountMeta::new(report_key, false),
95 AccountMeta::new_readonly(system_program::id(), false),
96 ],
97 ));
98
99 for (topic, aggregator) in aggregators {
101 itxs.push(
103 rialo_aggregator_interface::instruction::AggregatorInstruction::aggregate(
104 &aggregator,
105 &payer,
106 &report_key,
107 topic,
108 ),
109 );
110 }
111
112 itxs
113 }
114}
115
116pub fn derive_report_address<NONCE: Into<Nonce>>(creator: &Pubkey, nonce: NONCE) -> (Pubkey, u8) {
127 let nonce: Nonce = nonce.into();
128 Pubkey::find_program_address(
129 &[ORACLE_REPORT_SEED, &creator.to_bytes(), nonce.as_bytes()],
130 &crate::id(),
131 )
132}
133
134#[cfg(test)]
135mod tests {
136 use rialo_events_core::RialoEvent;
137 use rialo_s_pubkey::Pubkey;
138
139 use super::*;
140
141 #[derive(Default, RialoEvent)]
142 struct TestEvent {
143 name: String,
144 value: u64,
145 }
146
147 #[test]
148 fn test_report_oracle_updates() {
149 let aggregators = vec![
150 ("aggregator1".to_string(), Pubkey::new_unique()),
151 ("aggregator2".to_string(), Pubkey::new_unique()),
152 ];
153 let validator = Pubkey::new_unique();
154 let payer = Pubkey::new_unique();
155 let data = vec![0, 1, 2, 3];
156 let updates = vec![OracleUpdate { data, validator }];
157 let nonce = Nonce::from(b"test-oracle-42");
158 let oracle_id = OracleId::new(payer, nonce);
159
160 let instruction = OracleProcessorInstruction::report(
162 payer,
163 aggregators.clone(),
164 oracle_id,
165 updates.clone(),
166 );
167 assert_eq!(instruction.len(), 1 + aggregators.len()); let report_instruction = &instruction[0];
172 let expected_accounts = vec![
173 AccountMeta::new(payer, true),
174 AccountMeta::new(
175 derive_report_address(&oracle_id.creator, oracle_id.nonce).0,
176 false,
177 ),
178 AccountMeta::new_readonly(system_program::id(), false),
179 ];
180
181 let expected_data = bincode::serialize(&OracleProcessorInstruction::Report {
183 oracle_id,
184 updates: updates.clone(),
185 })
186 .unwrap();
187
188 assert_eq!(report_instruction.data, expected_data);
189 assert_eq!(report_instruction.accounts, expected_accounts);
190
191 for (i, (topic, aggregator)) in aggregators.into_iter().enumerate() {
193 let agg_instruction = &instruction[i + 1];
194
195 let expected_agg_instruction =
197 rialo_aggregator_interface::instruction::AggregatorInstruction::aggregate(
198 &aggregator,
199 &payer,
200 &derive_report_address(&oracle_id.creator, oracle_id.nonce).0,
201 topic,
202 );
203
204 assert_eq!(agg_instruction, &expected_agg_instruction);
205 }
206 }
207
208 #[test]
209 fn test_report_address_derivation() {
210 let oracle_creator = Pubkey::new_unique();
211 let (report_pubkey1, _) = derive_report_address(&oracle_creator, b"test-oracle-a42");
212 let (report_pubkey2, _) = derive_report_address(&oracle_creator, b"test-oracle-43");
213 assert_ne!(report_pubkey1, report_pubkey2);
214 }
215}