2025-08-10 18:51:55 -03:00
|
|
|
use nssa_core::{
|
|
|
|
|
account::Nonce,
|
|
|
|
|
program::{InstructionData, ProgramId},
|
|
|
|
|
};
|
2025-08-10 14:10:11 -03:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
2025-08-11 12:07:30 -03:00
|
|
|
use crate::{Address, error::NssaError, program::Program};
|
2025-08-10 14:10:11 -03:00
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
|
|
|
pub struct Message {
|
|
|
|
|
pub(crate) program_id: ProgramId,
|
|
|
|
|
pub(crate) addresses: Vec<Address>,
|
|
|
|
|
pub(crate) nonces: Vec<Nonce>,
|
2025-08-10 18:51:55 -03:00
|
|
|
pub(crate) instruction_data: InstructionData,
|
2025-08-10 14:10:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Message {
|
2025-08-11 12:07:30 -03:00
|
|
|
pub fn try_new<T: Serialize>(
|
2025-08-10 14:10:11 -03:00
|
|
|
program_id: ProgramId,
|
|
|
|
|
addresses: Vec<Address>,
|
|
|
|
|
nonces: Vec<Nonce>,
|
2025-08-10 18:59:29 -03:00
|
|
|
instruction: T,
|
2025-08-11 12:07:30 -03:00
|
|
|
) -> Result<Self, NssaError> {
|
|
|
|
|
let instruction_data = Program::serialize_instruction(instruction)?;
|
|
|
|
|
Ok(Self {
|
2025-08-10 14:10:11 -03:00
|
|
|
program_id,
|
|
|
|
|
addresses,
|
|
|
|
|
nonces,
|
|
|
|
|
instruction_data,
|
2025-08-11 12:07:30 -03:00
|
|
|
})
|
2025-08-10 14:10:11 -03:00
|
|
|
}
|
2025-08-11 20:22:41 -03:00
|
|
|
|
|
|
|
|
/// Serializes a `Message` into bytes in the following layout:
|
|
|
|
|
/// TAG || <program_id> (bytes LE) * 8 || addresses_len (4 bytes LE) || addresses (32 bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes * M) || instruction_data_len || instruction_data (4 bytes * K)
|
|
|
|
|
/// Integers and words are encoded in little-endian byte order, and fields appear in the above order.
|
|
|
|
|
pub(crate) fn message_to_bytes(&self) -> Vec<u8> {
|
|
|
|
|
const MESSAGE_ENCODING_PREFIX: &[u8; 19] = b"NSSA/v0.1/TxMessage";
|
|
|
|
|
|
|
|
|
|
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
|
|
|
|
// program_id: [u32; 8]
|
|
|
|
|
for word in &self.program_id {
|
|
|
|
|
bytes.extend_from_slice(&word.to_le_bytes());
|
|
|
|
|
}
|
|
|
|
|
// addresses: Vec<[u8;32]>
|
|
|
|
|
// serialize length as u32 little endian, then all addresses concatenated
|
|
|
|
|
let addresses_len = self.addresses.len() as u32;
|
|
|
|
|
bytes.extend(&addresses_len.to_le_bytes());
|
|
|
|
|
for addr in &self.addresses {
|
|
|
|
|
bytes.extend_from_slice(addr.value());
|
|
|
|
|
}
|
|
|
|
|
// nonces: Vec<u128>
|
|
|
|
|
let nonces_len = self.nonces.len() as u32;
|
|
|
|
|
bytes.extend(&nonces_len.to_le_bytes());
|
|
|
|
|
for nonce in &self.nonces {
|
|
|
|
|
bytes.extend(&nonce.to_le_bytes());
|
|
|
|
|
}
|
|
|
|
|
// instruction_data: Vec<u32>
|
|
|
|
|
// serialize length as u32 little endian, then all addresses concatenated
|
|
|
|
|
let instr_len = self.instruction_data.len() as u32;
|
|
|
|
|
bytes.extend(&instr_len.to_le_bytes());
|
|
|
|
|
for word in &self.instruction_data {
|
|
|
|
|
bytes.extend(&word.to_le_bytes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytes
|
|
|
|
|
}
|
2025-08-10 14:10:11 -03:00
|
|
|
}
|