solana_sdk/transaction/
mod.rs

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