Skip to main content

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