solana_transaction/
lib.rs

1#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3//! Atomically-committed sequences of instructions.
4//!
5//! While [`Instruction`]s are the basic unit of computation in Solana, they are
6//! submitted by clients in [`Transaction`]s containing one or more
7//! instructions, and signed by one or more [`Signer`]s. Solana executes the
8//! instructions in a transaction in order, and only commits any changes if all
9//! instructions terminate without producing an error or exception.
10//!
11//! Transactions do not directly contain their instructions but instead include
12//! a [`Message`], a precompiled representation of a sequence of instructions.
13//! `Message`'s constructors handle the complex task of reordering the
14//! individual lists of accounts required by each instruction into a single flat
15//! list of deduplicated accounts required by the Solana runtime. The
16//! `Transaction` type has constructors that build the `Message` so that clients
17//! don't need to interact with them directly.
18//!
19//! Prior to submission to the network, transactions must be signed by one or
20//! more keypairs, and this signing is typically performed by an abstract
21//! [`Signer`], which may be a [`Keypair`] but may also be other types of
22//! signers including remote wallets, such as Ledger devices, as represented by
23//! the [`RemoteKeypair`] type in the [`solana-remote-wallet`] crate.
24//!
25//! [`Signer`]: https://docs.rs/solana-signer/latest/solana_signer/trait.Signer.html
26//! [`Keypair`]: https://docs.rs/solana-keypair/latest/solana_keypair/struct.Keypair.html
27//! [`solana-remote-wallet`]: https://docs.rs/solana-remote-wallet/latest/
28//! [`RemoteKeypair`]: https://docs.rs/solana-remote-wallet/latest/solana_remote_wallet/remote_keypair/struct.RemoteKeypair.html
29//!
30//! Every transaction must be signed by a fee-paying account, the account from
31//! which the cost of executing the transaction is withdrawn. Other required
32//! signatures are determined by the requirements of the programs being executed
33//! by each instruction, and are conventionally specified by that program's
34//! documentation.
35//!
36//! When signing a transaction, a recent blockhash must be provided (which can
37//! be retrieved with [`RpcClient::get_latest_blockhash`]). This allows
38//! validators to drop old but unexecuted transactions; and to distinguish
39//! between accidentally duplicated transactions and intentionally duplicated
40//! transactions — any identical transactions will not be executed more
41//! than once, so updating the blockhash between submitting otherwise identical
42//! transactions makes them unique. If a client must sign a transaction long
43//! before submitting it to the network, then it can use the _[durable
44//! transaction nonce]_ mechanism instead of a recent blockhash to ensure unique
45//! transactions.
46//!
47//! [`RpcClient::get_latest_blockhash`]: https://docs.rs/solana-rpc-client/latest/solana_rpc_client/rpc_client/struct.RpcClient.html#method.get_latest_blockhash
48//! [durable transaction nonce]: https://docs.solanalabs.com/implemented-proposals/durable-tx-nonces
49//!
50//! # Examples
51//!
52//! This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
53//!
54//! [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
55//! [`anyhow`]: https://docs.rs/anyhow
56//!
57//! ```
58//! # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
59//! use anyhow::Result;
60//! use borsh::{BorshSerialize, BorshDeserialize};
61//! use solana_instruction::Instruction;
62//! use solana_keypair::Keypair;
63//! use solana_message::Message;
64//! use solana_pubkey::Pubkey;
65//! use solana_rpc_client::rpc_client::RpcClient;
66//! use solana_signer::Signer;
67//! use solana_transaction::Transaction;
68//!
69//! // A custom program instruction. This would typically be defined in
70//! // another crate so it can be shared between the on-chain program and
71//! // the client.
72//! #[derive(BorshSerialize, BorshDeserialize)]
73//! enum BankInstruction {
74//!     Initialize,
75//!     Deposit { lamports: u64 },
76//!     Withdraw { lamports: u64 },
77//! }
78//!
79//! fn send_initialize_tx(
80//!     client: &RpcClient,
81//!     program_id: Pubkey,
82//!     payer: &Keypair
83//! ) -> Result<()> {
84//!
85//!     let bank_instruction = BankInstruction::Initialize;
86//!
87//!     let instruction = Instruction::new_with_borsh(
88//!         program_id,
89//!         &bank_instruction,
90//!         vec![],
91//!     );
92//!
93//!     let blockhash = client.get_latest_blockhash()?;
94//!     let mut tx = Transaction::new_signed_with_payer(
95//!         &[instruction],
96//!         Some(&payer.pubkey()),
97//!         &[payer],
98//!         blockhash,
99//!     );
100//!     client.send_and_confirm_transaction(&tx)?;
101//!
102//!     Ok(())
103//! }
104//! #
105//! # let client = RpcClient::new(String::new());
106//! # let program_id = Pubkey::new_unique();
107//! # let payer = Keypair::new();
108//! # send_initialize_tx(&client, program_id, &payer)?;
109//! #
110//! # Ok::<(), anyhow::Error>(())
111//! ```
112
113#[cfg(feature = "serde")]
114use {
115    serde_derive::{Deserialize, Serialize},
116    solana_short_vec as short_vec,
117};
118pub use {
119    solana_address::Address,
120    solana_instruction::{AccountMeta, Instruction},
121    solana_instruction_error::InstructionError,
122    solana_message::{compiled_instruction::CompiledInstruction, Message, VersionedMessage},
123    solana_signature::Signature,
124    solana_transaction_error::{TransactionError, TransactionResult},
125};
126#[cfg(feature = "bincode")]
127pub use {
128    solana_hash::Hash,
129    solana_signer::{signers::Signers, SignerError},
130};
131use {
132    solana_message::inline_nonce::is_advance_nonce_instruction_data,
133    solana_sanitize::{Sanitize, SanitizeError},
134    solana_sdk_ids::system_program,
135    std::result,
136};
137
138pub mod sanitized;
139pub mod simple_vote_transaction_checker;
140pub mod versioned;
141
142#[derive(PartialEq, Eq, Clone, Copy, Debug)]
143pub enum TransactionVerificationMode {
144    HashOnly,
145    HashAndVerifyPrecompiles,
146    FullVerification,
147}
148
149// inlined to avoid solana-nonce dep
150#[cfg(test)]
151static_assertions::const_assert_eq!(
152    NONCED_TX_MARKER_IX_INDEX,
153    solana_nonce::NONCED_TX_MARKER_IX_INDEX
154);
155const NONCED_TX_MARKER_IX_INDEX: u8 = 0;
156
157/// An atomically-committed sequence of instructions.
158///
159/// While [`Instruction`]s are the basic unit of computation in Solana,
160/// they are submitted by clients in [`Transaction`]s containing one or
161/// more instructions, and signed by one or more [`Signer`]s.
162///
163/// [`Signer`]: https://docs.rs/solana-signer/latest/solana_signer/trait.Signer.html
164///
165/// See the [module documentation] for more details about transactions.
166///
167/// [module documentation]: self
168///
169/// Some constructors accept an optional `payer`, the account responsible for
170/// paying the cost of executing a transaction. In most cases, callers should
171/// specify the payer explicitly in these constructors. In some cases though,
172/// the caller is not _required_ to specify the payer, but is still allowed to:
173/// in the [`Message`] structure, the first account is always the fee-payer, so
174/// if the caller has knowledge that the first account of the constructed
175/// transaction's `Message` is both a signer and the expected fee-payer, then
176/// redundantly specifying the fee-payer is not strictly required.
177#[cfg_attr(
178    feature = "frozen-abi",
179    derive(solana_frozen_abi_macro::AbiExample),
180    solana_frozen_abi_macro::frozen_abi(digest = "BLig4G2ysd7dcensK9bhKtnKvCQc1n65XdanyzsdWGXN")
181)]
182#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
183#[derive(Debug, PartialEq, Default, Eq, Clone)]
184pub struct Transaction {
185    /// A set of signatures of a serialized [`Message`], signed by the first
186    /// keys of the `Message`'s [`account_keys`], where the number of signatures
187    /// is equal to [`num_required_signatures`] of the `Message`'s
188    /// [`MessageHeader`].
189    ///
190    /// [`account_keys`]: https://docs.rs/solana-message/latest/solana_message/legacy/struct.Message.html#structfield.account_keys
191    /// [`MessageHeader`]: https://docs.rs/solana-message/latest/solana_message/struct.MessageHeader.html
192    /// [`num_required_signatures`]: https://docs.rs/solana-message/latest/solana_message/struct.MessageHeader.html#structfield.num_required_signatures
193    // NOTE: Serialization-related changes must be paired with the direct read at sigverify.
194    #[cfg_attr(feature = "serde", serde(with = "short_vec"))]
195    pub signatures: Vec<Signature>,
196
197    /// The message to sign.
198    pub message: Message,
199}
200
201impl Sanitize for Transaction {
202    fn sanitize(&self) -> result::Result<(), SanitizeError> {
203        if self.message.header.num_required_signatures as usize > self.signatures.len() {
204            return Err(SanitizeError::IndexOutOfBounds);
205        }
206        if self.signatures.len() > self.message.account_keys.len() {
207            return Err(SanitizeError::IndexOutOfBounds);
208        }
209        self.message.sanitize()
210    }
211}
212
213impl Transaction {
214    /// Create an unsigned transaction from a [`Message`].
215    ///
216    /// # Examples
217    ///
218    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
219    ///
220    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
221    /// [`anyhow`]: https://docs.rs/anyhow
222    ///
223    /// ```
224    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
225    /// use anyhow::Result;
226    /// use borsh::{BorshSerialize, BorshDeserialize};
227    /// use solana_instruction::Instruction;
228    /// use solana_keypair::Keypair;
229    /// use solana_message::Message;
230    /// use solana_pubkey::Pubkey;
231    /// use solana_rpc_client::rpc_client::RpcClient;
232    /// use solana_signer::Signer;
233    /// use solana_transaction::Transaction;
234    ///
235    /// // A custom program instruction. This would typically be defined in
236    /// // another crate so it can be shared between the on-chain program and
237    /// // the client.
238    /// #[derive(BorshSerialize, BorshDeserialize)]
239    /// enum BankInstruction {
240    ///     Initialize,
241    ///     Deposit { lamports: u64 },
242    ///     Withdraw { lamports: u64 },
243    /// }
244    ///
245    /// fn send_initialize_tx(
246    ///     client: &RpcClient,
247    ///     program_id: Pubkey,
248    ///     payer: &Keypair
249    /// ) -> Result<()> {
250    ///
251    ///     let bank_instruction = BankInstruction::Initialize;
252    ///
253    ///     let instruction = Instruction::new_with_borsh(
254    ///         program_id,
255    ///         &bank_instruction,
256    ///         vec![],
257    ///     );
258    ///
259    ///     let message = Message::new(
260    ///         &[instruction],
261    ///         Some(&payer.pubkey()),
262    ///     );
263    ///
264    ///     let mut tx = Transaction::new_unsigned(message);
265    ///     let blockhash = client.get_latest_blockhash()?;
266    ///     tx.sign(&[payer], blockhash);
267    ///     client.send_and_confirm_transaction(&tx)?;
268    ///
269    ///     Ok(())
270    /// }
271    /// #
272    /// # let client = RpcClient::new(String::new());
273    /// # let program_id = Pubkey::new_unique();
274    /// # let payer = Keypair::new();
275    /// # send_initialize_tx(&client, program_id, &payer)?;
276    /// #
277    /// # Ok::<(), anyhow::Error>(())
278    /// ```
279    pub fn new_unsigned(message: Message) -> Self {
280        Self {
281            signatures: vec![Signature::default(); message.header.num_required_signatures as usize],
282            message,
283        }
284    }
285
286    /// Create a fully-signed transaction from a [`Message`].
287    ///
288    /// # Panics
289    ///
290    /// Panics when signing fails. See [`Transaction::try_sign`] and
291    /// [`Transaction::try_partial_sign`] for a full description of failure
292    /// scenarios.
293    ///
294    /// # Examples
295    ///
296    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
297    ///
298    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
299    /// [`anyhow`]: https://docs.rs/anyhow
300    ///
301    /// ```
302    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
303    /// use anyhow::Result;
304    /// use borsh::{BorshSerialize, BorshDeserialize};
305    /// use solana_instruction::Instruction;
306    /// use solana_keypair::Keypair;
307    /// use solana_message::Message;
308    /// use solana_pubkey::Pubkey;
309    /// use solana_rpc_client::rpc_client::RpcClient;
310    /// use solana_signer::Signer;
311    /// use solana_transaction::Transaction;
312    ///
313    /// // A custom program instruction. This would typically be defined in
314    /// // another crate so it can be shared between the on-chain program and
315    /// // the client.
316    /// #[derive(BorshSerialize, BorshDeserialize)]
317    /// enum BankInstruction {
318    ///     Initialize,
319    ///     Deposit { lamports: u64 },
320    ///     Withdraw { lamports: u64 },
321    /// }
322    ///
323    /// fn send_initialize_tx(
324    ///     client: &RpcClient,
325    ///     program_id: Pubkey,
326    ///     payer: &Keypair
327    /// ) -> Result<()> {
328    ///
329    ///     let bank_instruction = BankInstruction::Initialize;
330    ///
331    ///     let instruction = Instruction::new_with_borsh(
332    ///         program_id,
333    ///         &bank_instruction,
334    ///         vec![],
335    ///     );
336    ///
337    ///     let message = Message::new(
338    ///         &[instruction],
339    ///         Some(&payer.pubkey()),
340    ///     );
341    ///
342    ///     let blockhash = client.get_latest_blockhash()?;
343    ///     let mut tx = Transaction::new(&[payer], message, blockhash);
344    ///     client.send_and_confirm_transaction(&tx)?;
345    ///
346    ///     Ok(())
347    /// }
348    /// #
349    /// # let client = RpcClient::new(String::new());
350    /// # let program_id = Pubkey::new_unique();
351    /// # let payer = Keypair::new();
352    /// # send_initialize_tx(&client, program_id, &payer)?;
353    /// #
354    /// # Ok::<(), anyhow::Error>(())
355    /// ```
356    #[cfg(feature = "bincode")]
357    pub fn new<T: Signers + ?Sized>(
358        from_keypairs: &T,
359        message: Message,
360        recent_blockhash: Hash,
361    ) -> Transaction {
362        let mut tx = Self::new_unsigned(message);
363        tx.sign(from_keypairs, recent_blockhash);
364        tx
365    }
366
367    /// Create an unsigned transaction from a list of [`Instruction`]s.
368    ///
369    /// `payer` is the account responsible for paying the cost of executing the
370    /// transaction. It is typically provided, but is optional in some cases.
371    /// See the [`Transaction`] docs for more.
372    ///
373    /// # Examples
374    ///
375    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
376    ///
377    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
378    /// [`anyhow`]: https://docs.rs/anyhow
379    ///
380    /// ```
381    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
382    /// use anyhow::Result;
383    /// use borsh::{BorshSerialize, BorshDeserialize};
384    /// use solana_instruction::Instruction;
385    /// use solana_keypair::Keypair;
386    /// use solana_message::Message;
387    /// use solana_pubkey::Pubkey;
388    /// use solana_rpc_client::rpc_client::RpcClient;
389    /// use solana_signer::Signer;
390    /// use solana_transaction::Transaction;
391    ///
392    /// // A custom program instruction. This would typically be defined in
393    /// // another crate so it can be shared between the on-chain program and
394    /// // the client.
395    /// #[derive(BorshSerialize, BorshDeserialize)]
396    /// enum BankInstruction {
397    ///     Initialize,
398    ///     Deposit { lamports: u64 },
399    ///     Withdraw { lamports: u64 },
400    /// }
401    ///
402    /// fn send_initialize_tx(
403    ///     client: &RpcClient,
404    ///     program_id: Pubkey,
405    ///     payer: &Keypair
406    /// ) -> Result<()> {
407    ///
408    ///     let bank_instruction = BankInstruction::Initialize;
409    ///
410    ///     let instruction = Instruction::new_with_borsh(
411    ///         program_id,
412    ///         &bank_instruction,
413    ///         vec![],
414    ///     );
415    ///
416    ///     let mut tx = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
417    ///     let blockhash = client.get_latest_blockhash()?;
418    ///     tx.sign(&[payer], blockhash);
419    ///     client.send_and_confirm_transaction(&tx)?;
420    ///
421    ///     Ok(())
422    /// }
423    /// #
424    /// # let client = RpcClient::new(String::new());
425    /// # let program_id = Pubkey::new_unique();
426    /// # let payer = Keypair::new();
427    /// # send_initialize_tx(&client, program_id, &payer)?;
428    /// #
429    /// # Ok::<(), anyhow::Error>(())
430    /// ```
431    pub fn new_with_payer(instructions: &[Instruction], payer: Option<&Address>) -> Self {
432        let message = Message::new(instructions, payer);
433        Self::new_unsigned(message)
434    }
435
436    /// Create a fully-signed transaction from a list of [`Instruction`]s.
437    ///
438    /// `payer` is the account responsible for paying the cost of executing the
439    /// transaction. It is typically provided, but is optional in some cases.
440    /// See the [`Transaction`] docs for more.
441    ///
442    /// # Panics
443    ///
444    /// Panics when signing fails. See [`Transaction::try_sign`] and
445    /// [`Transaction::try_partial_sign`] for a full description of failure
446    /// scenarios.
447    ///
448    /// # Examples
449    ///
450    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
451    ///
452    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
453    /// [`anyhow`]: https://docs.rs/anyhow
454    ///
455    /// ```
456    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
457    /// use anyhow::Result;
458    /// use borsh::{BorshSerialize, BorshDeserialize};
459    /// use solana_instruction::Instruction;
460    /// use solana_keypair::Keypair;
461    /// use solana_message::Message;
462    /// use solana_pubkey::Pubkey;
463    /// use solana_rpc_client::rpc_client::RpcClient;
464    /// use solana_signer::Signer;
465    /// use solana_transaction::Transaction;
466    ///
467    /// // A custom program instruction. This would typically be defined in
468    /// // another crate so it can be shared between the on-chain program and
469    /// // the client.
470    /// #[derive(BorshSerialize, BorshDeserialize)]
471    /// enum BankInstruction {
472    ///     Initialize,
473    ///     Deposit { lamports: u64 },
474    ///     Withdraw { lamports: u64 },
475    /// }
476    ///
477    /// fn send_initialize_tx(
478    ///     client: &RpcClient,
479    ///     program_id: Pubkey,
480    ///     payer: &Keypair
481    /// ) -> Result<()> {
482    ///
483    ///     let bank_instruction = BankInstruction::Initialize;
484    ///
485    ///     let instruction = Instruction::new_with_borsh(
486    ///         program_id,
487    ///         &bank_instruction,
488    ///         vec![],
489    ///     );
490    ///
491    ///     let blockhash = client.get_latest_blockhash()?;
492    ///     let mut tx = Transaction::new_signed_with_payer(
493    ///         &[instruction],
494    ///         Some(&payer.pubkey()),
495    ///         &[payer],
496    ///         blockhash,
497    ///     );
498    ///     client.send_and_confirm_transaction(&tx)?;
499    ///
500    ///     Ok(())
501    /// }
502    /// #
503    /// # let client = RpcClient::new(String::new());
504    /// # let program_id = Pubkey::new_unique();
505    /// # let payer = Keypair::new();
506    /// # send_initialize_tx(&client, program_id, &payer)?;
507    /// #
508    /// # Ok::<(), anyhow::Error>(())
509    /// ```
510    #[cfg(feature = "bincode")]
511    pub fn new_signed_with_payer<T: Signers + ?Sized>(
512        instructions: &[Instruction],
513        payer: Option<&Address>,
514        signing_keypairs: &T,
515        recent_blockhash: Hash,
516    ) -> Self {
517        let message = Message::new(instructions, payer);
518        Self::new(signing_keypairs, message, recent_blockhash)
519    }
520
521    /// Create a fully-signed transaction from pre-compiled instructions.
522    ///
523    /// # Arguments
524    ///
525    /// * `from_keypairs` - The keys used to sign the transaction.
526    /// * `keys` - The keys for the transaction.  These are the program state
527    ///   instances or lamport recipient keys.
528    /// * `recent_blockhash` - The PoH hash.
529    /// * `program_ids` - The keys that identify programs used in the `instruction` vector.
530    /// * `instructions` - Instructions that will be executed atomically.
531    ///
532    /// # Panics
533    ///
534    /// Panics when signing fails. See [`Transaction::try_sign`] and for a full
535    /// description of failure conditions.
536    #[cfg(feature = "bincode")]
537    pub fn new_with_compiled_instructions<T: Signers + ?Sized>(
538        from_keypairs: &T,
539        keys: &[Address],
540        recent_blockhash: Hash,
541        program_ids: Vec<Address>,
542        instructions: Vec<CompiledInstruction>,
543    ) -> Self {
544        let mut account_keys = from_keypairs.pubkeys();
545        let from_keypairs_len = account_keys.len();
546        account_keys.extend_from_slice(keys);
547        account_keys.extend(&program_ids);
548        let message = Message::new_with_compiled_instructions(
549            from_keypairs_len as u8,
550            0,
551            program_ids.len() as u8,
552            account_keys,
553            Hash::default(),
554            instructions,
555        );
556        Transaction::new(from_keypairs, message, recent_blockhash)
557    }
558
559    /// Get the data for an instruction at the given index.
560    ///
561    /// The `instruction_index` corresponds to the [`instructions`] vector of
562    /// the `Transaction`'s [`Message`] value.
563    ///
564    /// [`instructions`]: Message::instructions
565    ///
566    /// # Panics
567    ///
568    /// Panics if `instruction_index` is greater than or equal to the number of
569    /// instructions in the transaction.
570    pub fn data(&self, instruction_index: usize) -> &[u8] {
571        &self.message.instructions[instruction_index].data
572    }
573
574    fn key_index(&self, instruction_index: usize, accounts_index: usize) -> Option<usize> {
575        self.message
576            .instructions
577            .get(instruction_index)
578            .and_then(|instruction| instruction.accounts.get(accounts_index))
579            .map(|&account_keys_index| account_keys_index as usize)
580    }
581
582    /// Get the `Pubkey` of an account required by one of the instructions in
583    /// the transaction.
584    ///
585    /// The `instruction_index` corresponds to the [`instructions`] vector of
586    /// the `Transaction`'s [`Message`] value; and the `account_index` to the
587    /// [`accounts`] vector of the message's [`CompiledInstruction`]s.
588    ///
589    /// [`instructions`]: Message::instructions
590    /// [`accounts`]: CompiledInstruction::accounts
591    /// [`CompiledInstruction`]: CompiledInstruction
592    ///
593    /// Returns `None` if `instruction_index` is greater than or equal to the
594    /// number of instructions in the transaction; or if `accounts_index` is
595    /// greater than or equal to the number of accounts in the instruction.
596    pub fn key(&self, instruction_index: usize, accounts_index: usize) -> Option<&Address> {
597        self.key_index(instruction_index, accounts_index)
598            .and_then(|account_keys_index| self.message.account_keys.get(account_keys_index))
599    }
600
601    /// Get the `Pubkey` of a signing account required by one of the
602    /// instructions in the transaction.
603    ///
604    /// The transaction does not need to be signed for this function to return a
605    /// signing account's pubkey.
606    ///
607    /// Returns `None` if the indexed account is not required to sign the
608    /// transaction. Returns `None` if the [`signatures`] field does not contain
609    /// enough elements to hold a signature for the indexed account (this should
610    /// only be possible if `Transaction` has been manually constructed).
611    ///
612    /// [`signatures`]: Transaction::signatures
613    ///
614    /// Returns `None` if `instruction_index` is greater than or equal to the
615    /// number of instructions in the transaction; or if `accounts_index` is
616    /// greater than or equal to the number of accounts in the instruction.
617    pub fn signer_key(&self, instruction_index: usize, accounts_index: usize) -> Option<&Address> {
618        match self.key_index(instruction_index, accounts_index) {
619            None => None,
620            Some(signature_index) => {
621                if signature_index >= self.signatures.len() {
622                    return None;
623                }
624                self.message.account_keys.get(signature_index)
625            }
626        }
627    }
628
629    /// Return the message containing all data that should be signed.
630    pub fn message(&self) -> &Message {
631        &self.message
632    }
633
634    #[cfg(feature = "bincode")]
635    /// Return the serialized message data to sign.
636    pub fn message_data(&self) -> Vec<u8> {
637        self.message().serialize()
638    }
639
640    /// Sign the transaction.
641    ///
642    /// This method fully signs a transaction with all required signers, which
643    /// must be present in the `keypairs` slice. To sign with only some of the
644    /// required signers, use [`Transaction::partial_sign`].
645    ///
646    /// If `recent_blockhash` is different than recorded in the transaction message's
647    /// [`recent_blockhash`] field, then the message's `recent_blockhash` will be updated
648    /// to the provided `recent_blockhash`, and any prior signatures will be cleared.
649    ///
650    /// [`recent_blockhash`]: Message::recent_blockhash
651    ///
652    /// # Panics
653    ///
654    /// Panics when signing fails. Use [`Transaction::try_sign`] to handle the
655    /// error. See the documentation for [`Transaction::try_sign`] for a full description of
656    /// failure conditions.
657    ///
658    /// # Examples
659    ///
660    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
661    ///
662    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
663    /// [`anyhow`]: https://docs.rs/anyhow
664    ///
665    /// ```
666    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
667    /// use anyhow::Result;
668    /// use borsh::{BorshSerialize, BorshDeserialize};
669    /// use solana_instruction::Instruction;
670    /// use solana_keypair::Keypair;
671    /// use solana_message::Message;
672    /// use solana_pubkey::Pubkey;
673    /// use solana_rpc_client::rpc_client::RpcClient;
674    /// use solana_signer::Signer;
675    /// use solana_transaction::Transaction;
676    ///
677    /// // A custom program instruction. This would typically be defined in
678    /// // another crate so it can be shared between the on-chain program and
679    /// // the client.
680    /// #[derive(BorshSerialize, BorshDeserialize)]
681    /// enum BankInstruction {
682    ///     Initialize,
683    ///     Deposit { lamports: u64 },
684    ///     Withdraw { lamports: u64 },
685    /// }
686    ///
687    /// fn send_initialize_tx(
688    ///     client: &RpcClient,
689    ///     program_id: Pubkey,
690    ///     payer: &Keypair
691    /// ) -> Result<()> {
692    ///
693    ///     let bank_instruction = BankInstruction::Initialize;
694    ///
695    ///     let instruction = Instruction::new_with_borsh(
696    ///         program_id,
697    ///         &bank_instruction,
698    ///         vec![],
699    ///     );
700    ///
701    ///     let mut tx = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
702    ///     let blockhash = client.get_latest_blockhash()?;
703    ///     tx.sign(&[payer], blockhash);
704    ///     client.send_and_confirm_transaction(&tx)?;
705    ///
706    ///     Ok(())
707    /// }
708    /// #
709    /// # let client = RpcClient::new(String::new());
710    /// # let program_id = Pubkey::new_unique();
711    /// # let payer = Keypair::new();
712    /// # send_initialize_tx(&client, program_id, &payer)?;
713    /// #
714    /// # Ok::<(), anyhow::Error>(())
715    /// ```
716    #[cfg(feature = "bincode")]
717    pub fn sign<T: Signers + ?Sized>(&mut self, keypairs: &T, recent_blockhash: Hash) {
718        if let Err(e) = self.try_sign(keypairs, recent_blockhash) {
719            panic!("Transaction::sign failed with error {e:?}");
720        }
721    }
722
723    /// Sign the transaction with a subset of required keys.
724    ///
725    /// Unlike [`Transaction::sign`], this method does not require all keypairs
726    /// to be provided, allowing a transaction to be signed in multiple steps.
727    ///
728    /// It is permitted to sign a transaction with the same keypair multiple
729    /// times.
730    ///
731    /// If `recent_blockhash` is different than recorded in the transaction message's
732    /// [`recent_blockhash`] field, then the message's `recent_blockhash` will be updated
733    /// to the provided `recent_blockhash`, and any prior signatures will be cleared.
734    ///
735    /// [`recent_blockhash`]: Message::recent_blockhash
736    ///
737    /// # Panics
738    ///
739    /// Panics when signing fails. Use [`Transaction::try_partial_sign`] to
740    /// handle the error. See the documentation for
741    /// [`Transaction::try_partial_sign`] for a full description of failure
742    /// conditions.
743    #[cfg(feature = "bincode")]
744    pub fn partial_sign<T: Signers + ?Sized>(&mut self, keypairs: &T, recent_blockhash: Hash) {
745        if let Err(e) = self.try_partial_sign(keypairs, recent_blockhash) {
746            panic!("Transaction::partial_sign failed with error {e:?}");
747        }
748    }
749
750    /// Sign the transaction with a subset of required keys.
751    ///
752    /// This places each of the signatures created from `keypairs` in the
753    /// corresponding position, as specified in the `positions` vector, in the
754    /// transactions [`signatures`] field. It does not verify that the signature
755    /// positions are correct.
756    ///
757    /// [`signatures`]: Transaction::signatures
758    ///
759    /// # Panics
760    ///
761    /// Panics if signing fails. Use [`Transaction::try_partial_sign_unchecked`]
762    /// to handle the error.
763    #[cfg(feature = "bincode")]
764    pub fn partial_sign_unchecked<T: Signers + ?Sized>(
765        &mut self,
766        keypairs: &T,
767        positions: Vec<usize>,
768        recent_blockhash: Hash,
769    ) {
770        if let Err(e) = self.try_partial_sign_unchecked(keypairs, positions, recent_blockhash) {
771            panic!("Transaction::partial_sign_unchecked failed with error {e:?}");
772        }
773    }
774
775    /// Sign the transaction, returning any errors.
776    ///
777    /// This method fully signs a transaction with all required signers, which
778    /// must be present in the `keypairs` slice. To sign with only some of the
779    /// required signers, use [`Transaction::try_partial_sign`].
780    ///
781    /// If `recent_blockhash` is different than recorded in the transaction message's
782    /// [`recent_blockhash`] field, then the message's `recent_blockhash` will be updated
783    /// to the provided `recent_blockhash`, and any prior signatures will be cleared.
784    ///
785    /// [`recent_blockhash`]: Message::recent_blockhash
786    ///
787    /// # Errors
788    ///
789    /// Signing will fail if some required signers are not provided in
790    /// `keypairs`; or, if the transaction has previously been partially signed,
791    /// some of the remaining required signers are not provided in `keypairs`.
792    /// In other words, the transaction must be fully signed as a result of
793    /// calling this function. The error is [`SignerError::NotEnoughSigners`].
794    ///
795    /// Signing will fail for any of the reasons described in the documentation
796    /// for [`Transaction::try_partial_sign`].
797    ///
798    /// # Examples
799    ///
800    /// This example uses the [`solana_rpc_client`] and [`anyhow`] crates.
801    ///
802    /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client
803    /// [`anyhow`]: https://docs.rs/anyhow
804    ///
805    /// ```
806    /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction};
807    /// use anyhow::Result;
808    /// use borsh::{BorshSerialize, BorshDeserialize};
809    /// use solana_instruction::Instruction;
810    /// use solana_keypair::Keypair;
811    /// use solana_message::Message;
812    /// use solana_pubkey::Pubkey;
813    /// use solana_rpc_client::rpc_client::RpcClient;
814    /// use solana_signer::Signer;
815    /// use solana_transaction::Transaction;
816    ///
817    /// // A custom program instruction. This would typically be defined in
818    /// // another crate so it can be shared between the on-chain program and
819    /// // the client.
820    /// #[derive(BorshSerialize, BorshDeserialize)]
821    /// enum BankInstruction {
822    ///     Initialize,
823    ///     Deposit { lamports: u64 },
824    ///     Withdraw { lamports: u64 },
825    /// }
826    ///
827    /// fn send_initialize_tx(
828    ///     client: &RpcClient,
829    ///     program_id: Pubkey,
830    ///     payer: &Keypair
831    /// ) -> Result<()> {
832    ///
833    ///     let bank_instruction = BankInstruction::Initialize;
834    ///
835    ///     let instruction = Instruction::new_with_borsh(
836    ///         program_id,
837    ///         &bank_instruction,
838    ///         vec![],
839    ///     );
840    ///
841    ///     let mut tx = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
842    ///     let blockhash = client.get_latest_blockhash()?;
843    ///     tx.try_sign(&[payer], blockhash)?;
844    ///     client.send_and_confirm_transaction(&tx)?;
845    ///
846    ///     Ok(())
847    /// }
848    /// #
849    /// # let client = RpcClient::new(String::new());
850    /// # let program_id = Pubkey::new_unique();
851    /// # let payer = Keypair::new();
852    /// # send_initialize_tx(&client, program_id, &payer)?;
853    /// #
854    /// # Ok::<(), anyhow::Error>(())
855    /// ```
856    #[cfg(feature = "bincode")]
857    pub fn try_sign<T: Signers + ?Sized>(
858        &mut self,
859        keypairs: &T,
860        recent_blockhash: Hash,
861    ) -> result::Result<(), SignerError> {
862        self.try_partial_sign(keypairs, recent_blockhash)?;
863
864        if !self.is_signed() {
865            Err(SignerError::NotEnoughSigners)
866        } else {
867            Ok(())
868        }
869    }
870
871    /// Sign the transaction with a subset of required keys, returning any errors.
872    ///
873    /// Unlike [`Transaction::try_sign`], this method does not require all
874    /// keypairs to be provided, allowing a transaction to be signed in multiple
875    /// steps.
876    ///
877    /// It is permitted to sign a transaction with the same keypair multiple
878    /// times.
879    ///
880    /// If `recent_blockhash` is different than recorded in the transaction message's
881    /// [`recent_blockhash`] field, then the message's `recent_blockhash` will be updated
882    /// to the provided `recent_blockhash`, and any prior signatures will be cleared.
883    ///
884    /// [`recent_blockhash`]: Message::recent_blockhash
885    ///
886    /// # Errors
887    ///
888    /// Signing will fail if
889    ///
890    /// - The transaction's [`Message`] is malformed such that the number of
891    ///   required signatures recorded in its header
892    ///   ([`num_required_signatures`]) is greater than the length of its
893    ///   account keys ([`account_keys`]). The error is
894    ///   [`SignerError::TransactionError`] where the interior
895    ///   [`TransactionError`] is [`TransactionError::InvalidAccountIndex`].
896    /// - Any of the provided signers in `keypairs` is not a required signer of
897    ///   the message. The error is [`SignerError::KeypairPubkeyMismatch`].
898    /// - Any of the signers is a [`Presigner`], and its provided signature is
899    ///   incorrect. The error is [`SignerError::PresignerError`] where the
900    ///   interior [`PresignerError`] is
901    ///   [`PresignerError::VerificationFailure`].
902    /// - The signer is a [`RemoteKeypair`] and
903    ///   - It does not understand the input provided ([`SignerError::InvalidInput`]).
904    ///   - The device cannot be found ([`SignerError::NoDeviceFound`]).
905    ///   - The user cancels the signing ([`SignerError::UserCancel`]).
906    ///   - An error was encountered connecting ([`SignerError::Connection`]).
907    ///   - Some device-specific protocol error occurs ([`SignerError::Protocol`]).
908    ///   - Some other error occurs ([`SignerError::Custom`]).
909    ///
910    /// See the documentation for the [`solana-remote-wallet`] crate for details
911    /// on the operation of [`RemoteKeypair`] signers.
912    ///
913    /// [`num_required_signatures`]: https://docs.rs/solana-message/latest/solana_message/struct.MessageHeader.html#structfield.num_required_signatures
914    /// [`account_keys`]: https://docs.rs/solana-message/latest/solana_message/legacy/struct.Message.html#structfield.account_keys
915    /// [`Presigner`]: https://docs.rs/solana-presigner/latest/solana_presigner/struct.Presigner.html
916    /// [`PresignerError`]: https://docs.rs/solana-signer/latest/solana_signer/enum.PresignerError.html
917    /// [`PresignerError::VerificationFailure`]: https://docs.rs/solana-signer/latest/solana_signer/enum.PresignerError.html#variant.WrongSize
918    /// [`solana-remote-wallet`]: https://docs.rs/solana-remote-wallet/latest/
919    /// [`RemoteKeypair`]: https://docs.rs/solana-remote-wallet/latest/solana_remote_wallet/remote_keypair/struct.RemoteKeypair.html
920    #[cfg(feature = "bincode")]
921    pub fn try_partial_sign<T: Signers + ?Sized>(
922        &mut self,
923        keypairs: &T,
924        recent_blockhash: Hash,
925    ) -> result::Result<(), SignerError> {
926        let positions: Vec<usize> = self
927            .get_signing_keypair_positions(&keypairs.pubkeys())?
928            .into_iter()
929            .collect::<Option<_>>()
930            .ok_or(SignerError::KeypairPubkeyMismatch)?;
931        self.try_partial_sign_unchecked(keypairs, positions, recent_blockhash)
932    }
933
934    /// Sign the transaction with a subset of required keys, returning any
935    /// errors.
936    ///
937    /// This places each of the signatures created from `keypairs` in the
938    /// corresponding position, as specified in the `positions` vector, in the
939    /// transactions [`signatures`] field. It does not verify that the signature
940    /// positions are correct.
941    ///
942    /// [`signatures`]: Transaction::signatures
943    ///
944    /// # Errors
945    ///
946    /// Returns an error if signing fails.
947    #[cfg(feature = "bincode")]
948    pub fn try_partial_sign_unchecked<T: Signers + ?Sized>(
949        &mut self,
950        keypairs: &T,
951        positions: Vec<usize>,
952        recent_blockhash: Hash,
953    ) -> result::Result<(), SignerError> {
954        // if you change the blockhash, you're re-signing...
955        if recent_blockhash != self.message.recent_blockhash {
956            self.message.recent_blockhash = recent_blockhash;
957            self.signatures
958                .iter_mut()
959                .for_each(|signature| *signature = Signature::default());
960        }
961
962        let signatures = keypairs.try_sign_message(&self.message_data())?;
963        for i in 0..positions.len() {
964            self.signatures[positions[i]] = signatures[i];
965        }
966        Ok(())
967    }
968
969    /// Returns a signature that is not valid for signing this transaction.
970    pub fn get_invalid_signature() -> Signature {
971        Signature::default()
972    }
973
974    #[cfg(feature = "verify")]
975    /// Verifies that all signers have signed the message.
976    ///
977    /// # Errors
978    ///
979    /// Returns [`TransactionError::SignatureFailure`] on error.
980    pub fn verify(&self) -> TransactionResult<()> {
981        let message_bytes = self.message_data();
982        if !self
983            ._verify_with_results(&message_bytes)
984            .iter()
985            .all(|verify_result| *verify_result)
986        {
987            Err(TransactionError::SignatureFailure)
988        } else {
989            Ok(())
990        }
991    }
992
993    #[cfg(feature = "verify")]
994    /// Verify the transaction and hash its message.
995    ///
996    /// # Errors
997    ///
998    /// Returns [`TransactionError::SignatureFailure`] on error.
999    pub fn verify_and_hash_message(&self) -> TransactionResult<Hash> {
1000        let message_bytes = self.message_data();
1001        if !self
1002            ._verify_with_results(&message_bytes)
1003            .iter()
1004            .all(|verify_result| *verify_result)
1005        {
1006            Err(TransactionError::SignatureFailure)
1007        } else {
1008            Ok(Message::hash_raw_message(&message_bytes))
1009        }
1010    }
1011
1012    #[cfg(feature = "verify")]
1013    /// Verifies that all signers have signed the message.
1014    ///
1015    /// Returns a vector with the length of required signatures, where each
1016    /// element is either `true` if that signer has signed, or `false` if not.
1017    pub fn verify_with_results(&self) -> Vec<bool> {
1018        self._verify_with_results(&self.message_data())
1019    }
1020
1021    #[cfg(feature = "verify")]
1022    pub(crate) fn _verify_with_results(&self, message_bytes: &[u8]) -> Vec<bool> {
1023        self.signatures
1024            .iter()
1025            .zip(&self.message.account_keys)
1026            .map(|(signature, pubkey)| signature.verify(pubkey.as_ref(), message_bytes))
1027            .collect()
1028    }
1029
1030    /// Get the positions of the pubkeys in `account_keys` associated with signing keypairs.
1031    ///
1032    /// [`account_keys`]: Message::account_keys
1033    pub fn get_signing_keypair_positions(
1034        &self,
1035        pubkeys: &[Address],
1036    ) -> TransactionResult<Vec<Option<usize>>> {
1037        if self.message.account_keys.len() < self.message.header.num_required_signatures as usize {
1038            return Err(TransactionError::InvalidAccountIndex);
1039        }
1040        let signed_keys =
1041            &self.message.account_keys[0..self.message.header.num_required_signatures as usize];
1042
1043        Ok(pubkeys
1044            .iter()
1045            .map(|pubkey| signed_keys.iter().position(|x| x == pubkey))
1046            .collect())
1047    }
1048
1049    #[cfg(feature = "verify")]
1050    /// Replace all the signatures and pubkeys.
1051    pub fn replace_signatures(
1052        &mut self,
1053        signers: &[(Address, Signature)],
1054    ) -> TransactionResult<()> {
1055        let num_required_signatures = self.message.header.num_required_signatures as usize;
1056        if signers.len() != num_required_signatures
1057            || self.signatures.len() != num_required_signatures
1058            || self.message.account_keys.len() < num_required_signatures
1059        {
1060            return Err(TransactionError::InvalidAccountIndex);
1061        }
1062
1063        for (index, account_key) in self
1064            .message
1065            .account_keys
1066            .iter()
1067            .enumerate()
1068            .take(num_required_signatures)
1069        {
1070            if let Some((_pubkey, signature)) =
1071                signers.iter().find(|(key, _signature)| account_key == key)
1072            {
1073                self.signatures[index] = *signature
1074            } else {
1075                return Err(TransactionError::InvalidAccountIndex);
1076            }
1077        }
1078
1079        self.verify()
1080    }
1081
1082    pub fn is_signed(&self) -> bool {
1083        self.signatures
1084            .iter()
1085            .all(|signature| *signature != Signature::default())
1086    }
1087}
1088
1089/// Returns true if transaction begins with an advance nonce instruction.
1090pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> {
1091    let message = tx.message();
1092    message
1093        .instructions
1094        .get(NONCED_TX_MARKER_IX_INDEX as usize)
1095        .filter(|instruction| {
1096            // Is system program
1097            matches!(
1098                message.account_keys.get(instruction.program_id_index as usize),
1099                Some(program_id) if system_program::check_id(program_id)
1100            ) && is_advance_nonce_instruction_data(&instruction.data)
1101        })
1102}
1103
1104#[cfg(test)]
1105mod tests {
1106    #![allow(deprecated)]
1107
1108    use {
1109        super::*,
1110        bincode::{deserialize, serialize, serialized_size},
1111        solana_instruction::AccountMeta,
1112        solana_keypair::Keypair,
1113        solana_presigner::Presigner,
1114        solana_sha256_hasher::hash,
1115        solana_signer::Signer,
1116        solana_system_interface::instruction as system_instruction,
1117        std::mem::size_of,
1118    };
1119
1120    fn get_program_id(tx: &Transaction, instruction_index: usize) -> &Address {
1121        let message = tx.message();
1122        let instruction = &message.instructions[instruction_index];
1123        instruction.program_id(&message.account_keys)
1124    }
1125
1126    #[test]
1127    fn test_refs() {
1128        let key = Keypair::new();
1129        let key1 = solana_pubkey::new_rand();
1130        let key2 = solana_pubkey::new_rand();
1131        let prog1 = solana_pubkey::new_rand();
1132        let prog2 = solana_pubkey::new_rand();
1133        let instructions = vec![
1134            CompiledInstruction::new(3, &(), vec![0, 1]),
1135            CompiledInstruction::new(4, &(), vec![0, 2]),
1136        ];
1137        let tx = Transaction::new_with_compiled_instructions(
1138            &[&key],
1139            &[key1, key2],
1140            Hash::default(),
1141            vec![prog1, prog2],
1142            instructions,
1143        );
1144        assert!(tx.sanitize().is_ok());
1145
1146        assert_eq!(tx.key(0, 0), Some(&key.pubkey()));
1147        assert_eq!(tx.signer_key(0, 0), Some(&key.pubkey()));
1148
1149        assert_eq!(tx.key(1, 0), Some(&key.pubkey()));
1150        assert_eq!(tx.signer_key(1, 0), Some(&key.pubkey()));
1151
1152        assert_eq!(tx.key(0, 1), Some(&key1));
1153        assert_eq!(tx.signer_key(0, 1), None);
1154
1155        assert_eq!(tx.key(1, 1), Some(&key2));
1156        assert_eq!(tx.signer_key(1, 1), None);
1157
1158        assert_eq!(tx.key(2, 0), None);
1159        assert_eq!(tx.signer_key(2, 0), None);
1160
1161        assert_eq!(tx.key(0, 2), None);
1162        assert_eq!(tx.signer_key(0, 2), None);
1163
1164        assert_eq!(*get_program_id(&tx, 0), prog1);
1165        assert_eq!(*get_program_id(&tx, 1), prog2);
1166    }
1167
1168    #[test]
1169    fn test_refs_invalid_program_id() {
1170        let key = Keypair::new();
1171        let instructions = vec![CompiledInstruction::new(1, &(), vec![])];
1172        let tx = Transaction::new_with_compiled_instructions(
1173            &[&key],
1174            &[],
1175            Hash::default(),
1176            vec![],
1177            instructions,
1178        );
1179        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1180    }
1181    #[test]
1182    fn test_refs_invalid_account() {
1183        let key = Keypair::new();
1184        let instructions = vec![CompiledInstruction::new(1, &(), vec![2])];
1185        let tx = Transaction::new_with_compiled_instructions(
1186            &[&key],
1187            &[],
1188            Hash::default(),
1189            vec![Address::default()],
1190            instructions,
1191        );
1192        assert_eq!(*get_program_id(&tx, 0), Address::default());
1193        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1194    }
1195
1196    #[test]
1197    fn test_sanitize_txs() {
1198        let key = Keypair::new();
1199        let id0 = Address::default();
1200        let program_id = solana_pubkey::new_rand();
1201        let ix = Instruction::new_with_bincode(
1202            program_id,
1203            &0,
1204            vec![
1205                AccountMeta::new(key.pubkey(), true),
1206                AccountMeta::new(id0, true),
1207            ],
1208        );
1209        let mut tx = Transaction::new_with_payer(&[ix], Some(&key.pubkey()));
1210        let o = tx.clone();
1211        assert_eq!(tx.sanitize(), Ok(()));
1212        assert_eq!(tx.message.account_keys.len(), 3);
1213
1214        tx = o.clone();
1215        tx.message.header.num_required_signatures = 3;
1216        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1217
1218        tx = o.clone();
1219        tx.message.header.num_readonly_signed_accounts = 4;
1220        tx.message.header.num_readonly_unsigned_accounts = 0;
1221        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1222
1223        tx = o.clone();
1224        tx.message.header.num_readonly_signed_accounts = 2;
1225        tx.message.header.num_readonly_unsigned_accounts = 2;
1226        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1227
1228        tx = o.clone();
1229        tx.message.header.num_readonly_signed_accounts = 0;
1230        tx.message.header.num_readonly_unsigned_accounts = 4;
1231        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1232
1233        tx = o.clone();
1234        tx.message.instructions[0].program_id_index = 3;
1235        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1236
1237        tx = o.clone();
1238        tx.message.instructions[0].accounts[0] = 3;
1239        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1240
1241        tx = o.clone();
1242        tx.message.instructions[0].program_id_index = 0;
1243        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1244
1245        tx = o.clone();
1246        tx.message.header.num_readonly_signed_accounts = 2;
1247        tx.message.header.num_readonly_unsigned_accounts = 3;
1248        tx.message.account_keys.resize(4, Address::default());
1249        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1250
1251        tx = o;
1252        tx.message.header.num_readonly_signed_accounts = 2;
1253        tx.message.header.num_required_signatures = 1;
1254        assert_eq!(tx.sanitize(), Err(SanitizeError::IndexOutOfBounds));
1255    }
1256
1257    fn create_sample_transaction() -> Transaction {
1258        let keypair = Keypair::try_from(
1259            [
1260                255, 101, 36, 24, 124, 23, 167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 156, 227,
1261                116, 193, 215, 38, 142, 22, 8, 14, 229, 239, 119, 93, 5, 218, 36, 100, 158, 252,
1262                33, 161, 97, 185, 62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90, 248, 14,
1263                68, 219, 231, 62, 157, 5, 142, 27, 210, 117,
1264            ]
1265            .as_ref(),
1266        )
1267        .unwrap();
1268        let to = Address::from([
1269            1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4,
1270            1, 1, 1,
1271        ]);
1272
1273        let program_id = Address::from([
1274            2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4,
1275            2, 2, 2,
1276        ]);
1277        let account_metas = vec![
1278            AccountMeta::new(keypair.pubkey(), true),
1279            AccountMeta::new(to, false),
1280        ];
1281        let instruction =
1282            Instruction::new_with_bincode(program_id, &(1u8, 2u8, 3u8), account_metas);
1283        let message = Message::new(&[instruction], Some(&keypair.pubkey()));
1284        let tx = Transaction::new(&[&keypair], message, Hash::default());
1285        tx.verify().expect("valid sample transaction signatures");
1286        tx
1287    }
1288
1289    #[test]
1290    fn test_transaction_serialize() {
1291        let tx = create_sample_transaction();
1292        let ser = serialize(&tx).unwrap();
1293        let deser = deserialize(&ser).unwrap();
1294        assert_eq!(tx, deser);
1295    }
1296
1297    /// Detect changes to the serialized size of payment transactions, which affects TPS.
1298    #[test]
1299    fn test_transaction_minimum_serialized_size() {
1300        let alice_keypair = Keypair::new();
1301        let alice_pubkey = alice_keypair.pubkey();
1302        let bob_pubkey = solana_pubkey::new_rand();
1303        let ix = system_instruction::transfer(&alice_pubkey, &bob_pubkey, 42);
1304
1305        let expected_data_size = size_of::<u32>() + size_of::<u64>();
1306        assert_eq!(expected_data_size, 12);
1307        assert_eq!(
1308            ix.data.len(),
1309            expected_data_size,
1310            "unexpected system instruction size"
1311        );
1312
1313        let expected_instruction_size = 1 + 1 + ix.accounts.len() + 1 + expected_data_size;
1314        assert_eq!(expected_instruction_size, 17);
1315
1316        let message = Message::new(&[ix], Some(&alice_pubkey));
1317        assert_eq!(
1318            serialized_size(&message.instructions[0]).unwrap() as usize,
1319            expected_instruction_size,
1320            "unexpected Instruction::serialized_size"
1321        );
1322
1323        let tx = Transaction::new(&[&alice_keypair], message, Hash::default());
1324
1325        let len_size = 1;
1326        let num_required_sigs_size = 1;
1327        let num_readonly_accounts_size = 2;
1328        let blockhash_size = size_of::<Hash>();
1329        let expected_transaction_size = len_size
1330            + (tx.signatures.len() * size_of::<Signature>())
1331            + num_required_sigs_size
1332            + num_readonly_accounts_size
1333            + len_size
1334            + (tx.message.account_keys.len() * size_of::<Address>())
1335            + blockhash_size
1336            + len_size
1337            + expected_instruction_size;
1338        assert_eq!(expected_transaction_size, 215);
1339
1340        assert_eq!(
1341            serialized_size(&tx).unwrap() as usize,
1342            expected_transaction_size,
1343            "unexpected serialized transaction size"
1344        );
1345    }
1346
1347    /// Detect binary changes in the serialized transaction data, which could have a downstream
1348    /// affect on SDKs and applications
1349    #[test]
1350    fn test_sdk_serialize() {
1351        assert_eq!(
1352            serialize(&create_sample_transaction()).unwrap(),
1353            vec![
1354                1, 120, 138, 162, 185, 59, 209, 241, 157, 71, 157, 74, 131, 4, 87, 54, 28, 38, 180,
1355                222, 82, 64, 62, 61, 62, 22, 46, 17, 203, 187, 136, 62, 43, 11, 38, 235, 17, 239,
1356                82, 240, 139, 130, 217, 227, 214, 9, 242, 141, 223, 94, 29, 184, 110, 62, 32, 87,
1357                137, 63, 139, 100, 221, 20, 137, 4, 5, 1, 0, 1, 3, 36, 100, 158, 252, 33, 161, 97,
1358                185, 62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90, 248, 14, 68, 219, 231,
1359                62, 157, 5, 142, 27, 210, 117, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
1360                9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1,
1361                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1362                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 1,
1363                3, 1, 2, 3
1364            ]
1365        );
1366    }
1367
1368    #[test]
1369    #[should_panic]
1370    fn test_transaction_missing_key() {
1371        let keypair = Keypair::new();
1372        let message = Message::new(&[], None);
1373        Transaction::new_unsigned(message).sign(&[&keypair], Hash::default());
1374    }
1375
1376    #[test]
1377    #[should_panic]
1378    fn test_partial_sign_mismatched_key() {
1379        let keypair = Keypair::new();
1380        let fee_payer = solana_pubkey::new_rand();
1381        let ix = Instruction::new_with_bincode(
1382            Address::default(),
1383            &0,
1384            vec![AccountMeta::new(fee_payer, true)],
1385        );
1386        let message = Message::new(&[ix], Some(&fee_payer));
1387        Transaction::new_unsigned(message).partial_sign(&[&keypair], Hash::default());
1388    }
1389
1390    #[test]
1391    fn test_partial_sign() {
1392        let keypair0 = Keypair::new();
1393        let keypair1 = Keypair::new();
1394        let keypair2 = Keypair::new();
1395        let ix = Instruction::new_with_bincode(
1396            Address::default(),
1397            &0,
1398            vec![
1399                AccountMeta::new(keypair0.pubkey(), true),
1400                AccountMeta::new(keypair1.pubkey(), true),
1401                AccountMeta::new(keypair2.pubkey(), true),
1402            ],
1403        );
1404        let message = Message::new(&[ix], Some(&keypair0.pubkey()));
1405        let mut tx = Transaction::new_unsigned(message);
1406
1407        tx.partial_sign(&[&keypair0, &keypair2], Hash::default());
1408        assert!(!tx.is_signed());
1409        tx.partial_sign(&[&keypair1], Hash::default());
1410        assert!(tx.is_signed());
1411
1412        let hash = hash(&[1]);
1413        tx.partial_sign(&[&keypair1], hash);
1414        assert!(!tx.is_signed());
1415        tx.partial_sign(&[&keypair0, &keypair2], hash);
1416        assert!(tx.is_signed());
1417    }
1418
1419    #[test]
1420    #[should_panic]
1421    fn test_transaction_missing_keypair() {
1422        let program_id = Address::default();
1423        let keypair0 = Keypair::new();
1424        let id0 = keypair0.pubkey();
1425        let ix = Instruction::new_with_bincode(program_id, &0, vec![AccountMeta::new(id0, true)]);
1426        let message = Message::new(&[ix], Some(&id0));
1427        Transaction::new_unsigned(message).sign(&Vec::<&Keypair>::new(), Hash::default());
1428    }
1429
1430    #[test]
1431    #[should_panic]
1432    fn test_transaction_wrong_key() {
1433        let program_id = Address::default();
1434        let keypair0 = Keypair::new();
1435        let wrong_id = Address::default();
1436        let ix =
1437            Instruction::new_with_bincode(program_id, &0, vec![AccountMeta::new(wrong_id, true)]);
1438        let message = Message::new(&[ix], Some(&wrong_id));
1439        Transaction::new_unsigned(message).sign(&[&keypair0], Hash::default());
1440    }
1441
1442    #[test]
1443    fn test_transaction_correct_key() {
1444        let program_id = Address::default();
1445        let keypair0 = Keypair::new();
1446        let id0 = keypair0.pubkey();
1447        let ix = Instruction::new_with_bincode(program_id, &0, vec![AccountMeta::new(id0, true)]);
1448        let message = Message::new(&[ix], Some(&id0));
1449        let mut tx = Transaction::new_unsigned(message);
1450        tx.sign(&[&keypair0], Hash::default());
1451        assert_eq!(
1452            tx.message.instructions[0],
1453            CompiledInstruction::new(1, &0, vec![0])
1454        );
1455        assert!(tx.is_signed());
1456    }
1457
1458    #[test]
1459    fn test_transaction_instruction_with_duplicate_keys() {
1460        let program_id = Address::default();
1461        let keypair0 = Keypair::new();
1462        let id0 = keypair0.pubkey();
1463        let id1 = solana_pubkey::new_rand();
1464        let ix = Instruction::new_with_bincode(
1465            program_id,
1466            &0,
1467            vec![
1468                AccountMeta::new(id0, true),
1469                AccountMeta::new(id1, false),
1470                AccountMeta::new(id0, false),
1471                AccountMeta::new(id1, false),
1472            ],
1473        );
1474        let message = Message::new(&[ix], Some(&id0));
1475        let mut tx = Transaction::new_unsigned(message);
1476        tx.sign(&[&keypair0], Hash::default());
1477        assert_eq!(
1478            tx.message.instructions[0],
1479            CompiledInstruction::new(2, &0, vec![0, 1, 0, 1])
1480        );
1481        assert!(tx.is_signed());
1482    }
1483
1484    #[test]
1485    fn test_try_sign_dyn_keypairs() {
1486        let program_id = Address::default();
1487        let keypair = Keypair::new();
1488        let pubkey = keypair.pubkey();
1489        let presigner_keypair = Keypair::new();
1490        let presigner_pubkey = presigner_keypair.pubkey();
1491
1492        let ix = Instruction::new_with_bincode(
1493            program_id,
1494            &0,
1495            vec![
1496                AccountMeta::new(pubkey, true),
1497                AccountMeta::new(presigner_pubkey, true),
1498            ],
1499        );
1500        let message = Message::new(&[ix], Some(&pubkey));
1501        let mut tx = Transaction::new_unsigned(message);
1502
1503        let presigner_sig = presigner_keypair.sign_message(&tx.message_data());
1504        let presigner = Presigner::new(&presigner_pubkey, &presigner_sig);
1505
1506        let signers: Vec<&dyn Signer> = vec![&keypair, &presigner];
1507
1508        let res = tx.try_sign(&signers, Hash::default());
1509        assert_eq!(res, Ok(()));
1510        assert_eq!(tx.signatures[0], keypair.sign_message(&tx.message_data()));
1511        assert_eq!(tx.signatures[1], presigner_sig);
1512
1513        // Wrong key should error, not panic
1514        let another_pubkey = solana_pubkey::new_rand();
1515        let ix = Instruction::new_with_bincode(
1516            program_id,
1517            &0,
1518            vec![
1519                AccountMeta::new(another_pubkey, true),
1520                AccountMeta::new(presigner_pubkey, true),
1521            ],
1522        );
1523        let message = Message::new(&[ix], Some(&another_pubkey));
1524        let mut tx = Transaction::new_unsigned(message);
1525
1526        let res = tx.try_sign(&signers, Hash::default());
1527        assert!(res.is_err());
1528        assert_eq!(
1529            tx.signatures,
1530            vec![Signature::default(), Signature::default()]
1531        );
1532    }
1533
1534    fn nonced_transfer_tx() -> (Address, Address, Transaction) {
1535        let from_keypair = Keypair::new();
1536        let from_pubkey = from_keypair.pubkey();
1537        let nonce_keypair = Keypair::new();
1538        let nonce_pubkey = nonce_keypair.pubkey();
1539        let instructions = [
1540            system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey),
1541            system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42),
1542        ];
1543        let message = Message::new(&instructions, Some(&nonce_pubkey));
1544        let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default());
1545        (from_pubkey, nonce_pubkey, tx)
1546    }
1547
1548    #[test]
1549    fn tx_uses_nonce_ok() {
1550        let (_, _, tx) = nonced_transfer_tx();
1551        assert!(uses_durable_nonce(&tx).is_some());
1552    }
1553
1554    #[test]
1555    fn tx_uses_nonce_empty_ix_fail() {
1556        assert!(uses_durable_nonce(&Transaction::default()).is_none());
1557    }
1558
1559    #[test]
1560    fn tx_uses_nonce_bad_prog_id_idx_fail() {
1561        let (_, _, mut tx) = nonced_transfer_tx();
1562        tx.message.instructions.get_mut(0).unwrap().program_id_index = 255u8;
1563        assert!(uses_durable_nonce(&tx).is_none());
1564    }
1565
1566    #[test]
1567    fn tx_uses_nonce_first_prog_id_not_nonce_fail() {
1568        let from_keypair = Keypair::new();
1569        let from_pubkey = from_keypair.pubkey();
1570        let nonce_keypair = Keypair::new();
1571        let nonce_pubkey = nonce_keypair.pubkey();
1572        let instructions = [
1573            system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42),
1574            system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey),
1575        ];
1576        let message = Message::new(&instructions, Some(&from_pubkey));
1577        let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default());
1578        assert!(uses_durable_nonce(&tx).is_none());
1579    }
1580
1581    #[test]
1582    fn tx_uses_nonce_wrong_first_nonce_ix_fail() {
1583        let from_keypair = Keypair::new();
1584        let from_pubkey = from_keypair.pubkey();
1585        let nonce_keypair = Keypair::new();
1586        let nonce_pubkey = nonce_keypair.pubkey();
1587        let instructions = [
1588            system_instruction::withdraw_nonce_account(
1589                &nonce_pubkey,
1590                &nonce_pubkey,
1591                &from_pubkey,
1592                42,
1593            ),
1594            system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42),
1595        ];
1596        let message = Message::new(&instructions, Some(&nonce_pubkey));
1597        let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default());
1598        assert!(uses_durable_nonce(&tx).is_none());
1599    }
1600
1601    #[test]
1602    fn tx_keypair_pubkey_mismatch() {
1603        let from_keypair = Keypair::new();
1604        let from_pubkey = from_keypair.pubkey();
1605        let to_pubkey = Address::new_unique();
1606        let instructions = [system_instruction::transfer(&from_pubkey, &to_pubkey, 42)];
1607        let mut tx = Transaction::new_with_payer(&instructions, Some(&from_pubkey));
1608        let unused_keypair = Keypair::new();
1609        let err = tx
1610            .try_partial_sign(&[&from_keypair, &unused_keypair], Hash::default())
1611            .unwrap_err();
1612        assert_eq!(err, SignerError::KeypairPubkeyMismatch);
1613    }
1614
1615    #[test]
1616    fn test_unsized_signers() {
1617        fn instructions_to_tx(
1618            instructions: &[Instruction],
1619            signers: Box<dyn Signers>,
1620        ) -> Transaction {
1621            let pubkeys = signers.pubkeys();
1622            let first_signer = pubkeys.first().expect("should exist");
1623            let message = Message::new(instructions, Some(first_signer));
1624            Transaction::new(signers.as_ref(), message, Hash::default())
1625        }
1626
1627        let signer: Box<dyn Signer> = Box::new(Keypair::new());
1628        let tx = instructions_to_tx(&[], Box::new(vec![signer]));
1629
1630        assert!(tx.is_signed());
1631    }
1632
1633    #[test]
1634    fn test_replace_signatures() {
1635        let program_id = Address::default();
1636        let keypair0 = Keypair::new();
1637        let keypair1 = Keypair::new();
1638        let pubkey0 = keypair0.pubkey();
1639        let pubkey1 = keypair1.pubkey();
1640        let ix = Instruction::new_with_bincode(
1641            program_id,
1642            &0,
1643            vec![
1644                AccountMeta::new(pubkey0, true),
1645                AccountMeta::new(pubkey1, true),
1646            ],
1647        );
1648        let message = Message::new(&[ix], Some(&pubkey0));
1649        let expected_account_keys = message.account_keys.clone();
1650        let mut tx = Transaction::new_unsigned(message);
1651        tx.sign(&[&keypair0, &keypair1], Hash::new_unique());
1652
1653        let signature0 = keypair0.sign_message(&tx.message_data());
1654        let signature1 = keypair1.sign_message(&tx.message_data());
1655
1656        // Replace signatures with order swapped
1657        tx.replace_signatures(&[(pubkey1, signature1), (pubkey0, signature0)])
1658            .unwrap();
1659        // Order of account_keys should not change
1660        assert_eq!(tx.message.account_keys, expected_account_keys);
1661        // Order of signatures should match original account_keys list
1662        assert_eq!(tx.signatures, &[signature0, signature1]);
1663    }
1664}