1use crate::prelude::*;
2use crate::*;
3use bytemuck::{Pod, Zeroable};
4use std::cell::Ref;
5
6#[repr(u8)]
7#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
8pub enum FunctionStatus {
9 #[default]
10 None = 0,
11 Active = 1 << 0,
12 NonExecutable = 1 << 1,
13 Expired = 1 << 2,
14 OutOfFunds = 1 << 3,
15 InvalidPermissions = 1 << 4,
16}
17impl From<FunctionStatus> for u8 {
18 fn from(value: FunctionStatus) -> Self {
19 match value {
20 FunctionStatus::Active => 1 << 0,
21 FunctionStatus::NonExecutable => 1 << 1,
22 FunctionStatus::Expired => 1 << 2,
23 FunctionStatus::OutOfFunds => 1 << 3,
24 FunctionStatus::InvalidPermissions => 1 << 4,
25 _ => 0,
26 }
27 }
28}
29impl From<u8> for FunctionStatus {
30 fn from(value: u8) -> Self {
31 match value {
32 1 => FunctionStatus::Active,
33 2 => FunctionStatus::NonExecutable,
34 4 => FunctionStatus::Expired,
35 8 => FunctionStatus::OutOfFunds,
36 16 => FunctionStatus::InvalidPermissions,
37 _ => FunctionStatus::default(),
38 }
39 }
40}
41#[zero_copy(unsafe)]
42#[repr(packed)]
43#[derive(PartialEq, Debug)]
44pub struct FunctionAccountData {
45 #[deprecated(
48 since = "0.28.35",
49 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
50 )]
51 pub is_scheduled: u8,
52 #[deprecated(
54 since = "0.28.35",
55 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
56 )]
57 pub is_triggered: u8,
58
59 pub permissions: u32,
61 pub status: FunctionStatus,
62
63 pub bump: u8,
68 pub creator_seed: [u8; 32],
70 pub name: [u8; 64],
72 pub metadata: [u8; 256],
74 pub created_at_slot: u64,
76 pub created_at: i64,
78 pub updated_at: i64,
80
81 #[deprecated(
86 since = "0.28.35",
87 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
88 )]
89 pub enclave: Quote,
90 pub mr_enclaves: [[u8; 32]; 32],
92
93 pub container_registry: [u8; 64],
98 pub container: [u8; 64],
100 pub version: [u8; 32],
102 #[deprecated(
104 since = "0.28.35",
105 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
106 )]
107 pub params_schema: [u8; 256],
108 #[deprecated(
110 since = "0.28.35",
111 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
112 )]
113 pub default_container_params: [u8; 256],
114
115 pub authority: Pubkey,
120 pub attestation_queue: Pubkey,
122 pub queue_idx: u32,
124 pub address_lookup_table: Pubkey,
126
127 #[deprecated(
132 since = "0.28.35",
133 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
134 )]
135 pub schedule: [u8; 64],
136 #[deprecated(
138 since = "0.28.35",
139 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
140 )]
141 pub last_execution_timestamp: i64,
142 #[deprecated(
144 since = "0.28.35",
145 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
146 )]
147 pub next_allowed_timestamp: i64,
148 #[deprecated(
150 since = "0.28.35",
151 note = "please use a `FunctionRequestAccountData` for all on-demand executions"
152 )]
153 pub trigger_count: u64,
154 #[deprecated(
156 since = "0.28.35",
157 note = "please use a `FunctionRequestAccountData` for all on-demand executions"
158 )]
159 pub triggered_since: i64,
160
161 pub permission_expiration: i64,
164
165 pub num_requests: u64,
168 pub requests_disabled: u8,
170 pub requests_require_authorization: u8,
173 pub reserved1: [u8; 8],
175 pub requests_fee: u64,
179
180 pub escrow_wallet: Pubkey,
183 pub escrow_token_wallet: Pubkey,
185 pub reward_escrow_wallet: Pubkey,
188 pub reward_escrow_token_wallet: Pubkey,
190
191 #[deprecated(
193 since = "0.28.35",
194 note = "please use the error_status field on your function consumer (request or routine)"
195 )]
196 pub error_status: u8,
197
198 pub num_routines: u64,
201 pub routines_disabled: BoolWithLock,
203 pub routines_require_authorization: u8,
206 pub routines_dev_fee: u64,
210
211 pub mr_enclave: [u8; 32],
214 pub verification_status: u8,
216 pub verification_timestamp: i64,
218 pub valid_until: i64,
220
221 pub _ebuf: [u8; 956],
223}
224
225impl Default for FunctionAccountData {
226 fn default() -> Self {
227 unsafe { std::mem::zeroed() }
228 }
229}
230
231impl anchor_lang::AccountDeserialize for FunctionAccountData {
232 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
233 if buf.len() < FunctionAccountData::discriminator().len() {
234 return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
235 }
236 let given_disc = &buf[..8];
237 if FunctionAccountData::discriminator() != given_disc {
238 return Err(
239 anchor_lang::error::Error::from(anchor_lang::error::AnchorError {
240 error_name: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.name(),
241 error_code_number: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
242 .into(),
243 error_msg: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
244 .to_string(),
245 error_origin: Some(anchor_lang::error::ErrorOrigin::Source(
246 anchor_lang::error::Source {
247 filename: "programs/attestation_program/src/lib.rs",
248 line: 1u32,
249 },
250 )),
251 compared_values: None,
252 })
253 .with_account_name("FunctionAccountData"),
254 );
255 }
256 Self::try_deserialize_unchecked(buf)
257 }
258
259 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
260 let data: &[u8] = &buf[8..];
261 bytemuck::try_from_bytes(data)
262 .map(|r: &Self| *r)
263 .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
264 }
265}
266
267unsafe impl Pod for FunctionAccountData {}
268unsafe impl Zeroable for FunctionAccountData {}
269
270impl Discriminator for FunctionAccountData {
271 const DISCRIMINATOR: [u8; 8] = [76, 139, 47, 44, 240, 182, 148, 200];
272}
273
274impl Owner for FunctionAccountData {
275 fn owner() -> Pubkey {
276 SWITCHBOARD_ATTESTATION_PROGRAM_ID
277 }
278}
279
280impl ZeroCopy for FunctionAccountData {}
281
282impl FunctionAccountData {
283 pub fn size() -> usize {
284 8 + std::mem::size_of::<FunctionAccountData>()
285 }
286
287 pub fn new<'info>(
301 function_account_info: &'info AccountInfo<'info>,
302 ) -> anchor_lang::Result<Ref<'info, FunctionAccountData>> {
303 let data = function_account_info.try_borrow_data()?;
304 if data.len() < FunctionAccountData::discriminator().len() {
305 return Err(ErrorCode::AccountDiscriminatorNotFound.into());
306 }
307
308 let mut disc_bytes = [0u8; 8];
309 disc_bytes.copy_from_slice(&data[..8]);
310 if disc_bytes != FunctionAccountData::discriminator() {
311 return Err(ErrorCode::AccountDiscriminatorMismatch.into());
312 }
313
314 Ok(Ref::map(data, |data| {
315 bytemuck::from_bytes(&data[8..std::mem::size_of::<FunctionAccountData>() + 8])
316 }))
317 }
318
319 pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&FunctionAccountData> {
333 if data.len() < FunctionAccountData::discriminator().len() {
334 return Err(ErrorCode::AccountDiscriminatorNotFound.into());
335 }
336
337 let mut disc_bytes = [0u8; 8];
338 disc_bytes.copy_from_slice(&data[..8]);
339 if disc_bytes != FunctionAccountData::discriminator() {
340 return Err(ErrorCode::AccountDiscriminatorMismatch.into());
341 }
342
343 Ok(bytemuck::from_bytes(
344 &data[8..std::mem::size_of::<FunctionAccountData>() + 8],
345 ))
346 }
347
348 pub fn validate(&self, signer: &AccountInfo) -> anchor_lang::Result<bool> {
354 if self.enclave.mr_enclave == [0u8; 32] {
358 return Ok(false);
359 }
360
361 if self.enclave.enclave_signer != signer.key() {
363 return Ok(false);
364 }
365
366 Ok(self.enclave.is_verified(&Clock::get()?))
368 }
369
370 #[deprecated(
376 since = "0.28.35",
377 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
378 )]
379 pub fn validate_signer<'a>(&self, signer: &AccountInfo<'a>) -> anchor_lang::Result<bool> {
380 if self.enclave.mr_enclave == [0u8; 32] {
386 return Ok(false);
387 }
388
389 if self.enclave.enclave_signer != signer.key() {
391 return Ok(false);
392 }
393
394 Ok(self.enclave.is_verified(&Clock::get()?))
396 }
397
398 pub fn validate_request(
447 &self,
448 request: &FunctionRequestAccountData,
449 enclave_signer: &AccountInfo,
450 ) -> anchor_lang::Result<bool> {
451 if request.attestation_queue != self.attestation_queue {
452 msg!(
453 "AttestationQueueMismatch: fn: {}, request: {}",
454 self.attestation_queue,
455 request.attestation_queue
456 );
457 return Ok(false);
458 }
459
460 if request.active_request.enclave_signer != enclave_signer.key() {
461 msg!(
462 "SignerMismatch: expected {}, received {}",
463 request.active_request.enclave_signer,
464 enclave_signer.key()
465 );
466 return Ok(false);
467 }
468
469 if enclave_signer.signer_key().is_none() {
471 msg!(
472 "enclave_signer ({}) did not sign the transaction",
473 enclave_signer.key()
474 );
475 return Ok(false);
476 }
477
478 Ok(true)
479 }
480
481 pub fn validate_routine(
527 &self,
528 routine: &FunctionRoutineAccountData,
529 enclave_signer: &AccountInfo,
530 ) -> anchor_lang::Result<bool> {
531 if routine.attestation_queue != self.attestation_queue {
532 msg!(
533 "AttestationQueueMismatch: fn: {}, routine: {}",
534 self.attestation_queue,
535 routine.attestation_queue
536 );
537 return Ok(false);
538 }
539
540 if routine.enclave_signer != enclave_signer.key() {
542 msg!(
543 "EnclaveSignerMismatch: expected {}, received {}",
544 routine.enclave_signer,
545 enclave_signer.key()
546 );
547 return Ok(false);
548 }
549
550 if enclave_signer.signer_key().is_none() {
552 msg!(
553 "enclave_signer ({}) did not sign the transaction",
554 enclave_signer.key()
555 );
556 return Ok(false);
557 }
558
559 Ok(true)
560 }
561
562 #[deprecated(
563 since = "0.28.35",
564 note = "please use a `FunctionRoutineAccountData` for all scheduled executions"
565 )]
566 pub fn is_empty_schedule(&self) -> bool {
567 self.schedule
568 .first()
569 .map(|&byte| byte == 0)
570 .unwrap_or(false)
571 }
572
573 pub fn get_container(&self) -> String {
574 std::str::from_utf8(&self.container)
575 .unwrap_or("")
576 .trim()
577 .to_string()
578 }
579
580 pub fn get_container_registry(&self) -> String {
581 std::str::from_utf8(&self.container_registry)
582 .unwrap_or("")
583 .trim()
584 .to_string()
585 }
586
587 pub fn get_version(&self) -> String {
588 let version = std::str::from_utf8(&self.version)
589 .unwrap_or("latest")
590 .trim()
591 .to_string();
592
593 if version.is_empty() {
594 String::from("latest")
595 } else {
596 version
597 }
598 }
599
600 pub fn get_name(&self) -> String {
601 format!("{}:{}", self.get_container(), self.get_version()).replace('\u{0}', "")
602 }
603
604 pub fn get_function_name(&self) -> String {
605 std::str::from_utf8(&self.name)
606 .unwrap_or("")
607 .trim()
608 .to_string()
609 }
610
611 pub fn assert_permissions(
621 &self,
622 queue_require_usage_permissions: bool,
623 ) -> anchor_lang::Result<()> {
624 if queue_require_usage_permissions
625 && self.permissions != SwitchboardAttestationPermission::PermitQueueUsage as u32
626 {
627 return Err(error!(SwitchboardError::PermissionDenied));
628 }
629
630 Ok(())
631 }
632
633 pub fn assert_mr_enclave(&self, mr_enclave: &[u8; 32]) -> anchor_lang::Result<()> {
636 if !self.is_valid_enclave(mr_enclave) {
637 return Err(error!(SwitchboardError::InvalidMrEnclave));
638 }
639
640 Ok(())
641 }
642
643 pub fn is_valid_enclave(&self, mr_enclave: &[u8; 32]) -> bool {
655 if *mr_enclave == [0u8; 32] {
656 return false;
657 }
658
659 self.mr_enclaves.contains(mr_enclave)
660 }
661
662 pub fn parse_enclaves(&self) -> Vec<[u8; 32]> {
674 let mut parsed_enclaves: Vec<[u8; 32]> = vec![];
675 for mr_enclave in self.mr_enclaves.iter() {
676 if *mr_enclave != [0u8; 32] {
677 parsed_enclaves.push(*mr_enclave)
678 }
679 }
680 parsed_enclaves
681 }
682
683 pub fn assert_has_enclaves(&self) -> anchor_lang::Result<()> {
689 if self.parse_enclaves().is_empty() {
690 return Err(error!(SwitchboardError::MrEnclavesEmpty));
691 }
692
693 Ok(())
694 }
695
696 fn assert_requests_enabled(&self) -> anchor_lang::Result<()> {
702 if self.requests_disabled.to_bool() {
703 return Err(error!(SwitchboardError::UserRequestsDisabled));
704 }
705
706 Ok(())
707 }
708
709 fn assert_routines_enabled(&self) -> anchor_lang::Result<()> {
715 if self.routines_disabled.is_disabled() {
716 return Err(error!(SwitchboardError::FunctionRoutinesDisabled));
717 }
718
719 Ok(())
720 }
721
722 pub fn ready_for_routines(&self) -> anchor_lang::Result<()> {
736 self.assert_routines_enabled()?;
737 self.assert_has_enclaves()?;
738
739 if self.status != FunctionStatus::Active {
740 return Err(error!(SwitchboardError::FunctionNotReady));
741 }
742
743 Ok(())
744 }
745
746 pub fn ready_for_requests(&self) -> anchor_lang::Result<()> {
760 self.assert_requests_enabled()?;
761 self.assert_has_enclaves()?;
762
763 if self.status != FunctionStatus::Active && self.status != FunctionStatus::OutOfFunds {
764 return Err(error!(SwitchboardError::FunctionNotReady));
765 }
766
767 Ok(())
768 }
769
770 pub fn get_reward_token_wallet(&self) -> Pubkey {
773 if self.reward_escrow_token_wallet != Pubkey::default() {
774 self.reward_escrow_token_wallet
775 } else {
776 self.escrow_token_wallet
777 }
778 }
779}
780#[cfg(test)]
781mod tests {
782 use super::*;
783
784 use std::str::FromStr;
785
786 const FUNCTION_DATA: [u8; 3903] = [
787 76, 139, 47, 44, 240, 182, 148, 200, 1, 0, 0, 0, 0, 0, 1, 254, 218, 146, 221, 148, 1, 120,
788 215, 193, 125, 114, 207, 207, 22, 231, 179, 145, 88, 164, 177, 30, 89, 129, 230, 41, 12,
789 196, 209, 106, 74, 219, 84, 225, 83, 111, 108, 97, 110, 97, 32, 84, 97, 115, 107, 32, 82,
790 117, 110, 110, 101, 114, 32, 70, 117, 110, 99, 116, 105, 111, 110, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
799 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
800 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 18, 218, 14, 0, 0, 0, 0, 227, 58, 32,
801 101, 0, 0, 0, 0, 236, 84, 32, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
802 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
804 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
805 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
806 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
807 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
808 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
809 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
810 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
811 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
812 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
813 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
815 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
816 225, 147, 52, 198, 184, 237, 187, 106, 131, 221, 177, 176, 80, 145, 117, 118, 50, 205, 62,
817 19, 161, 35, 83, 210, 209, 6, 138, 101, 21, 112, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
818 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
819 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
820 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
821 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
827 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
828 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
830 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
831 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
832 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
833 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
834 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
835 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
836 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
837 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
838 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
839 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
840 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
841 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
842 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
843 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
844 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
845 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
846 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
847 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
849 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
850 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 111, 99, 107, 101, 114,
851 104, 117, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
852 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115,
853 119, 105, 116, 99, 104, 98, 111, 97, 114, 100, 108, 97, 98, 115, 47, 115, 111, 108, 97,
854 110, 97, 45, 116, 97, 115, 107, 45, 114, 117, 110, 110, 101, 114, 45, 102, 117, 110, 99,
855 116, 105, 111, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 97,
856 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
857 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
858 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
859 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
860 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
861 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
862 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
863 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
864 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
865 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
866 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
872 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
873 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
874 0, 0, 0, 0, 218, 146, 221, 148, 1, 120, 215, 193, 125, 114, 207, 207, 22, 231, 179, 145,
875 88, 164, 177, 30, 89, 129, 230, 41, 12, 196, 209, 106, 74, 219, 84, 225, 174, 177, 70, 231,
876 73, 196, 214, 194, 190, 219, 159, 24, 162, 119, 159, 16, 120, 53, 239, 102, 225, 241, 66,
877 97, 108, 144, 152, 47, 53, 76, 242, 215, 0, 0, 0, 0, 70, 65, 33, 246, 149, 218, 240, 26,
878 241, 158, 100, 187, 243, 161, 203, 30, 151, 239, 214, 115, 213, 239, 24, 92, 137, 228, 4,
879 197, 143, 13, 48, 131, 42, 32, 42, 47, 53, 32, 42, 32, 42, 32, 42, 32, 42, 0, 0, 0, 0, 0,
880 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
881 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 120, 45, 101, 0, 0, 0, 0, 149, 120,
882 45, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
883 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 249,
884 132, 49, 100, 114, 123, 49, 150, 198, 234, 193, 130, 176, 237, 177, 72, 2, 22, 174, 106,
885 202, 197, 89, 28, 119, 35, 166, 73, 57, 38, 23, 116, 180, 233, 161, 252, 164, 99, 206, 179,
886 104, 122, 218, 86, 162, 24, 43, 248, 82, 63, 111, 64, 70, 179, 213, 70, 253, 4, 4, 203, 25,
887 32, 254, 160, 249, 132, 49, 100, 114, 123, 49, 150, 198, 234, 193, 130, 176, 237, 177, 72,
888 2, 22, 174, 106, 202, 197, 89, 28, 119, 35, 166, 73, 57, 38, 23, 116, 180, 233, 161, 252,
889 164, 99, 206, 179, 104, 122, 218, 86, 162, 24, 43, 248, 82, 63, 111, 64, 70, 179, 213, 70,
890 253, 4, 4, 203, 25, 32, 254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
891 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
892 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
893 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
894 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
895 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
896 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
897 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
899 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
900 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
901 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
902 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
903 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
904 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
906 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
907 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
909 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
910 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
911 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
912 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
913 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
914 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
915 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
916 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
917 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
918 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
919 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
920 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
921 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
922 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
923 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
924 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
925 ];
926
927 const FUNCTION_DATA_HEX: &str = "4c8b2f2cf0b694c801000000000001feda92dd940178d7c17d72cfcf16e7b39158a4b11e5981e6290cc4d16a4adb54e1536f6c616e61205461736b2052756e6e65722046756e6374696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c712da0e00000000e33a206500000000ec542065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023e19334c6b8edbb6a83ddb1b05091757632cd3e13a12353d2d1068a6515707d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000646f636b657268756200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000737769746368626f6172646c6162732f736f6c616e612d7461736b2d72756e6e65722d66756e6374696f6e0000000000000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000da92dd940178d7c17d72cfcf16e7b39158a4b11e5981e6290cc4d16a4adb54e1aeb146e749c4d6c2bedb9f18a2779f107835ef66e1f142616c90982f354cf2d700000000464121f695daf01af19e64bbf3a1cb1e97efd673d5ef185c89e404c58f0d30832a202a2f35202a202a202a202a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076782d650000000095782d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0f9843164727b3196c6eac182b0edb1480216ae6acac5591c7723a64939261774b4e9a1fca463ceb3687ada56a2182bf8523f6f4046b3d546fd0404cb1920fea0f9843164727b3196c6eac182b0edb1480216ae6acac5591c7723a64939261774b4e9a1fca463ceb3687ada56a2182bf8523f6f4046b3d546fd0404cb1920feff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
928
929 #[test]
930 fn test_function_deserialization() {
931 let function =
932 FunctionAccountData::try_deserialize_unchecked(&mut FUNCTION_DATA.as_slice()).unwrap();
933
934 assert_eq!(
935 std::str::from_utf8(&function.container)
936 .unwrap()
937 .to_string()
938 .trim_matches(char::from(0)),
939 "switchboardlabs/solana-task-runner-function"
940 );
941
942 assert_eq!(
943 std::str::from_utf8(&function.container_registry)
944 .unwrap()
945 .to_string()
946 .trim_matches(char::from(0)),
947 "dockerhub"
948 );
949
950 assert_eq!(
951 std::str::from_utf8(&function.version)
952 .unwrap()
953 .to_string()
954 .trim_matches(char::from(0)),
955 "latest"
956 );
957
958 assert_eq!(
959 function.attestation_queue,
960 Pubkey::from_str("CkvizjVnm2zA5Wuwan34NhVT3zFc7vqUyGnA6tuEF5aE").unwrap()
961 );
962
963 assert_eq!(
964 function.authority,
965 Pubkey::from_str("FiDmUK83DTc1ijEyVnwMoQwJ6W4gC2S8JhncKsheDQTJ").unwrap()
966 );
967 }
968
969 #[test]
970 fn test_hex_decode() {
971 let account_bytes = hex::decode(FUNCTION_DATA_HEX).unwrap();
972 let function = FunctionAccountData::try_deserialize(&mut account_bytes.as_slice()).unwrap();
973
974 assert_eq!(
975 std::str::from_utf8(&function.container)
976 .unwrap()
977 .to_string()
978 .trim_matches(char::from(0)),
979 "switchboardlabs/solana-task-runner-function"
980 );
981
982 assert_eq!(
983 std::str::from_utf8(&function.container_registry)
984 .unwrap()
985 .to_string()
986 .trim_matches(char::from(0)),
987 "dockerhub"
988 );
989
990 assert_eq!(
991 std::str::from_utf8(&function.version)
992 .unwrap()
993 .to_string()
994 .trim_matches(char::from(0)),
995 "latest"
996 );
997
998 assert_eq!(
999 function.attestation_queue,
1000 Pubkey::from_str("CkvizjVnm2zA5Wuwan34NhVT3zFc7vqUyGnA6tuEF5aE").unwrap()
1001 );
1002
1003 assert_eq!(
1004 function.authority,
1005 Pubkey::from_str("FiDmUK83DTc1ijEyVnwMoQwJ6W4gC2S8JhncKsheDQTJ").unwrap()
1006 );
1007 }
1008}