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
use crate::SbError;
use serde::Deserialize;

fn default_cluster() -> String {
    "devnet".to_string()
}

const DEFAULT_PUBKEY: &str = "11111111111111111111111111111111";

/// The expected environment variables when a solana function is being executed
#[derive(Deserialize, Debug, Default)]
pub struct SolanaFunctionEnvironment {
    /// FUNCTION_KEY: the pubkey of the function being executed
    pub function_key: String,
    /// PAYER: The gas payer for this transaction
    pub payer: String,
    /// VERIFIER: the pubey of the oracle veriying this call
    pub verifier: String,
    /// REWARD_RECEIVER: The escrow to send the reward the oracle will receive
    /// for executing this function
    pub reward_receiver: String,

    // can be manually populated from client if missing
    /// FUNCTION_DATA: The preloaded data of the `FUNCTION_KEY` account
    #[serde(default)]
    pub function_data: String,
    /// VERIFIER_ENCLAVE_SIGNER: The keypair the verifying oracle is using to
    /// sign this transaction.
    #[serde(default)]
    pub verifier_enclave_signer: String,
    /// QUEUE_AUTHORITY: The authority of the oracle queue this function is
    /// executing on.
    #[serde(default)]
    pub queue_authority: String,

    // only used for requests
    /// FUNCTION_REQUEST_KEY: If this function is being called with parameters,
    /// this ariable will hold the pubkey of the request account
    #[serde(default)]
    pub function_request_key: String,
    /// FUNCTION_REQUEST_DATA: The preloaded data of the `FUNCTION_REQUEST_KEY`
    /// account
    #[serde(default)]
    pub function_request_data: String,

    // helpers
    #[serde(default = "default_cluster")]
    pub cluster: String,
}
impl SolanaFunctionEnvironment {
    pub fn parse() -> Result<Self, SbError> {
        match envy::from_env::<SolanaFunctionEnvironment>() {
            Ok(env) => Ok(env),
            Err(error) => Err(SbError::CustomMessage(format!(
                "failed to decode environment variables: {}",
                error
            ))),
        }
    }

    /**
     * Returns the vec! of environment variable key-value pairs used by bollard
     */
    pub fn to_env(&self) -> Vec<String> {
        let mut env = vec![];
        env.push(format!("CLUSTER={}", self.cluster));
        env.push(format!("FUNCTION_KEY={}", self.function_key));
        env.push(format!("PAYER={}", self.payer));
        env.push(format!("VERIFIER={}", self.verifier));
        env.push(format!("REWARD_RECEIVER={}", self.reward_receiver));

        if !self.function_request_key.is_empty()
            && &self.function_request_key != &DEFAULT_PUBKEY.to_string()
        {
            env.push(format!(
                "FUNCTION_REQUEST_KEY={}",
                self.function_request_key
            ));
        }

        if !self.verifier_enclave_signer.is_empty()
            && &self.verifier_enclave_signer != &DEFAULT_PUBKEY.to_string()
        {
            env.push(format!(
                "VERIFIER_ENCLAVE_SIGNER={}",
                self.verifier_enclave_signer
            ));
        }

        if !self.queue_authority.is_empty() && &self.queue_authority != &DEFAULT_PUBKEY.to_string()
        {
            env.push(format!("QUEUE_AUTHORITY={}", self.queue_authority));
        }

        if !self.function_data.is_empty() && !self.function_data.chars().all(|c| c == '0') {
            env.push(format!("FUNCTION_DATA={}", self.function_data));
        }

        if !self.function_request_data.is_empty()
            && !self.function_request_data.chars().all(|c| c == '0')
        {
            env.push(format!(
                "FUNCTION_REQUEST_DATA={}",
                self.function_request_data
            ));
        }

        env
    }
}