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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use anchor_lang::prelude::*;

use crate::{majority, MAX_FULFILLMENT_AUTHORITIES_COUNT};

use super::RandomnessResponse;

/// Pending request representation.
#[cfg_attr(feature = "sdk", derive(Debug))]
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct PendingRequest {
    pub client: Pubkey,
    pub seed: [u8; 32],
    /// Responses collected so far.
    pub responses: Vec<RandomnessResponse>,
}

impl PendingRequest {
    pub const SIZE: usize =
        32 + 32 + 4 + (RandomnessResponse::SIZE) * majority(MAX_FULFILLMENT_AUTHORITIES_COUNT);
}

/// Fulfilled request representation.
#[cfg_attr(feature = "sdk", derive(Debug))]
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct FulfilledRequest {
    pub client: Pubkey,
    pub seed: [u8; 32],
    /// Generated randomness.
    ///
    /// Please look into the account history logs to observe the individual components.
    pub randomness: [u8; 64],
}

impl FulfilledRequest {
    pub const SIZE: usize = 32 + 32 + 64;
}

#[cfg_attr(feature = "sdk", derive(Debug))]
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum Request {
    Pending(PendingRequest),
    Fulfilled(FulfilledRequest),
}

impl Request {
    pub const FULFILLED_SIZE: usize = 1 + FulfilledRequest::SIZE;
    pub const PENDING_SIZE: usize = 1 + PendingRequest::SIZE;

    /// Returns fulfilled randomness request.
    ///
    /// Returns `None` if randomness is not yet fulfilled.
    pub const fn fulfilled(&self) -> Option<&FulfilledRequest> {
        match self {
            Request::Pending(_) => None,
            Request::Fulfilled(ref x) => Some(x),
        }
    }

    /// Returns fulfilled randomness request.
    ///
    /// Returns `None` if randomness is not yet fulfilled.
    pub fn fulfilled_mut(&mut self) -> Option<&mut FulfilledRequest> {
        match self {
            Request::Pending(_) => None,
            Request::Fulfilled(ref mut x) => Some(x),
        }
    }

    /// Returns pending randomness request.
    ///
    /// Returns `None` if randomness is already fulfilled.
    pub fn pending(&self) -> Option<&PendingRequest> {
        match self {
            Request::Pending(ref x) => Some(x),
            Request::Fulfilled(_) => None,
        }
    }

    /// Returns pending randomness request.
    ///
    /// Returns `None` if randomness is already fulfilled.
    pub fn pending_mut(&mut self) -> Option<&mut PendingRequest> {
        match self {
            Request::Pending(ref mut x) => Some(x),
            Request::Fulfilled(_) => None,
        }
    }

    /// Returns the request seed.
    pub const fn seed(&self) -> &[u8; 32] {
        match self {
            Request::Pending(ref x) => &x.seed,
            Request::Fulfilled(ref x) => &x.seed,
        }
    }

    /// Returns the request client.
    pub const fn client(&self) -> &Pubkey {
        match self {
            Request::Pending(ref x) => &x.client,
            Request::Fulfilled(ref x) => &x.client,
        }
    }

    /// Returns the pending randomness.
    ///
    /// # Panic
    ///
    /// Panics if the randomness is fulfilled.
    #[inline(always)]
    #[track_caller]
    pub fn unwrap_pending(self) -> PendingRequest {
        match self {
            Request::Pending(x) => x,
            Request::Fulfilled(_) => {
                panic!("called `Request::unwrap_pending()` on a `Fulfilled` request")
            }
        }
    }

    /// Returns the fulfilled randomness.
    ///
    /// # Panic
    ///
    /// Panics if the randomness is pending.
    #[inline(always)]
    #[track_caller]
    pub fn unwrap_fulfilled(self) -> FulfilledRequest {
        match self {
            Request::Fulfilled(x) => x,
            Request::Pending(_) => {
                panic!("called `Request::unwrap_fulfilled()` on a `Pending` request")
            }
        }
    }
}

#[account]
#[cfg_attr(feature = "sdk", derive(Debug))]
pub struct RandomnessV2 {
    pub request: Request,
}

impl RandomnessV2 {
    pub const FULFILLED_SIZE: usize = Request::FULFILLED_SIZE;
    pub const PENDING_SIZE: usize = Request::PENDING_SIZE;

    /// See [`Request::fulfilled`].
    #[inline(always)]
    pub const fn fulfilled(&self) -> Option<&FulfilledRequest> {
        self.request.fulfilled()
    }

    /// See [`Request::fulfilled_mut`].
    #[inline(always)]
    pub fn fulfilled_mut(&mut self) -> Option<&mut FulfilledRequest> {
        self.request.fulfilled_mut()
    }

    /// See [`Request::pending`].
    #[inline(always)]
    pub fn pending(&self) -> Option<&PendingRequest> {
        self.request.pending()
    }

    /// See [`Request::pending_mut`].
    #[inline(always)]
    pub fn pending_mut(&mut self) -> Option<&mut PendingRequest> {
        self.request.pending_mut()
    }

    /// See [`Request::seed`].
    #[inline(always)]
    pub const fn seed(&self) -> &[u8; 32] {
        self.request.seed()
    }

    /// See [`Request::client`].
    #[inline(always)]
    pub const fn client(&self) -> &Pubkey {
        self.request.client()
    }

    /// See [`Request::unwrap_pending`].
    #[inline(always)]
    pub fn unwrap_pending(self) -> PendingRequest {
        self.request.unwrap_pending()
    }

    /// See [`Request::unwrap_fulfilled`].
    #[inline(always)]
    pub fn unwrap_fulfilled(self) -> FulfilledRequest {
        self.request.unwrap_fulfilled()
    }
}