1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::*;

#[derive(Clone)]
pub struct ServiceRowWithData {
    pub service: Pubkey,
    pub service_account: FunctionServiceAccountData,
    pub function: Pubkey,
    pub function_account: FunctionAccountData,
}

impl ServiceWorkerAccountData {
    pub fn fetch(
        client: &solana_client::rpc_client::RpcClient,
        pubkey: Pubkey,
    ) -> std::result::Result<Self, switchboard_common::SbError> {
        crate::client::fetch_zerocopy_account(client, pubkey)
    }

    pub async fn fetch_async(
        client: &solana_client::nonblocking::rpc_client::RpcClient,
        pubkey: Pubkey,
    ) -> std::result::Result<Self, switchboard_common::SbError> {
        crate::client::fetch_zerocopy_account_async(client, pubkey).await
    }

    pub fn fetch_sync<T: solana_sdk::client::SyncClient>(
        client: &T,
        pubkey: Pubkey,
    ) -> std::result::Result<Self, switchboard_common::SbError> {
        crate::client::fetch_zerocopy_account_sync(client, pubkey)
    }

    /// Fetch all services and account data for a given ServiceWorker
    pub async fn fetch_services(
        &self,
        client: &solana_client::nonblocking::rpc_client::RpcClient,
    ) -> std::result::Result<Vec<ServiceRowWithData>, switchboard_common::SbError> {
        let rows = &self.services[..self.services_len as usize];

        let mut service_pubkeys: Vec<Pubkey> = vec![];
        let mut function_pubkeys: Vec<Pubkey> = vec![];

        for row in rows {
            service_pubkeys.push(row.service);
            function_pubkeys.push(row.function);
        }

        let all_pubkeys: Vec<Pubkey> = [service_pubkeys.clone(), function_pubkeys.clone()].concat();

        let accounts: Vec<Option<solana_sdk::account::Account>> =
            match client.get_multiple_accounts(&all_pubkeys).await {
                Err(e) => {
                    log::error!("Error fetching accounts: {:?}", e);
                    return Err(switchboard_common::SbError::CustomError {
                        message: "Failed to call getProgramAccounts".to_string(),
                        source: std::sync::Arc::new(e),
                    });
                }
                Ok(accounts) => accounts,
            };

        let mut services: Vec<ServiceRowWithData> = Vec::with_capacity(rows.len());

        for i in 0..rows.len() {
            let service_pubkey = service_pubkeys[i];
            let service_account = match accounts[i].clone() {
                None => {
                    log::error!("Error fetching service account {:?}", service_pubkey);
                    continue;
                }
                Some(account) => {
                    match FunctionServiceAccountData::try_deserialize(&mut &account.data[..]) {
                        Ok(service) => service,
                        Err(e) => {
                            log::error!(
                                "Error deseserializing service account {:?}: {:?}",
                                service_pubkey,
                                e
                            );
                            continue;
                        }
                    }
                }
            };

            let function_pubkey = function_pubkeys[i];
            let function_account = match accounts[i + rows.len()].clone() {
                None => {
                    log::error!("Error fetching function account {:?}", function_pubkey);
                    continue;
                }
                Some(account) => {
                    match FunctionAccountData::try_deserialize(&mut &account.data[..]) {
                        Ok(function) => function,
                        Err(e) => {
                            log::error!(
                                "Error deseserializing function account {:?}: {:?}",
                                function_pubkey,
                                e
                            );
                            continue;
                        }
                    }
                }
            };

            services[i] = ServiceRowWithData {
                service: service_pubkey,
                service_account,
                function: function_pubkey,
                function_account,
            };
        }

        Ok(services)
    }
}