solana_block_decoder/instruction/
compiled_instruction.rs

1use {
2    serde_derive::{Deserialize, Serialize},
3    solana_short_vec as short_vec,
4    solana_transaction_status_client_types::{
5        UiCompiledInstruction,
6    }
7};
8
9/// A compact encoding of an instruction.
10///
11/// A `CompiledInstruction` is a component of a multi-instruction [`Message`],
12/// which is the core of a Solana transaction. It is created during the
13/// construction of `Message`. Most users will not interact with it directly.
14///
15/// [`Message`]: crate::message::Message
16#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
17#[serde(rename_all = "camelCase")]
18pub struct CompiledInstruction {
19    /// Index into the transaction keys array indicating the program account that executes this instruction.
20    pub program_id_index: u8,
21    /// Ordered indices into the transaction keys array indicating which accounts to pass to the program.
22    #[serde(with = "short_vec")]
23    pub accounts: Vec<u8>,
24    /// The program input data.
25    #[serde(with = "short_vec")]
26    pub data: Vec<u8>,
27}
28
29impl From<UiCompiledInstruction> for CompiledInstruction {
30    fn from(ui_compiled_instruction: UiCompiledInstruction) -> Self {
31        Self {
32            program_id_index: ui_compiled_instruction.program_id_index,
33            accounts: ui_compiled_instruction.accounts,
34            data: bs58::decode(ui_compiled_instruction.data).into_vec().unwrap(),
35        }
36    }
37}
38
39impl From<CompiledInstruction> for solana_message::compiled_instruction::CompiledInstruction {
40    fn from(instr: CompiledInstruction) -> Self {
41        Self {
42            program_id_index: instr.program_id_index,
43            accounts: instr.accounts,
44            data: instr.data,
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use serde_json;
53    use solana_transaction_status_client_types::UiCompiledInstruction;
54    use solana_message::compiled_instruction::CompiledInstruction as SolanaCompiledInstruction;
55    use bs58;
56
57    #[test]
58    fn test_serialization_deserialization() {
59        let instr = CompiledInstruction {
60            program_id_index: 1,
61            accounts: vec![0, 1, 2],
62            data: vec![10, 20, 30],
63        };
64
65        let json = serde_json::to_string(&instr).unwrap();
66        let deserialized: CompiledInstruction = serde_json::from_str(&json).unwrap();
67
68        assert_eq!(instr, deserialized);
69    }
70
71    #[test]
72    fn test_from_ui_compiled_instruction_valid() {
73        let ui_instr = UiCompiledInstruction {
74            program_id_index: 2,
75            accounts: vec![3, 4, 5],
76            data: bs58::encode(vec![100, 101, 102]).into_string(),
77            stack_height: None,
78        };
79
80        let compiled_instr: CompiledInstruction = ui_instr.clone().into();
81
82        assert_eq!(compiled_instr.program_id_index, ui_instr.program_id_index);
83        assert_eq!(compiled_instr.accounts, ui_instr.accounts);
84        assert_eq!(compiled_instr.data, vec![100, 101, 102]);
85    }
86
87    #[test]
88    fn test_from_ui_compiled_instruction_invalid_base58() {
89        let ui_instr = UiCompiledInstruction {
90            program_id_index: 0,
91            accounts: vec![0],
92            data: "invalid_base58".to_string(),
93            stack_height: None,
94        };
95
96        let result = std::panic::catch_unwind(|| {
97            let _compiled_instr: CompiledInstruction = ui_instr.into();
98        });
99
100        assert!(result.is_err());
101    }
102
103    #[test]
104    fn test_from_compiled_instruction_to_solana_compiled_instruction() {
105        let instr = CompiledInstruction {
106            program_id_index: 3,
107            accounts: vec![6, 7, 8],
108            data: vec![9, 10, 11],
109        };
110
111        let solana_instr: SolanaCompiledInstruction = instr.clone().into();
112
113        assert_eq!(solana_instr.program_id_index, instr.program_id_index);
114        assert_eq!(solana_instr.accounts, instr.accounts);
115        assert_eq!(solana_instr.data, instr.data);
116    }
117}