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
use {
crate::{instructions::initialize_multisig::MAX_MULTISIG_SIGNERS, ID},
core::mem::size_of,
solana_account_view::{AccountView, Ref},
solana_address::Address,
solana_program_error::ProgramError,
};
/// Multisignature data.
#[repr(C)]
pub struct Multisig {
/// Number of signers required
m: u8,
/// Number of valid signers
n: u8,
/// Is `true` if this structure has been initialized
is_initialized: u8,
/// Signer public keys
signers: [Address; MAX_MULTISIG_SIGNERS],
}
impl Multisig {
/// The length of the `Multisig` account data.
pub const LEN: usize = size_of::<Multisig>();
/// Return a `Multisig` from the given account view.
///
/// This method performs owner and length validation on `AccountView`, safe
/// borrowing the account data.
#[inline]
pub fn from_account_view(
account_view: &AccountView,
) -> Result<Ref<'_, Multisig>, ProgramError> {
if account_view.data_len() != Self::LEN {
return Err(ProgramError::InvalidAccountData);
}
if !account_view.owned_by(&ID) {
return Err(ProgramError::InvalidAccountOwner);
}
Ok(Ref::map(account_view.try_borrow()?, |data| unsafe {
Self::from_bytes_unchecked(data)
}))
}
/// Return a `Multisig` from the given account view.
///
/// This method performs owner and length validation on `AccountView`, but
/// does not perform the borrow check.
///
/// # Safety
///
/// The caller must ensure that it is safe to borrow the account data (e.g.,
/// there are no mutable borrows of the account data).
#[inline]
pub unsafe fn from_account_view_unchecked(
account_view: &AccountView,
) -> Result<&Self, ProgramError> {
if account_view.data_len() != Self::LEN {
return Err(ProgramError::InvalidAccountData);
}
if account_view.owner() != &ID {
return Err(ProgramError::InvalidAccountOwner);
}
Ok(Self::from_bytes_unchecked(account_view.borrow_unchecked()))
}
/// Return a `Multisig` from the given bytes.
///
/// # Safety
///
/// The caller must ensure that `bytes` contains a valid representation of
/// `Multisig`, and it has the correct length to be interpreted as an
/// instance of `Multisig`.
#[inline(always)]
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
&*(bytes.as_ptr() as *const Multisig)
}
/// Number of signers required to validate the `Multisig` signature.
#[inline(always)]
pub const fn required_signers(&self) -> u8 {
self.m
}
/// Number of signer addresses present on the `Multisig`.
#[inline(always)]
pub const fn signers_len(&self) -> usize {
self.n as usize
}
/// Return the signer addresses of the `Multisig`.
#[inline(always)]
pub fn signers(&self) -> &[Address] {
// SAFETY: `self.signers` is an array of `Address` with a fixed size of
// `MAX_MULTISIG_SIGNERS`; `self.signers_len` is always `<=
// MAX_MULTISIG_SIGNERS` and indicates how many of these signers are
// valid.
unsafe { self.signers.get_unchecked(..self.signers_len()) }
}
/// Check whether the multisig is initialized or not.
//
// It will return a boolean value indicating whether [`self.is_initialized`]
// is different than `0` or not.
#[inline(always)]
pub fn is_initialized(&self) -> bool {
self.is_initialized != 0
}
}