1#[cfg(feature = "serde-traits")]
31use serde::{Deserialize, Serialize};
32use {crate::error::AccountResolutionError, solana_program_error::ProgramError};
33
34#[derive(Clone, Debug, PartialEq)]
36#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
37#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
38pub enum Seed {
39 Uninitialized,
41 Literal {
47 bytes: Vec<u8>,
53 },
54 InstructionData {
61 index: u8,
63 length: u8,
67 },
68 AccountKey {
75 index: u8,
77 },
78 #[cfg_attr(
85 feature = "serde-traits",
86 serde(rename_all = "camelCase", alias = "account_data")
87 )]
88 AccountData {
89 account_index: u8,
91 data_index: u8,
93 length: u8,
97 },
98}
99impl Seed {
100 pub fn tlv_size(&self) -> u8 {
102 match &self {
103 Self::Uninitialized => 0,
105 Self::Literal { bytes } => 1 + 1 + bytes.len() as u8,
107 Self::InstructionData { .. } => 1 + 1 + 1,
109 Self::AccountKey { .. } => 1 + 1,
111 Self::AccountData { .. } => 1 + 1 + 1 + 1,
114 }
115 }
116
117 pub fn pack(&self, dst: &mut [u8]) -> Result<(), ProgramError> {
119 if dst.len() != self.tlv_size() as usize {
120 return Err(AccountResolutionError::NotEnoughBytesForSeed.into());
121 }
122 if dst.len() > 32 {
123 return Err(AccountResolutionError::SeedConfigsTooLarge.into());
124 }
125 match &self {
126 Self::Uninitialized => return Err(AccountResolutionError::InvalidSeedConfig.into()),
127 Self::Literal { bytes } => {
128 dst[0] = 1;
129 dst[1] = bytes.len() as u8;
130 dst[2..].copy_from_slice(bytes);
131 }
132 Self::InstructionData { index, length } => {
133 dst[0] = 2;
134 dst[1] = *index;
135 dst[2] = *length;
136 }
137 Self::AccountKey { index } => {
138 dst[0] = 3;
139 dst[1] = *index;
140 }
141 Self::AccountData {
142 account_index,
143 data_index,
144 length,
145 } => {
146 dst[0] = 4;
147 dst[1] = *account_index;
148 dst[2] = *data_index;
149 dst[3] = *length;
150 }
151 }
152 Ok(())
153 }
154
155 pub fn pack_into_address_config(seeds: &[Self]) -> Result<[u8; 32], ProgramError> {
158 let mut packed = [0u8; 32];
159 let mut i: usize = 0;
160 for seed in seeds {
161 let seed_size = seed.tlv_size() as usize;
162 let slice_end = i + seed_size;
163 if slice_end > 32 {
164 return Err(AccountResolutionError::SeedConfigsTooLarge.into());
165 }
166 seed.pack(&mut packed[i..slice_end])?;
167 i = slice_end;
168 }
169 Ok(packed)
170 }
171
172 pub fn unpack(bytes: &[u8]) -> Result<Self, ProgramError> {
174 let (discrim, rest) = bytes
175 .split_first()
176 .ok_or::<ProgramError>(ProgramError::InvalidAccountData)?;
177 match discrim {
178 0 => Ok(Self::Uninitialized),
179 1 => unpack_seed_literal(rest),
180 2 => unpack_seed_instruction_arg(rest),
181 3 => unpack_seed_account_key(rest),
182 4 => unpack_seed_account_data(rest),
183 _ => Err(ProgramError::InvalidAccountData),
184 }
185 }
186
187 pub fn unpack_address_config(address_config: &[u8; 32]) -> Result<Vec<Self>, ProgramError> {
190 let mut seeds = vec![];
191 let mut i = 0;
192 while i < 32 {
193 let seed = Self::unpack(&address_config[i..])?;
194 let seed_size = seed.tlv_size() as usize;
195 i += seed_size;
196 if seed == Self::Uninitialized {
197 break;
198 }
199 seeds.push(seed);
200 }
201 Ok(seeds)
202 }
203}
204
205fn unpack_seed_literal(bytes: &[u8]) -> Result<Seed, ProgramError> {
206 let (length, rest) = bytes
207 .split_first()
208 .ok_or::<ProgramError>(AccountResolutionError::InvalidBytesForSeed.into())?;
210 let length = *length as usize;
211 if rest.len() < length {
212 return Err(AccountResolutionError::InvalidBytesForSeed.into());
214 }
215 Ok(Seed::Literal {
216 bytes: rest[..length].to_vec(),
217 })
218}
219
220fn unpack_seed_instruction_arg(bytes: &[u8]) -> Result<Seed, ProgramError> {
221 if bytes.len() < 2 {
222 return Err(AccountResolutionError::InvalidBytesForSeed.into());
224 }
225 Ok(Seed::InstructionData {
226 index: bytes[0],
227 length: bytes[1],
228 })
229}
230
231fn unpack_seed_account_key(bytes: &[u8]) -> Result<Seed, ProgramError> {
232 if bytes.is_empty() {
233 return Err(AccountResolutionError::InvalidBytesForSeed.into());
235 }
236 Ok(Seed::AccountKey { index: bytes[0] })
237}
238
239fn unpack_seed_account_data(bytes: &[u8]) -> Result<Seed, ProgramError> {
240 if bytes.len() < 3 {
241 return Err(AccountResolutionError::InvalidBytesForSeed.into());
243 }
244 Ok(Seed::AccountData {
245 account_index: bytes[0],
246 data_index: bytes[1],
247 length: bytes[2],
248 })
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 #[test]
256 fn test_pack() {
257 let seed = Seed::Literal { bytes: vec![1; 33] };
259 let mut packed = vec![0u8; seed.tlv_size() as usize];
260 assert_eq!(
261 seed.pack(&mut packed).unwrap_err(),
262 AccountResolutionError::SeedConfigsTooLarge.into()
263 );
264 assert_eq!(
265 Seed::pack_into_address_config(&[seed]).unwrap_err(),
266 AccountResolutionError::SeedConfigsTooLarge.into()
267 );
268
269 let seed = Seed::Literal { bytes: vec![1; 12] };
271 let mut packed = vec![0u8; seed.tlv_size() as usize - 1];
272 assert_eq!(
273 seed.pack(&mut packed).unwrap_err(),
274 AccountResolutionError::NotEnoughBytesForSeed.into()
275 );
276
277 let seed = Seed::Uninitialized;
279 let mut packed = vec![0u8; seed.tlv_size() as usize];
280 assert_eq!(
281 seed.pack(&mut packed).unwrap_err(),
282 AccountResolutionError::InvalidSeedConfig.into()
283 );
284 }
285
286 #[test]
287 fn test_pack_address_config() {
288 let seed = Seed::Literal { bytes: vec![1; 36] };
290 assert_eq!(
291 Seed::pack_into_address_config(&[seed]).unwrap_err(),
292 AccountResolutionError::SeedConfigsTooLarge.into()
293 );
294
295 let seed1 = Seed::Literal { bytes: vec![1; 30] }; let seed2 = Seed::InstructionData {
298 index: 0,
299 length: 4,
300 }; assert_eq!(
302 Seed::pack_into_address_config(&[seed1, seed2]).unwrap_err(),
303 AccountResolutionError::SeedConfigsTooLarge.into()
304 );
305 }
306
307 #[test]
308 fn test_unpack() {
309 let zeroes = [0u8; 32];
311 let seeds = Seed::unpack_address_config(&zeroes).unwrap();
312 assert_eq!(seeds, vec![]);
313
314 let bytes = [];
316 assert_eq!(
317 Seed::unpack(&bytes).unwrap_err(),
318 ProgramError::InvalidAccountData
319 );
320
321 let bytes = [
323 1, 4, 1, 1, 1, ];
327 assert_eq!(
328 Seed::unpack(&bytes).unwrap_err(),
329 AccountResolutionError::InvalidBytesForSeed.into()
330 );
331
332 let bytes = [
334 2, 2, ];
337 assert_eq!(
338 Seed::unpack(&bytes).unwrap_err(),
339 AccountResolutionError::InvalidBytesForSeed.into()
340 );
341
342 let bytes = [
344 3, ];
346 assert_eq!(
347 Seed::unpack(&bytes).unwrap_err(),
348 AccountResolutionError::InvalidBytesForSeed.into()
349 );
350 }
351
352 #[test]
353 fn test_unpack_address_config() {
354 let bytes = [
356 1, 4, 1, 1, 1, 1, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363 ];
364 assert_eq!(
365 Seed::unpack_address_config(&bytes).unwrap_err(),
366 ProgramError::InvalidAccountData
367 );
368
369 let bytes = [
375 1, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, ];
383 assert_eq!(
384 Seed::unpack_address_config(&bytes).unwrap_err(),
385 AccountResolutionError::InvalidBytesForSeed.into(),
386 );
387
388 let bytes = [
394 1, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, ];
403 assert_eq!(
404 Seed::unpack_address_config(&bytes).unwrap(),
405 vec![
406 Seed::Literal {
407 bytes: vec![1u8; 16]
408 },
409 Seed::Literal {
410 bytes: vec![1u8; 10]
411 },
412 Seed::AccountKey { index: 0 }
413 ],
414 );
415
416 let bytes = [
419 1, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, ];
428 assert_eq!(
429 Seed::unpack_address_config(&bytes).unwrap_err(),
430 AccountResolutionError::InvalidBytesForSeed.into(),
431 );
432 }
433
434 fn test_pack_unpack_seed(seed: Seed) {
435 let tlv_size = seed.tlv_size() as usize;
436 let mut packed = vec![0u8; tlv_size];
437 seed.pack(&mut packed).unwrap();
438 let unpacked = Seed::unpack(&packed).unwrap();
439 assert_eq!(seed, unpacked);
440 }
441
442 #[test]
443 fn test_pack_unpack() {
444 let mut mixed = vec![];
445
446 let bytes = b"hello";
449 let seed = Seed::Literal {
450 bytes: bytes.to_vec(),
451 };
452 test_pack_unpack_seed(seed);
453
454 let bytes = 8u8.to_le_bytes();
455 let seed = Seed::Literal {
456 bytes: bytes.to_vec(),
457 };
458 test_pack_unpack_seed(seed.clone());
459 mixed.push(seed);
460
461 let bytes = 32u32.to_le_bytes();
462 let seed = Seed::Literal {
463 bytes: bytes.to_vec(),
464 };
465 test_pack_unpack_seed(seed.clone());
466 mixed.push(seed);
467
468 let seed = Seed::InstructionData {
471 index: 0,
472 length: 0,
473 };
474 test_pack_unpack_seed(seed);
475
476 let seed = Seed::InstructionData {
477 index: 6,
478 length: 9,
479 };
480 test_pack_unpack_seed(seed.clone());
481 mixed.push(seed);
482
483 let seed = Seed::AccountKey { index: 0 };
486 test_pack_unpack_seed(seed);
487
488 let seed = Seed::AccountKey { index: 9 };
489 test_pack_unpack_seed(seed.clone());
490 mixed.push(seed);
491
492 let seed = Seed::AccountData {
495 account_index: 0,
496 data_index: 0,
497 length: 0,
498 };
499 test_pack_unpack_seed(seed);
500
501 let seed = Seed::AccountData {
502 account_index: 0,
503 data_index: 0,
504 length: 9,
505 };
506 test_pack_unpack_seed(seed.clone());
507 mixed.push(seed);
508
509 let packed_array = Seed::pack_into_address_config(&mixed).unwrap();
512 let unpacked_array = Seed::unpack_address_config(&packed_array).unwrap();
513 assert_eq!(mixed, unpacked_array);
514
515 let mut shuffled_mixed = mixed.clone();
516 shuffled_mixed.swap(0, 1);
517 shuffled_mixed.swap(1, 4);
518 shuffled_mixed.swap(3, 0);
519
520 let packed_array = Seed::pack_into_address_config(&shuffled_mixed).unwrap();
521 let unpacked_array = Seed::unpack_address_config(&packed_array).unwrap();
522 assert_eq!(shuffled_mixed, unpacked_array);
523 }
524}