spl_tlv_account_resolution/
pubkey_data.rs1#[cfg(feature = "serde-traits")]
8use serde::{Deserialize, Serialize};
9use {crate::error::AccountResolutionError, solana_program_error::ProgramError};
10
11#[derive(Clone, Debug, PartialEq)]
13#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
14#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
15pub enum PubkeyData {
16 Uninitialized,
18 InstructionData {
26 index: u8,
28 },
29 AccountData {
38 account_index: u8,
40 data_index: u8,
42 },
43}
44impl PubkeyData {
45 pub fn tlv_size(&self) -> u8 {
47 match self {
48 Self::Uninitialized => 0,
49 Self::InstructionData { .. } => 1 + 1,
51 Self::AccountData { .. } => 1 + 1 + 1,
54 }
55 }
56
57 pub fn pack(&self, dst: &mut [u8]) -> Result<(), ProgramError> {
59 if dst.len() != self.tlv_size() as usize {
62 return Err(AccountResolutionError::NotEnoughBytesForPubkeyData.into());
63 }
64 match &self {
65 Self::Uninitialized => {
66 return Err(AccountResolutionError::InvalidPubkeyDataConfig.into())
67 }
68 Self::InstructionData { index } => {
69 dst[0] = 1;
70 dst[1] = *index;
71 }
72 Self::AccountData {
73 account_index,
74 data_index,
75 } => {
76 dst[0] = 2;
77 dst[1] = *account_index;
78 dst[2] = *data_index;
79 }
80 }
81 Ok(())
82 }
83
84 pub fn pack_into_address_config(key_data: &Self) -> Result<[u8; 32], ProgramError> {
87 let mut packed = [0u8; 32];
88 let tlv_size = key_data.tlv_size() as usize;
89 key_data.pack(&mut packed[..tlv_size])?;
90 Ok(packed)
91 }
92
93 pub fn unpack(bytes: &[u8]) -> Result<Self, ProgramError> {
95 let (discrim, rest) = bytes
96 .split_first()
97 .ok_or::<ProgramError>(ProgramError::InvalidAccountData)?;
98 match discrim {
99 0 => Ok(Self::Uninitialized),
100 1 => {
101 if rest.is_empty() {
102 return Err(AccountResolutionError::InvalidBytesForPubkeyData.into());
103 }
104 Ok(Self::InstructionData { index: rest[0] })
105 }
106 2 => {
107 if rest.len() < 2 {
108 return Err(AccountResolutionError::InvalidBytesForPubkeyData.into());
109 }
110 Ok(Self::AccountData {
111 account_index: rest[0],
112 data_index: rest[1],
113 })
114 }
115 _ => Err(ProgramError::InvalidAccountData),
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_pack() {
126 let key = PubkeyData::InstructionData { index: 0 };
128 let mut packed = vec![0u8; key.tlv_size() as usize - 1];
129 assert_eq!(
130 key.pack(&mut packed).unwrap_err(),
131 AccountResolutionError::NotEnoughBytesForPubkeyData.into(),
132 );
133
134 let key = PubkeyData::InstructionData { index: 0 };
136 let mut packed = vec![0u8; key.tlv_size() as usize + 1];
137 assert_eq!(
138 key.pack(&mut packed).unwrap_err(),
139 AccountResolutionError::NotEnoughBytesForPubkeyData.into(),
140 );
141
142 let key = PubkeyData::Uninitialized;
144 let mut packed = vec![0u8; key.tlv_size() as usize];
145 assert_eq!(
146 key.pack(&mut packed).unwrap_err(),
147 AccountResolutionError::InvalidPubkeyDataConfig.into(),
148 );
149 }
150
151 #[test]
152 fn test_unpack() {
153 let zeroes = [0u8; 32];
155 let key = PubkeyData::unpack(&zeroes).unwrap();
156 assert_eq!(key, PubkeyData::Uninitialized);
157
158 let bytes = [];
160 assert_eq!(
161 PubkeyData::unpack(&bytes).unwrap_err(),
162 ProgramError::InvalidAccountData
163 );
164 }
165
166 fn test_pack_unpack_key(key: PubkeyData) {
167 let tlv_size = key.tlv_size() as usize;
168 let mut packed = vec![0u8; tlv_size];
169 key.pack(&mut packed).unwrap();
170 let unpacked = PubkeyData::unpack(&packed).unwrap();
171 assert_eq!(key, unpacked);
172 }
173
174 #[test]
175 fn test_pack_unpack() {
176 test_pack_unpack_key(PubkeyData::InstructionData { index: 0 });
178
179 test_pack_unpack_key(PubkeyData::AccountData {
181 account_index: 0,
182 data_index: 0,
183 });
184 }
185}