Skip to content

Commit 0eafdf5

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

File tree

2 files changed

+141
-77
lines changed

2 files changed

+141
-77
lines changed
Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,120 @@
1-
use core::slice::from_raw_parts;
1+
use core::{mem::MaybeUninit, slice};
22

33
use pinocchio::{
44
account_info::AccountInfo,
5+
cpi::slice_invoke_signed,
56
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
77
program_error::ProgramError,
88
ProgramResult,
99
};
1010

11-
extern crate alloc;
12-
13-
use alloc::vec::Vec;
14-
15-
use crate::{write_bytes, UNINIT_BYTE};
16-
1711
/// Initialize a new Multisig.
1812
///
1913
/// ### Accounts:
2014
/// 0. `[writable]` The multisig account to initialize.
2115
/// 1. `[]` Rent sysvar
22-
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23-
/// 11`.
16+
/// 2. ..`2+N`. `[]` The N signer accounts, where N is between 1 and 11.
2417
pub struct InitializeMultisig<'a> {
2518
/// Multisig Account.
2619
pub multisig: &'a AccountInfo,
2720
/// Rent sysvar Account.
2821
pub rent_sysvar: &'a AccountInfo,
2922
/// Signer Accounts
30-
pub multisig_signers: Vec<&'a AccountInfo>,
23+
pub multisig_signers: &'a [&'a AccountInfo],
3124
/// The number of signers (M) required to validate this multisignature
3225
/// account.
3326
pub m: u8,
3427
}
3528

3629
impl InitializeMultisig<'_> {
30+
pub const MAX_ALLOWED_ACCOUNTS: usize = 1 + 1 + 11; // 1 multisig + 1 rent_sysvar + 11 MAX_SIGNERS
31+
3732
#[inline(always)]
38-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
39-
self.invoke_signed::<ACCOUNTS>(&[])
33+
pub fn invoke(&self) -> ProgramResult {
34+
self.slice_invoke_signed(&[])
4035
}
4136

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

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

51-
account_metas.extend(
52-
self.multisig_signers
53-
.iter()
54-
.map(|a| AccountMeta::readonly(a.key())),
55-
);
68+
for i in 2..(2 + multisig_signers.len()) {
69+
unsafe {
70+
// SAFETY:
71+
// - `i` in 2..(2 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
72+
// - `i - 2` < multisig_signers.len()
73+
acc_metas.get_unchecked_mut(i).write(AccountMeta::readonly(
74+
multisig_signers.get_unchecked(i - 2).key(),
75+
));
76+
}
77+
}
5678

5779
// Instruction data layout:
5880
// - [0]: instruction discriminator (1 byte, u8)
5981
// - [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]);
82+
let data = &[2, m];
6683

6784
let instruction = Instruction {
6885
program_id: &crate::ID,
69-
accounts: account_metas.as_slice(),
70-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
86+
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
87+
data,
7188
};
7289

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

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

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

83-
invoke_signed(&instruction, &account_infos, signers)
114+
slice_invoke_signed(
115+
&instruction,
116+
unsafe { slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts) },
117+
signers,
118+
)
84119
}
85120
}
Lines changed: 68 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,112 @@
1-
use core::slice::from_raw_parts;
1+
use core::{mem::MaybeUninit, slice};
22

33
use pinocchio::{
44
account_info::AccountInfo,
5+
cpi::slice_invoke_signed,
56
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
77
program_error::ProgramError,
88
ProgramResult,
99
};
1010

11-
extern crate alloc;
12-
13-
use alloc::vec::Vec;
14-
15-
use crate::{write_bytes, UNINIT_BYTE};
16-
1711
/// Initialize a new Multisig.
1812
///
1913
/// ### Accounts:
2014
/// 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`.
15+
/// 1. ..`1+N`. `[]` The N signer accounts, where N is between 1 and 11.
2416
pub struct InitializeMultisig2<'a> {
2517
/// Multisig Account.
2618
pub multisig: &'a AccountInfo,
2719
/// Signer Accounts
28-
pub multisig_signers: Vec<&'a AccountInfo>,
20+
pub multisig_signers: &'a [&'a AccountInfo],
2921
/// The number of signers (M) required to validate this multisignature
3022
/// account.
3123
pub m: u8,
3224
}
3325

3426
impl InitializeMultisig2<'_> {
27+
pub const MAX_ALLOWED_ACCOUNTS: usize = 1 + 11; // 1 multisig + 11 MAX_SIGNERS
28+
3529
#[inline(always)]
36-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
37-
self.invoke_signed::<ACCOUNTS>(&[])
30+
pub fn invoke(&self) -> ProgramResult {
31+
self.slice_invoke_signed(&[])
3832
}
3933

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

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

49-
account_metas.extend(
50-
self.multisig_signers
51-
.iter()
52-
.map(|a| AccountMeta::readonly(a.key())),
53-
);
61+
for i in 1..(1 + multisig_signers.len()) {
62+
unsafe {
63+
// SAFETY:
64+
// - `i` in 1..(1 + multisig_signers.len()) is guaranteed less than MAX_ALLOWED_ACCOUNTS
65+
// - `i - 1` < multisig_signers.len()
66+
acc_metas.get_unchecked_mut(i).write(AccountMeta::readonly(
67+
multisig_signers.get_unchecked(i - 1).key(),
68+
));
69+
}
70+
}
5471

5572
// Instruction data layout:
5673
// - [0]: instruction discriminator (1 byte, u8)
5774
// - [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]);
75+
let data = &[2, m];
6476

6577
let instruction = Instruction {
6678
program_id: &crate::ID,
67-
accounts: account_metas.as_slice(),
68-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
79+
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
80+
data,
6981
};
7082

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

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

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

81-
invoke_signed(&instruction, &account_infos, signers)
106+
slice_invoke_signed(
107+
&instruction,
108+
unsafe { slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts) },
109+
signers,
110+
)
82111
}
83112
}

0 commit comments

Comments
 (0)