gmsol_solana_utils/utils/
transaction_size.rs

1use std::{borrow::Borrow, collections::HashSet};
2
3use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
4
5/// Estimated the size of the result transaction.
6///
7/// Based on the docs of [Solana Transactions](https://solana.com/docs/core/transactions),
8/// and referring to the implementation of `@pythnetwork/solana-utils`.
9pub fn transaction_size<T: Borrow<Instruction>>(
10    ixs: &[T],
11    is_versioned_transaction: bool,
12    lookup_table: Option<&HashSet<Pubkey>>,
13    lookup_table_addresses: usize,
14) -> usize {
15    use std::collections::HashSet;
16
17    fn get_size_of_compressed_u16(size: usize) -> usize {
18        match size {
19            0..=127 => 1,
20            128..=16383 => 2,
21            _ => 3,
22        }
23    }
24
25    let mut programs = HashSet::<Pubkey>::default();
26    let mut accounts = HashSet::<Pubkey>::default();
27    let mut signers = HashSet::<Pubkey>::default();
28
29    let ixs_size = ixs.iter().fold(0, |size, ix| {
30        let ix = ix.borrow();
31        programs.insert(ix.program_id);
32        accounts.insert(ix.program_id);
33        ix.accounts.iter().for_each(|account| {
34            accounts.insert(account.pubkey);
35            if account.is_signer {
36                signers.insert(account.pubkey);
37            }
38        });
39        size + 1
40            + get_size_of_compressed_u16(ix.accounts.len())
41            + ix.accounts.len()
42            + get_size_of_compressed_u16(ix.data.len())
43            + ix.data.len()
44    });
45
46    let num_of_address_lookups = if let Some(lookup_table) = lookup_table {
47        let total_accounts = accounts.len();
48        accounts = accounts.difference(lookup_table).copied().collect();
49        accounts = accounts
50            .union(&signers)
51            .chain(programs.iter())
52            .copied()
53            .collect();
54        total_accounts - accounts.len()
55    } else {
56        0
57    };
58
59    let size = get_size_of_compressed_u16(signers.len())
60        + signers.len() * 64
61        + 3
62        + get_size_of_compressed_u16(accounts.len())
63        + accounts.len() * 32
64        + 32
65        + get_size_of_compressed_u16(ixs.len())
66        + ixs_size
67        + num_of_address_lookups;
68    if is_versioned_transaction {
69        size + 1 + get_size_of_compressed_u16(0) + lookup_table_addresses * (32 + 2)
70    } else {
71        size
72    }
73}