use crate::models::instruction::Instruction;
use crate::models::{hash_base58::HashBase58, pubkey_base58::PubkeyBase58};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Message {
Legacy(MessageLegacy),
V0(MessageV0),
}
impl Message {
pub fn header(&self) -> &MessageHeader {
match self {
Message::Legacy(m) => &m.header,
Message::V0(m) => &m.header,
}
}
pub fn account_keys(&self) -> &Vec<PubkeyBase58> {
match self {
Message::Legacy(m) => &m.account_keys,
Message::V0(m) => &m.account_keys,
}
}
pub fn recent_blockhash(&self) -> &HashBase58 {
match self {
Message::Legacy(m) => &m.recent_blockhash,
Message::V0(m) => &m.recent_blockhash,
}
}
pub fn instructions(&self) -> &Vec<Instruction> {
match self {
Message::Legacy(m) => &m.instructions,
Message::V0(m) => &m.instructions,
}
}
pub fn account_keys_mut(&mut self) -> &mut Vec<PubkeyBase58> {
match self {
Message::Legacy(m) => &mut m.account_keys,
Message::V0(m) => &mut m.account_keys,
}
}
pub fn sanitize(&self) -> crate::errors::Result<()> {
match self {
Message::Legacy(m) => m.sanitize(),
Message::V0(m) => m.sanitize(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageLegacy {
pub header: MessageHeader,
#[serde(with = "solana_short_vec")]
pub account_keys: Vec<PubkeyBase58>,
pub recent_blockhash: HashBase58,
#[serde(with = "solana_short_vec")]
pub instructions: Vec<Instruction>,
}
impl MessageLegacy {
pub fn sanitize(&self) -> crate::errors::Result<()> {
if has_duplicates(&self.account_keys) {
return Err(crate::errors::ToolError::InvalidInput(
"Message contains duplicate account keys".into(),
));
}
Ok(())
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageV0 {
pub header: MessageHeader,
#[serde(with = "solana_short_vec")]
pub account_keys: Vec<PubkeyBase58>,
pub recent_blockhash: HashBase58,
#[serde(with = "solana_short_vec")]
pub instructions: Vec<Instruction>,
#[serde(with = "solana_short_vec")]
pub address_table_lookups: Vec<MessageAddressTableLookup>,
}
impl MessageV0 {
pub fn sanitize(&self) -> crate::errors::Result<()> {
if has_duplicates(&self.account_keys) {
return Err(crate::errors::ToolError::InvalidInput(
"Message contains duplicate account keys".into(),
));
}
Ok(())
}
}
fn has_duplicates(keys: &[PubkeyBase58]) -> bool {
for (i, k1) in keys.iter().enumerate() {
for k2 in keys.iter().skip(i + 1) {
if k1 == k2 {
return true;
}
}
}
false
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MessageAddressTableLookup {
pub account_key: PubkeyBase58,
#[serde(with = "solana_short_vec")]
pub writable_indexes: Vec<u8>,
#[serde(with = "solana_short_vec")]
pub readonly_indexes: Vec<u8>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MessageHeader {
#[serde(alias = "numRequiredSignatures")]
pub num_required_signatures: u8,
#[serde(alias = "numReadonlySignedAccounts")]
pub num_readonly_signed_accounts: u8,
#[serde(alias = "numReadonlyUnsignedAccounts")]
pub num_readonly_unsigned_accounts: u8,
}