Clean invoke in prep for native invoke (#14055)

This commit is contained in:
Jack May
2020-12-10 18:25:57 -08:00
committed by GitHub
parent aa2751e614
commit 83fda2d972
2 changed files with 118 additions and 66 deletions

View File

@ -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(