174 lines
5.2 KiB
Rust
174 lines
5.2 KiB
Rust
//! Program instructions
|
|
|
|
use crate::id;
|
|
use borsh::{BorshDeserialize, BorshSerialize};
|
|
use solana_program::{
|
|
instruction::{AccountMeta, Instruction},
|
|
pubkey::Pubkey,
|
|
};
|
|
|
|
/// Instructions supported by the program
|
|
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)]
|
|
pub enum RecordInstruction {
|
|
/// Create a new record
|
|
///
|
|
/// Accounts expected by this instruction:
|
|
///
|
|
/// 0. `[writable]` Record account, must be uninitialized
|
|
/// 1. `[]` Record authority
|
|
Initialize,
|
|
|
|
/// Write to the provided record account
|
|
///
|
|
/// Accounts expected by this instruction:
|
|
///
|
|
/// 0. `[writable]` Record account, must be previously initialized
|
|
/// 1. `[signer]` Current record authority
|
|
Write {
|
|
/// Offset to start writing record, expressed as `u64`.
|
|
offset: u64,
|
|
/// Data to replace the existing record data
|
|
data: Vec<u8>,
|
|
},
|
|
|
|
/// Update the authority of the provided record account
|
|
///
|
|
/// Accounts expected by this instruction:
|
|
///
|
|
/// 0. `[writable]` Record account, must be previously initialized
|
|
/// 1. `[signer]` Current record authority
|
|
/// 2. `[]` New record authority
|
|
SetAuthority,
|
|
|
|
/// Close the provided record account, draining lamports to recipient account
|
|
///
|
|
/// Accounts expected by this instruction:
|
|
///
|
|
/// 0. `[writable]` Record account, must be previously initialized
|
|
/// 1. `[signer]` Record authority
|
|
/// 2. `[]` Receiver of account lamports
|
|
CloseAccount,
|
|
}
|
|
|
|
/// Create a `RecordInstruction::Initialize` instruction
|
|
pub fn initialize(record_account: &Pubkey, authority: &Pubkey) -> Instruction {
|
|
Instruction::new_with_borsh(
|
|
id(),
|
|
&RecordInstruction::Initialize,
|
|
vec![
|
|
AccountMeta::new(*record_account, false),
|
|
AccountMeta::new_readonly(*authority, false),
|
|
],
|
|
)
|
|
}
|
|
|
|
/// Create a `RecordInstruction::Write` instruction
|
|
pub fn write(record_account: &Pubkey, signer: &Pubkey, offset: u64, data: Vec<u8>) -> Instruction {
|
|
Instruction::new_with_borsh(
|
|
id(),
|
|
&RecordInstruction::Write { offset, data },
|
|
vec![
|
|
AccountMeta::new(*record_account, false),
|
|
AccountMeta::new_readonly(*signer, true),
|
|
],
|
|
)
|
|
}
|
|
|
|
/// Create a `RecordInstruction::SetAuthority` instruction
|
|
pub fn set_authority(
|
|
record_account: &Pubkey,
|
|
signer: &Pubkey,
|
|
new_authority: &Pubkey,
|
|
) -> Instruction {
|
|
Instruction::new_with_borsh(
|
|
id(),
|
|
&RecordInstruction::SetAuthority,
|
|
vec![
|
|
AccountMeta::new(*record_account, false),
|
|
AccountMeta::new_readonly(*signer, true),
|
|
AccountMeta::new_readonly(*new_authority, false),
|
|
],
|
|
)
|
|
}
|
|
|
|
/// Create a `RecordInstruction::CloseAccount` instruction
|
|
pub fn close_account(record_account: &Pubkey, signer: &Pubkey, receiver: &Pubkey) -> Instruction {
|
|
Instruction::new_with_borsh(
|
|
id(),
|
|
&RecordInstruction::CloseAccount,
|
|
vec![
|
|
AccountMeta::new(*record_account, false),
|
|
AccountMeta::new_readonly(*signer, true),
|
|
AccountMeta::new(*receiver, false),
|
|
],
|
|
)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::state::tests::TEST_DATA;
|
|
use solana_program::program_error::ProgramError;
|
|
|
|
#[test]
|
|
fn serialize_initialize() {
|
|
let instruction = RecordInstruction::Initialize;
|
|
let expected = vec![0];
|
|
assert_eq!(instruction.try_to_vec().unwrap(), expected);
|
|
assert_eq!(
|
|
RecordInstruction::try_from_slice(&expected).unwrap(),
|
|
instruction
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_write() {
|
|
let data = TEST_DATA.try_to_vec().unwrap();
|
|
let offset = 0u64;
|
|
let instruction = RecordInstruction::Write {
|
|
offset: 0,
|
|
data: data.clone(),
|
|
};
|
|
let mut expected = vec![1];
|
|
expected.extend_from_slice(&offset.to_le_bytes());
|
|
expected.append(&mut data.try_to_vec().unwrap());
|
|
assert_eq!(instruction.try_to_vec().unwrap(), expected);
|
|
assert_eq!(
|
|
RecordInstruction::try_from_slice(&expected).unwrap(),
|
|
instruction
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_set_authority() {
|
|
let instruction = RecordInstruction::SetAuthority;
|
|
let expected = vec![2];
|
|
assert_eq!(instruction.try_to_vec().unwrap(), expected);
|
|
assert_eq!(
|
|
RecordInstruction::try_from_slice(&expected).unwrap(),
|
|
instruction
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_close_account() {
|
|
let instruction = RecordInstruction::CloseAccount;
|
|
let expected = vec![3];
|
|
assert_eq!(instruction.try_to_vec().unwrap(), expected);
|
|
assert_eq!(
|
|
RecordInstruction::try_from_slice(&expected).unwrap(),
|
|
instruction
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_invalid_instruction() {
|
|
let mut expected = vec![12];
|
|
expected.append(&mut TEST_DATA.try_to_vec().unwrap());
|
|
let err: ProgramError = RecordInstruction::try_from_slice(&expected)
|
|
.unwrap_err()
|
|
.into();
|
|
assert!(matches!(err, ProgramError::BorshIoError(_)));
|
|
}
|
|
}
|