Skip to content

Commit 1fb3bee

Browse files
committed
chore : resolve comments and refactor
1 parent 98ee441 commit 1fb3bee

File tree

2 files changed

+143
-83
lines changed

2 files changed

+143
-83
lines changed
Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,118 @@
1-
use core::slice::from_raw_parts;
1+
use core::mem::MaybeUninit;
22

33
use pinocchio::{
44
account_info::AccountInfo,
5+
cpi::slice_invoke_signed,
56
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
7-
program_error::ProgramError,
87
ProgramResult,
98
};
109

11-
extern crate alloc;
12-
13-
use alloc::vec::Vec;
14-
15-
use crate::{write_bytes, UNINIT_BYTE};
16-
1710
/// Initialize a new Multisig.
1811
///
1912
/// ### Accounts:
2013
/// 0. `[writable]` The multisig account to initialize.
2114
/// 1. `[]` Rent sysvar
22-
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23-
/// 11`.
15+
/// 2. ..`2+N`. `[]` The N signer accounts, where N is between 1 and 11.
2416
pub struct InitializeMultisig<'a> {
2517
/// Multisig Account.
2618
pub multisig: &'a AccountInfo,
2719
/// Rent sysvar Account.
2820
pub rent_sysvar: &'a AccountInfo,
2921
/// Signer Accounts
30-
pub multisig_signers: Vec<&'a AccountInfo>,
22+
pub multisig_signers: &'a [&'a AccountInfo],
3123
/// The number of signers (M) required to validate this multisignature
3224
/// account.
3325
pub m: u8,
3426
}
3527

3628
impl InitializeMultisig<'_> {
29+
pub const MAX_ALLOWED_ACCOUNTS: usize = 1 + 1 + 11; // 1 multisig + 1 rent_sysvar + 11 MAX_SIGNERS
30+
3731
#[inline(always)]
38-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
39-
self.invoke_signed::<ACCOUNTS>(&[])
32+
pub fn invoke(&self) -> ProgramResult {
33+
self.slice_invoke_signed(&[])
4034
}
4135

42-
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
43-
if ACCOUNTS != self.multisig_signers.len() + 2 {
44-
return Err(ProgramError::InvalidArgument);
45-
}
36+
pub fn slice_invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
37+
let &Self {
38+
multisig,
39+
rent_sysvar,
40+
multisig_signers,
41+
m,
42+
} = self;
43+
44+
let num_accounts = 2 + multisig_signers.len();
4645

4746
// Account metadata
48-
let mut account_metas = Vec::with_capacity(1 + self.multisig_signers.len());
49-
account_metas.push(AccountMeta::writable(self.multisig.key()));
47+
const UNINIT_META: MaybeUninit<AccountMeta> = MaybeUninit::<AccountMeta>::uninit();
48+
let mut account_metas = [UNINIT_META; Self::MAX_ALLOWED_ACCOUNTS];
49+
50+
unsafe {
51+
// SAFETY:
52+
// - `account_metas` is sized to at least MAX_ALLOWED_ACCOUNTS
53+
// - Index 0 and 1 are always present
54+
account_metas
55+
.get_unchecked_mut(0)
56+
.write(AccountMeta::writable(multisig.key()));
57+
account_metas
58+
.get_unchecked_mut(1)
59+
.write(AccountMeta::readonly(rent_sysvar.key()));
60+
}
5061

51-
account_metas.extend(
52-
self.multisig_signers
53-
.iter()
54-
.map(|a| AccountMeta::readonly(a.key())),
55-
);
62+
for i in 2..(2 + multisig_signers.len()) {
63+
unsafe {
64+
// SAFETY:
65+
// - `i` in 2..(2 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
66+
// - `i - 2` < multisig_signers.len()
67+
account_metas
68+
.get_unchecked_mut(i)
69+
.write(AccountMeta::readonly(
70+
multisig_signers.get_unchecked(i - 2).key(),
71+
));
72+
}
73+
}
5674

5775
// Instruction data layout:
5876
// - [0]: instruction discriminator (1 byte, u8)
5977
// - [1]: m (1 byte, u8)
60-
let mut instruction_data = [UNINIT_BYTE; 2];
61-
62-
// Set discriminator as u8 at offset [0]
63-
write_bytes(&mut instruction_data, &[2]);
64-
// Set number of signers (m) at offset 1
65-
write_bytes(&mut instruction_data[1..2], &[self.m]);
78+
let data = &[2, m];
6679

6780
let instruction = Instruction {
6881
program_id: &crate::ID,
69-
accounts: account_metas.as_slice(),
70-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
82+
accounts: unsafe {
83+
core::slice::from_raw_parts(account_metas.as_ptr() as _, num_accounts)
84+
},
85+
data,
7186
};
7287

73-
let mut account_infos = Vec::with_capacity(2 + self.multisig_signers.len());
88+
// Account info array
89+
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
90+
let mut account_infos = [UNINIT_INFO; Self::MAX_ALLOWED_ACCOUNTS];
7491

75-
account_infos.push(self.multisig);
76-
77-
account_infos.extend_from_slice(self.multisig_signers.as_slice());
92+
unsafe {
93+
// SAFETY:
94+
// - `account_infos` is sized to at least MAX_ALLOWED_ACCOUNTS
95+
// - Index 0 and 1 are always present
96+
account_infos.get_unchecked_mut(0).write(multisig);
97+
account_infos.get_unchecked_mut(1).write(rent_sysvar);
98+
}
7899

79-
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
80-
.try_into()
81-
.map_err(|_| ProgramError::InvalidArgument)?;
100+
// Fill signer accounts
101+
for i in 2..(2 + multisig_signers.len()) {
102+
unsafe {
103+
// SAFETY:
104+
// - `i` in 2..(2 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
105+
// - `i - 2` < multisig_signers.len()
106+
account_infos
107+
.get_unchecked_mut(i)
108+
.write(multisig_signers.get_unchecked(i - 2));
109+
}
110+
}
82111

83-
invoke_signed(&instruction, &account_infos, signers)
112+
slice_invoke_signed(
113+
&instruction,
114+
unsafe { core::slice::from_raw_parts(account_infos.as_ptr() as _, num_accounts) },
115+
signers,
116+
)
84117
}
85118
}
Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,110 @@
1-
use core::slice::from_raw_parts;
1+
use core::mem::MaybeUninit;
22

33
use pinocchio::{
44
account_info::AccountInfo,
5+
cpi::slice_invoke_signed,
56
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
7-
program_error::ProgramError,
87
ProgramResult,
98
};
109

11-
extern crate alloc;
12-
13-
use alloc::vec::Vec;
14-
15-
use crate::{write_bytes, UNINIT_BYTE};
16-
1710
/// Initialize a new Multisig.
1811
///
1912
/// ### Accounts:
2013
/// 0. `[writable]` The multisig account to initialize.
21-
/// 1. `[]` Rent sysvar
22-
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23-
/// 11`.
14+
/// 1. ..`1+N`. `[]` The N signer accounts, where N is between 1 and 11.
2415
pub struct InitializeMultisig2<'a> {
2516
/// Multisig Account.
2617
pub multisig: &'a AccountInfo,
2718
/// Signer Accounts
28-
pub multisig_signers: Vec<&'a AccountInfo>,
19+
pub multisig_signers: &'a [&'a AccountInfo],
2920
/// The number of signers (M) required to validate this multisignature
3021
/// account.
3122
pub m: u8,
3223
}
3324

3425
impl InitializeMultisig2<'_> {
26+
pub const MAX_ALLOWED_ACCOUNTS: usize = 1 + 11; // 1 multisig + 11 MAX_SIGNERS
27+
3528
#[inline(always)]
36-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
37-
self.invoke_signed::<ACCOUNTS>(&[])
29+
pub fn invoke(&self) -> ProgramResult {
30+
self.slice_invoke_signed(&[])
3831
}
3932

40-
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
41-
if ACCOUNTS != self.multisig_signers.len() + 1 {
42-
return Err(ProgramError::InvalidArgument);
43-
}
33+
pub fn slice_invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
34+
let &Self {
35+
multisig,
36+
multisig_signers,
37+
m,
38+
} = self;
39+
40+
let num_accounts = 1 + multisig_signers.len();
4441

4542
// Account metadata
46-
let mut account_metas = Vec::with_capacity(1 + self.multisig_signers.len());
47-
account_metas.push(AccountMeta::writable(self.multisig.key()));
43+
const UNINIT_META: MaybeUninit<AccountMeta> = MaybeUninit::<AccountMeta>::uninit();
44+
let mut account_metas = [UNINIT_META; Self::MAX_ALLOWED_ACCOUNTS];
45+
46+
unsafe {
47+
// SAFETY:
48+
// - `account_metas` is sized to at least MAX_ALLOWED_ACCOUNTS
49+
// - Index 0 is always present
50+
account_metas
51+
.get_unchecked_mut(0)
52+
.write(AccountMeta::writable(multisig.key()));
53+
}
4854

49-
account_metas.extend(
50-
self.multisig_signers
51-
.iter()
52-
.map(|a| AccountMeta::readonly(a.key())),
53-
);
55+
for i in 1..(1 + multisig_signers.len()) {
56+
unsafe {
57+
// SAFETY:
58+
// - `i` in 1..(1 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
59+
// - `i - 1` < multisig_signers.len()
60+
account_metas
61+
.get_unchecked_mut(i)
62+
.write(AccountMeta::readonly(
63+
multisig_signers.get_unchecked(i - 1).key(),
64+
));
65+
}
66+
}
5467

5568
// Instruction data layout:
5669
// - [0]: instruction discriminator (1 byte, u8)
5770
// - [1]: m (1 byte, u8)
58-
let mut instruction_data = [UNINIT_BYTE; 2];
59-
60-
// Set discriminator as u8 at offset [0]
61-
write_bytes(&mut instruction_data, &[2]);
62-
// Set number of signers (m) at offset 1
63-
write_bytes(&mut instruction_data[1..2], &[self.m]);
71+
let data = &[2, m];
6472

6573
let instruction = Instruction {
6674
program_id: &crate::ID,
67-
accounts: account_metas.as_slice(),
68-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
75+
accounts: unsafe {
76+
core::slice::from_raw_parts(account_metas.as_ptr() as _, num_accounts)
77+
},
78+
data,
6979
};
7080

71-
let mut account_infos = Vec::with_capacity(1 + self.multisig_signers.len());
81+
// Account info array
82+
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
83+
let mut account_infos = [UNINIT_INFO; Self::MAX_ALLOWED_ACCOUNTS];
7284

73-
account_infos.push(self.multisig);
74-
75-
account_infos.extend_from_slice(self.multisig_signers.as_slice());
85+
unsafe {
86+
// SAFETY:
87+
// - `account_infos` is sized to at least MAX_ALLOWED_ACCOUNTS
88+
// - Index 0 is always present
89+
account_infos.get_unchecked_mut(0).write(multisig);
90+
}
7691

77-
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
78-
.try_into()
79-
.map_err(|_| ProgramError::InvalidArgument)?;
92+
// Fill signer accounts
93+
for i in 1..(1 + multisig_signers.len()) {
94+
unsafe {
95+
// SAFETY:
96+
// - `i` in 1..(1 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
97+
// - `i - 1` < multisig_signers.len()
98+
account_infos
99+
.get_unchecked_mut(i)
100+
.write(multisig_signers.get_unchecked(i - 1));
101+
}
102+
}
80103

81-
invoke_signed(&instruction, &account_infos, signers)
104+
slice_invoke_signed(
105+
&instruction,
106+
unsafe { core::slice::from_raw_parts(account_infos.as_ptr() as _, num_accounts) },
107+
signers,
108+
)
82109
}
83110
}

0 commit comments

Comments
 (0)