Clean invoke in prep for native invoke (#14055)
This commit is contained in:
@ -490,6 +490,106 @@ impl MessageProcessor {
|
||||
Err(InstructionError::UnsupportedProgramId)
|
||||
}
|
||||
|
||||
/// Verify instruction against the caller
|
||||
pub fn verify_instruction(
|
||||
keyed_accounts: &[&KeyedAccount],
|
||||
instruction: &Instruction,
|
||||
signers: &[Pubkey],
|
||||
) -> Result<(), InstructionError> {
|
||||
// Check for privilege escalation
|
||||
for account in instruction.accounts.iter() {
|
||||
let keyed_account = keyed_accounts
|
||||
.iter()
|
||||
.find_map(|keyed_account| {
|
||||
if &account.pubkey == keyed_account.unsigned_key() {
|
||||
Some(keyed_account)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
// Readonly account cannot become writable
|
||||
if account.is_writable && !keyed_account.is_writable() {
|
||||
return Err(InstructionError::PrivilegeEscalation);
|
||||
}
|
||||
|
||||
if account.is_signer && // If message indicates account is signed
|
||||
!( // one of the following needs to be true:
|
||||
keyed_account.signer_key().is_some() // Signed in the parent instruction
|
||||
|| signers.contains(&account.pubkey) // Signed by the program
|
||||
) {
|
||||
return Err(InstructionError::PrivilegeEscalation);
|
||||
}
|
||||
}
|
||||
|
||||
// validate the caller has access to the program account
|
||||
let _ = keyed_accounts
|
||||
.iter()
|
||||
.find_map(|keyed_account| {
|
||||
if &instruction.program_id == keyed_account.unsigned_key() {
|
||||
Some(keyed_account)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_message(
|
||||
instruction: &Instruction,
|
||||
keyed_accounts: &[&KeyedAccount],
|
||||
signers: &[Pubkey],
|
||||
) -> Result<(Message, Pubkey, usize), InstructionError> {
|
||||
// Check for privilege escalation
|
||||
for account in instruction.accounts.iter() {
|
||||
let keyed_account = keyed_accounts
|
||||
.iter()
|
||||
.find_map(|keyed_account| {
|
||||
if &account.pubkey == keyed_account.unsigned_key() {
|
||||
Some(keyed_account)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
// Readonly account cannot become writable
|
||||
if account.is_writable && !keyed_account.is_writable() {
|
||||
return Err(InstructionError::PrivilegeEscalation);
|
||||
}
|
||||
|
||||
if account.is_signer && // If message indicates account is signed
|
||||
!( // one of the following needs to be true:
|
||||
keyed_account.signer_key().is_some() // Signed in the parent instruction
|
||||
|| signers.contains(&account.pubkey) // Signed by the program
|
||||
) {
|
||||
return Err(InstructionError::PrivilegeEscalation);
|
||||
}
|
||||
}
|
||||
|
||||
// validate the caller has access to the program account
|
||||
let _ = keyed_accounts
|
||||
.iter()
|
||||
.find_map(|keyed_account| {
|
||||
if &instruction.program_id == keyed_account.unsigned_key() {
|
||||
Some(keyed_account)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
|
||||
let message = Message::new(&[instruction.clone()], None);
|
||||
let id = *message
|
||||
.program_id(0)
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
let index = message
|
||||
.program_index(0)
|
||||
.ok_or(InstructionError::MissingAccount)?;
|
||||
Ok((message, id, index))
|
||||
}
|
||||
|
||||
/// Process a cross-program instruction
|
||||
/// This method calls the instruction's program entrypoint function
|
||||
pub fn process_cross_program_instruction(
|
||||
|
Reference in New Issue
Block a user