poseidon_client/transactions/
message.rs1use crate::{
2 CompiledInstruction, MessageBuilder, PoseidonError, PoseidonResult, PublicKey, RecentBlockHash,
3};
4use borsh::{BorshDeserialize, BorshSerialize};
5use core::fmt;
6use itertools::Itertools;
7use serde::{Deserialize, Serialize};
8
9#[derive(PartialEq, Eq, Clone, BorshSerialize, BorshDeserialize, Deserialize, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct Message {
12 pub header: MessageHeader,
15
16 #[serde(with = "short_vec")]
18 pub account_keys: Vec<PublicKey>,
19
20 pub recent_blockhash: RecentBlockHash,
22
23 #[serde(with = "short_vec")]
26 pub instructions: Vec<CompiledInstruction>,
27}
28
29impl Default for Message {
30 fn default() -> Self {
31 Message::new()
32 }
33}
34
35impl Message {
36 pub fn new() -> Self {
37 Self {
38 header: MessageHeader::default(),
39 account_keys: Vec::default(),
40 recent_blockhash: RecentBlockHash::default(),
41 instructions: Vec::default(),
42 }
43 }
44
45 pub fn add_recent_blockhash(&mut self, blockhash: RecentBlockHash) -> &mut Self {
46 self.recent_blockhash = blockhash;
47
48 self
49 }
50
51 pub fn build(&mut self, message_builder: MessageBuilder) -> PoseidonResult<&mut Self> {
52 let mut all_keys = message_builder.signed_keys;
53 let num_required_signatures = all_keys.len() as u8;
54 all_keys.extend(&message_builder.unsigned_keys);
55 self.header.num_required_signatures = num_required_signatures;
56 self.header.num_readonly_unsigned_accounts = message_builder.num_readonly_unsigned_accounts;
57 self.header.num_readonly_signed_accounts = message_builder.num_readonly_signed_accounts;
58 self.account_keys = all_keys.into_iter().unique().collect_vec();
59 message_builder
60 .instructions
61 .iter()
62 .try_for_each(|instruction| {
63 let program_id_index = match self
64 .account_keys
65 .iter()
66 .enumerate()
67 .find(|(_, account)| *account == &instruction.program_id)
68 {
69 Some((index, _)) => index as u8,
70 None => return Err(PoseidonError::ProgramIdNotFound),
71 };
72
73 let account_indexes = message_builder
75 .instructions
76 .iter()
77 .map(|instruction| {
78 instruction
79 .accounts
80 .iter()
81 .map(|account_meta| {
82 match self
83 .account_keys
84 .iter()
85 .enumerate()
86 .find(|(_, public_key)| *public_key == &account_meta.pubkey)
87 {
88 Some((index, _)) => Ok(index as u8),
89 None => Err(PoseidonError::PublicKeyNotFoundInMessageAccounts),
90 }
91 })
92 .collect::<Result<Vec<u8>, PoseidonError>>()
93 .map_err(|_| PoseidonError::AccountIndexNotFoundInMessageAccounts)
94 })
95 .collect::<Result<Vec<Vec<u8>>, PoseidonError>>()
96 .map_err(|_| PoseidonError::AccountIndexNotFoundInMessageAccounts)?;
97
98 let account_indexes: Vec<u8> = account_indexes.into_iter().flatten().collect();
99
100 self.instructions.push(CompiledInstruction {
101 program_id_index,
102 accounts: account_indexes,
103 data: instruction.data.clone(),
104 });
105
106 Ok(())
107 })?;
108
109 Ok(self)
110 }
111
112 pub fn to_bytes(&self) -> PoseidonResult<Vec<u8>> {
113 Ok(bincode::serialize(&self)?)
114 }
115}
116
117impl fmt::Debug for Message {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 let account_keys: Vec<String> = self
120 .account_keys
121 .iter()
122 .map(|account_key| bs58::encode(account_key).into_string())
123 .collect();
124 f.debug_struct("Message")
125 .field("header", &self.header)
126 .field("account_keys", &account_keys)
127 .field(
128 "recent_blockhash",
129 &bs58::encode(&self.recent_blockhash).into_string(),
130 )
131 .field("instructions", &self.instructions)
132 .finish()
133 }
134}
135
136#[derive(
137 Default,
138 Debug,
139 PartialEq,
140 Eq,
141 PartialOrd,
142 Ord,
143 Copy,
144 Clone,
145 Serialize,
146 Deserialize,
147 BorshSerialize,
148 BorshDeserialize,
149)]
150#[serde(rename_all = "camelCase")]
151pub struct MessageHeader {
152 pub num_required_signatures: u8,
156
157 pub num_readonly_signed_accounts: u8,
162
163 pub num_readonly_unsigned_accounts: u8,
165}