Skip to content

Commit ed203c5

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

File tree

2 files changed

+114
-85
lines changed

2 files changed

+114
-85
lines changed
Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,103 @@
1-
use core::slice::from_raw_parts;
1+
use core::{mem::MaybeUninit, slice};
22

33
use pinocchio::{
44
account_info::AccountInfo,
5-
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
5+
cpi::invoke_with_bounds,
6+
instruction::{AccountMeta, Instruction},
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};
11+
/// Maximum number of multisignature signers.
12+
pub const MAX_MULTISIG_SIGNERS: usize = 11;
1613

1714
/// Initialize a new Multisig.
1815
///
1916
/// ### Accounts:
2017
/// 0. `[writable]` The multisig account to initialize.
2118
/// 1. `[]` Rent sysvar
22-
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23-
/// 11`.
24-
pub struct InitializeMultisig<'a> {
19+
/// 2. ..`2+N`. `[]` The N signer accounts, where N is between 1 and 11.
20+
pub struct InitializeMultisig<'a, 'b>
21+
where
22+
'a: 'b,
23+
{
2524
/// Multisig Account.
2625
pub multisig: &'a AccountInfo,
2726
/// Rent sysvar Account.
2827
pub rent_sysvar: &'a AccountInfo,
2928
/// Signer Accounts
30-
pub multisig_signers: Vec<&'a AccountInfo>,
29+
pub multisig_signers: &'b [&'a AccountInfo],
3130
/// The number of signers (M) required to validate this multisignature
3231
/// account.
3332
pub m: u8,
3433
}
3534

36-
impl InitializeMultisig<'_> {
35+
impl InitializeMultisig<'_, '_> {
3736
#[inline(always)]
38-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
39-
self.invoke_signed::<ACCOUNTS>(&[])
40-
}
41-
42-
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
43-
if ACCOUNTS != self.multisig_signers.len() + 2 {
37+
pub fn invoke(&self) -> ProgramResult {
38+
let &Self {
39+
multisig,
40+
rent_sysvar,
41+
multisig_signers,
42+
m,
43+
} = self;
44+
45+
if multisig_signers.len() > MAX_MULTISIG_SIGNERS {
4446
return Err(ProgramError::InvalidArgument);
4547
}
4648

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

51-
account_metas.extend(
52-
self.multisig_signers
53-
.iter()
54-
.map(|a| AccountMeta::readonly(a.key())),
55-
);
67+
for (account_meta, signer) in acc_metas[2..].iter_mut().zip(multisig_signers.iter()) {
68+
account_meta.write(AccountMeta::readonly(signer.key()));
69+
}
5670

5771
// Instruction data layout:
5872
// - [0]: instruction discriminator (1 byte, u8)
5973
// - [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]);
74+
let data = &[2, m];
6675

6776
let instruction = Instruction {
6877
program_id: &crate::ID,
69-
accounts: account_metas.as_slice(),
70-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
78+
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
79+
data,
7180
};
7281

73-
let mut account_infos = Vec::with_capacity(2 + self.multisig_signers.len());
74-
75-
account_infos.push(self.multisig);
82+
// Account info array
83+
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
84+
let mut acc_infos = [UNINIT_INFO; 2 + MAX_MULTISIG_SIGNERS];
7685

77-
account_infos.extend_from_slice(self.multisig_signers.as_slice());
86+
unsafe {
87+
// SAFETY:
88+
// - `account_infos` is sized to 2 + MAX_MULTISIG_SIGNERS
89+
// - Index 0 and 1 are always present
90+
acc_infos.get_unchecked_mut(0).write(multisig);
91+
acc_infos.get_unchecked_mut(1).write(rent_sysvar);
92+
}
7893

79-
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
80-
.try_into()
81-
.map_err(|_| ProgramError::InvalidArgument)?;
94+
// Fill signer accounts
95+
for (account_info, signer) in acc_infos[2..].iter_mut().zip(multisig_signers.iter()) {
96+
account_info.write(signer);
97+
}
8298

83-
invoke_signed(&instruction, &account_infos, signers)
99+
invoke_with_bounds::<{ 2 + MAX_MULTISIG_SIGNERS }>(&instruction, unsafe {
100+
slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts)
101+
})
84102
}
85103
}
Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,94 @@
1-
use core::slice::from_raw_parts;
1+
use core::{mem::MaybeUninit, slice};
22

33
use pinocchio::{
44
account_info::AccountInfo,
5-
instruction::{AccountMeta, Instruction, Signer},
6-
program::invoke_signed,
5+
cpi::invoke_with_bounds,
6+
instruction::{AccountMeta, Instruction},
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};
11+
use crate::instructions::MAX_MULTISIG_SIGNERS;
1612

1713
/// Initialize a new Multisig.
1814
///
1915
/// ### Accounts:
2016
/// 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`.
24-
pub struct InitializeMultisig2<'a> {
17+
/// 1. ..`1+N`. `[]` The N signer accounts, where N is between 1 and 11.
18+
pub struct InitializeMultisig2<'a, 'b>
19+
where
20+
'a: 'b,
21+
{
2522
/// Multisig Account.
2623
pub multisig: &'a AccountInfo,
2724
/// Signer Accounts
28-
pub multisig_signers: Vec<&'a AccountInfo>,
25+
pub multisig_signers: &'b [&'a AccountInfo],
2926
/// The number of signers (M) required to validate this multisignature
3027
/// account.
3128
pub m: u8,
3229
}
3330

34-
impl InitializeMultisig2<'_> {
31+
impl InitializeMultisig2<'_, '_> {
3532
#[inline(always)]
36-
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
37-
self.invoke_signed::<ACCOUNTS>(&[])
38-
}
39-
40-
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
41-
if ACCOUNTS != self.multisig_signers.len() + 1 {
33+
pub fn invoke(&self) -> ProgramResult {
34+
let &Self {
35+
multisig,
36+
multisig_signers,
37+
m,
38+
} = self;
39+
40+
if multisig_signers.len() > MAX_MULTISIG_SIGNERS {
4241
return Err(ProgramError::InvalidArgument);
4342
}
4443

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

49-
account_metas.extend(
50-
self.multisig_signers
51-
.iter()
52-
.map(|a| AccountMeta::readonly(a.key())),
53-
);
59+
for (account_meta, signer) in acc_metas[1..].iter_mut().zip(multisig_signers.iter()) {
60+
account_meta.write(AccountMeta::readonly(signer.key()));
61+
}
5462

5563
// Instruction data layout:
5664
// - [0]: instruction discriminator (1 byte, u8)
5765
// - [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]);
66+
let data = &[19, m];
6467

6568
let instruction = Instruction {
6669
program_id: &crate::ID,
67-
accounts: account_metas.as_slice(),
68-
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
70+
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
71+
data,
6972
};
7073

71-
let mut account_infos = Vec::with_capacity(1 + self.multisig_signers.len());
72-
73-
account_infos.push(self.multisig);
74+
// Account info array
75+
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
76+
let mut acc_infos = [UNINIT_INFO; 1 + MAX_MULTISIG_SIGNERS];
7477

75-
account_infos.extend_from_slice(self.multisig_signers.as_slice());
78+
unsafe {
79+
// SAFETY:
80+
// - `account_infos` is sized to 1 + MAX_MULTISIG_SIGNERS
81+
// - Index 0 is always present
82+
acc_infos.get_unchecked_mut(0).write(multisig);
83+
}
7684

77-
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
78-
.try_into()
79-
.map_err(|_| ProgramError::InvalidArgument)?;
85+
// Fill signer accounts
86+
for (account_info, signer) in acc_infos[1..].iter_mut().zip(multisig_signers.iter()) {
87+
account_info.write(signer);
88+
}
8089

81-
invoke_signed(&instruction, &account_infos, signers)
90+
invoke_with_bounds::<{ 1 + MAX_MULTISIG_SIGNERS }>(&instruction, unsafe {
91+
slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts)
92+
})
8293
}
8394
}

0 commit comments

Comments
 (0)