116 lines
5.1 KiB
Rust
116 lines
5.1 KiB
Rust
// file: crates/ksp-program-api/tests/external_implementation.rs
|
|
// version: 1
|
|
|
|
//! Downstream-style implementation canary for the open Program decoder contract.
|
|
|
|
const EXTERNAL_PROGRAM_ID_BYTES: [u8; 32] = [0xE7_u8; 32];
|
|
const FOREIGN_PROGRAM_ID_BYTES: [u8; 32] = [0xE8_u8; 32];
|
|
const SUPPORTED_OPCODE: u8 = 0x2A_u8;
|
|
|
|
struct ExternalDecodedInstruction {
|
|
opcode: u8,
|
|
}
|
|
|
|
struct ExternalProgramDecoder {
|
|
program_ids: [ksp_program_api::Pubkey; 1],
|
|
}
|
|
|
|
impl ExternalProgramDecoder {
|
|
fn new() -> Self {
|
|
return Self { program_ids: [ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES)] };
|
|
}
|
|
}
|
|
|
|
impl ksp_program_api::ProgramInstructionDecoder for ExternalProgramDecoder {
|
|
type Decoded = ExternalDecodedInstruction;
|
|
|
|
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
|
return &self.program_ids;
|
|
}
|
|
|
|
fn recognize(&self, instruction: &ksp_program_api::ProgramInstruction) -> ksp_program_api::ProgramInstructionRecognition {
|
|
if instruction.program_id() != &self.program_ids[0] {
|
|
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
|
}
|
|
if instruction.data().first() == std::option::Option::Some(&SUPPORTED_OPCODE) {
|
|
return ksp_program_api::ProgramInstructionRecognition::ExactMatch;
|
|
}
|
|
return ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
|
}
|
|
|
|
fn decode(
|
|
&self,
|
|
instruction: &ksp_program_api::ProgramInstruction,
|
|
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
|
if instruction.program_id() != &self.program_ids[0] {
|
|
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported);
|
|
}
|
|
let opcode = match instruction.data().first() {
|
|
std::option::Option::Some(value) if *value == SUPPORTED_OPCODE => *value,
|
|
_ => return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported),
|
|
};
|
|
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(ExternalDecodedInstruction { opcode }));
|
|
}
|
|
}
|
|
|
|
fn assert_send_sync<T: Send + Sync>(_value: &T) {
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_004_external_decoder_uses_unregistered_pubkey_and_implementation_owned_output() {
|
|
let decoder = ExternalProgramDecoder::new();
|
|
assert_send_sync(&decoder);
|
|
let external_program_id = ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES);
|
|
assert!(ksp_core_lib::find_program_pubkey(&external_program_id).is_none());
|
|
assert_eq!(ksp_program_api::ProgramInstructionDecoder::program_ids(&decoder), &[external_program_id]);
|
|
let exact = ksp_program_api::ProgramInstruction::try_new(external_program_id, std::vec![], std::vec![SUPPORTED_OPCODE]);
|
|
assert!(exact.is_ok());
|
|
let exact = match exact {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &exact), ksp_program_api::ProgramInstructionRecognition::ExactMatch);
|
|
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &exact);
|
|
assert!(outcome.is_ok());
|
|
let outcome = match outcome {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let decoded = match outcome {
|
|
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
|
_ => return,
|
|
};
|
|
assert_eq!(decoded.opcode, SUPPORTED_OPCODE);
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_004_external_decoder_distinguishes_program_match_unsupported_and_no_match() {
|
|
let decoder = ExternalProgramDecoder::new();
|
|
let external_program_id = ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES);
|
|
let program_only = ksp_program_api::ProgramInstruction::try_new(external_program_id, std::vec![], std::vec![0x11_u8]);
|
|
assert!(program_only.is_ok());
|
|
let program_only = match program_only {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &program_only), ksp_program_api::ProgramInstructionRecognition::ProgramMatch);
|
|
let unsupported = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &program_only);
|
|
assert!(unsupported.is_ok());
|
|
let unsupported = match unsupported {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert!(matches!(unsupported, ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported));
|
|
let foreign_program_id = ksp_program_api::Pubkey::new_from_array(FOREIGN_PROGRAM_ID_BYTES);
|
|
let foreign = ksp_program_api::ProgramInstruction::try_new(foreign_program_id, std::vec![], std::vec![SUPPORTED_OPCODE]);
|
|
assert!(foreign.is_ok());
|
|
let foreign = match foreign {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &foreign), ksp_program_api::ProgramInstructionRecognition::NoMatch);
|
|
return;
|
|
}
|