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