solana_runtime/
non_circulating_supply.rs

1use {
2    crate::bank::Bank,
3    log::*,
4    solana_account::ReadableAccount,
5    solana_accounts_db::accounts_index::{AccountIndex, IndexKey, ScanConfig, ScanResult},
6    solana_pubkey::Pubkey,
7    solana_stake_interface::{self as stake, state::StakeStateV2},
8    solana_stake_program::stake_state,
9    std::collections::HashSet,
10};
11
12pub struct NonCirculatingSupply {
13    pub lamports: u64,
14    pub accounts: Vec<Pubkey>,
15}
16
17pub fn calculate_non_circulating_supply(bank: &Bank) -> ScanResult<NonCirculatingSupply> {
18    debug!("Updating Bank supply, epoch: {}", bank.epoch());
19    let mut non_circulating_accounts_set: HashSet<Pubkey> = HashSet::new();
20
21    for key in non_circulating_accounts() {
22        non_circulating_accounts_set.insert(key);
23    }
24    let withdraw_authority_list = withdraw_authority();
25
26    let clock = bank.clock();
27    let config = &ScanConfig::default();
28    let stake_accounts = if bank
29        .rc
30        .accounts
31        .accounts_db
32        .account_indexes
33        .contains(&AccountIndex::ProgramId)
34    {
35        bank.get_filtered_indexed_accounts(
36            &IndexKey::ProgramId(stake::program::id()),
37            // The program-id account index checks for Account owner on inclusion. However, due to
38            // the current AccountsDb implementation, an account may remain in storage as a
39            // zero-lamport Account::Default() after being wiped and reinitialized in later
40            // updates. We include the redundant filter here to avoid returning these accounts.
41            |account| account.owner() == &stake::program::id(),
42            config,
43            None,
44        )?
45    } else {
46        bank.get_program_accounts(&stake::program::id(), config)?
47    };
48
49    for (pubkey, account) in stake_accounts.iter() {
50        let stake_account = stake_state::from(account).unwrap_or_default();
51        match stake_account {
52            StakeStateV2::Initialized(meta) => {
53                if meta.lockup.is_in_force(&clock, None)
54                    || withdraw_authority_list.contains(&meta.authorized.withdrawer)
55                {
56                    non_circulating_accounts_set.insert(*pubkey);
57                }
58            }
59            StakeStateV2::Stake(meta, _stake, _stake_flags) => {
60                if meta.lockup.is_in_force(&clock, None)
61                    || withdraw_authority_list.contains(&meta.authorized.withdrawer)
62                {
63                    non_circulating_accounts_set.insert(*pubkey);
64                }
65            }
66            _ => {}
67        }
68    }
69
70    let lamports = non_circulating_accounts_set
71        .iter()
72        .map(|pubkey| bank.get_balance(pubkey))
73        .sum();
74
75    Ok(NonCirculatingSupply {
76        lamports,
77        accounts: non_circulating_accounts_set.into_iter().collect(),
78    })
79}
80
81// Mainnet-beta accounts that should be considered non-circulating
82pub fn non_circulating_accounts() -> Vec<Pubkey> {
83    [
84        solana_pubkey::pubkey!("9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA"),
85        solana_pubkey::pubkey!("GK2zqSsXLA2rwVZk347RYhh6jJpRsCA69FjLW93ZGi3B"),
86        solana_pubkey::pubkey!("CWeRmXme7LmbaUWTZWFLt6FMnpzLCHaQLuR2TdgFn4Lq"),
87        solana_pubkey::pubkey!("HCV5dGFJXRrJ3jhDYA4DCeb9TEDTwGGYXtT3wHksu2Zr"),
88        solana_pubkey::pubkey!("14FUT96s9swbmH7ZjpDvfEDywnAYy9zaNhv4xvezySGu"),
89        solana_pubkey::pubkey!("HbZ5FfmKWNHC7uwk6TF1hVi6TCs7dtYfdjEcuPGgzFAg"),
90        solana_pubkey::pubkey!("C7C8odR8oashR5Feyrq2tJKaXL18id1dSj2zbkDGL2C2"),
91        solana_pubkey::pubkey!("Eyr9P5XsjK2NUKNCnfu39eqpGoiLFgVAv1LSQgMZCwiQ"),
92        solana_pubkey::pubkey!("DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ"),
93        solana_pubkey::pubkey!("CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S"),
94        solana_pubkey::pubkey!("7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2"),
95        solana_pubkey::pubkey!("GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ"),
96        solana_pubkey::pubkey!("Mc5XB47H3DKJHym5RLa9mPzWv5snERsF3KNv5AauXK8"),
97        solana_pubkey::pubkey!("7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri"),
98        solana_pubkey::pubkey!("AG3m2bAibcY8raMt4oXEGqRHwX4FWKPPJVjZxn1LySDX"),
99        solana_pubkey::pubkey!("5XdtyEDREHJXXW1CTtCsVjJRjBapAwK78ZquzvnNVRrV"),
100        solana_pubkey::pubkey!("6yKHERk8rsbmJxvMpPuwPs1ct3hRiP7xaJF2tvnGU6nK"),
101        solana_pubkey::pubkey!("CHmdL15akDcJgBkY6BP3hzs98Dqr6wbdDC5p8odvtSbq"),
102        solana_pubkey::pubkey!("FR84wZQy3Y3j2gWz6pgETUiUoJtreMEuWfbg6573UCj9"),
103        solana_pubkey::pubkey!("5q54XjQ7vDx4y6KphPeE97LUNiYGtP55spjvXAWPGBuf"),
104        solana_pubkey::pubkey!("3o6xgkJ9sTmDeQWyfj3sxwon18fXJB9PV5LDc8sfgR4a"),
105        solana_pubkey::pubkey!("GumSE5HsMV5HCwBTv2D2D81yy9x17aDkvobkqAfTRgmo"),
106        solana_pubkey::pubkey!("AzVV9ZZDxTgW4wWfJmsG6ytaHpQGSe1yz76Nyy84VbQF"),
107        solana_pubkey::pubkey!("8CUUMKYNGxdgYio5CLHRHyzMEhhVRMcqefgE6dLqnVRK"),
108        solana_pubkey::pubkey!("CQDYc4ET2mbFhVpgj41gXahL6Exn5ZoPcGAzSHuYxwmE"),
109        solana_pubkey::pubkey!("5PLJZLJiRR9vf7d1JCCg7UuWjtyN9nkab9uok6TqSyuP"),
110        solana_pubkey::pubkey!("7xJ9CLtEAcEShw9kW2gSoZkRWL566Dg12cvgzANJwbTr"),
111        solana_pubkey::pubkey!("BuCEvc9ze8UoAQwwsQLy8d447C8sA4zeVtVpc6m5wQeS"),
112        solana_pubkey::pubkey!("8ndGYFjav6NDXvzYcxs449Aub3AxYv4vYpk89zRDwgj7"),
113        solana_pubkey::pubkey!("8W58E8JVJjH1jCy5CeHJQgvwFXTyAVyesuXRZGbcSUGG"),
114        solana_pubkey::pubkey!("GNiz4Mq886bTNDT3pijGsu2gbw6it7sqrwncro45USeB"),
115        solana_pubkey::pubkey!("GhsotwFMH6XUrRLJCxcx62h7748N2Uq8mf87hUGkmPhg"),
116        solana_pubkey::pubkey!("Fgyh8EeYGZtbW8sS33YmNQnzx54WXPrJ5KWNPkCfWPot"),
117        solana_pubkey::pubkey!("8UVjvYyoqP6sqcctTso3xpCdCfgTMiv3VRh7vraC2eJk"),
118        solana_pubkey::pubkey!("BhvLngiqqKeZ8rpxch2uGjeCiC88zzewoWPRuoxpp1aS"),
119        solana_pubkey::pubkey!("63DtkW7zuARcd185EmHAkfF44bDcC2SiTSEj2spLP3iA"),
120        solana_pubkey::pubkey!("GvpCiTgq9dmEeojCDBivoLoZqc4AkbUDACpqPMwYLWKh"),
121        solana_pubkey::pubkey!("7Y8smnoUrYKGGuDq2uaFKVxJYhojgg7DVixHyAtGTYEV"),
122        solana_pubkey::pubkey!("DUS1KxwUhUyDKB4A81E8vdnTe3hSahd92Abtn9CXsEcj"),
123        solana_pubkey::pubkey!("F9MWFw8cnYVwsRq8Am1PGfFL3cQUZV37mbGoxZftzLjN"),
124        solana_pubkey::pubkey!("8vqrX3H2BYLaXVintse3gorPEM4TgTwTFZNN1Fm9TdYs"),
125        solana_pubkey::pubkey!("CUageMFi49kzoDqtdU8NvQ4Bq3sbtJygjKDAXJ45nmAi"),
126        solana_pubkey::pubkey!("5smrYwb1Hr2T8XMnvsqccTgXxuqQs14iuE8RbHFYf2Cf"),
127        solana_pubkey::pubkey!("xQadXQiUTCCFhfHjvQx1hyJK6KVWr1w2fD6DT3cdwj7"),
128        solana_pubkey::pubkey!("8DE8fqPfv1fp9DHyGyDFFaMjpopMgDeXspzoi9jpBJjC"),
129        solana_pubkey::pubkey!("3itU5ME8L6FDqtMiRoUiT1F7PwbkTtHBbW51YWD5jtjm"),
130        solana_pubkey::pubkey!("AsrYX4FeLXnZcrjcZmrASY2Eq1jvEeQfwxtNTxS5zojA"),
131        solana_pubkey::pubkey!("8rT45mqpuDBR1vcnDc9kwP9DrZAXDR4ZeuKWw3u1gTGa"),
132        solana_pubkey::pubkey!("nGME7HgBT6tAJN1f6YuCCngpqT5cvSTndZUVLjQ4jwA"),
133        solana_pubkey::pubkey!("CzAHrrrHKx9Lxf6wdCMrsZkLvk74c7J2vGv8VYPUmY6v"),
134        solana_pubkey::pubkey!("AzHQ8Bia1grVVbcGyci7wzueSWkgvu7YZVZ4B9rkL5P6"),
135        solana_pubkey::pubkey!("FiWYY85b58zEEcPtxe3PuqzWPjqBJXqdwgZeqSBmT9Cn"),
136        solana_pubkey::pubkey!("GpxpMVhrBBBEYbEJxdR62w3daWz444V7m6dxYDZKH77D"),
137        solana_pubkey::pubkey!("3bTGcGB9F98XxnrBNftmmm48JGfPgi5sYxDEKiCjQYk3"),
138        solana_pubkey::pubkey!("8pNBEppa1VcFAsx4Hzq9CpdXUXZjUXbvQwLX2K7QsCwb"),
139        solana_pubkey::pubkey!("HKJgYGTTYYR2ZkfJKHbn58w676fKueQXmvbtpyvrSM3N"),
140        solana_pubkey::pubkey!("3jnknRabs7G2V9dKhxd2KP85pNWXKXiedYnYxtySnQMs"),
141        solana_pubkey::pubkey!("4sxwau4mdqZ8zEJsfryXq4QFYnMJSCp3HWuZQod8WU5k"),
142        solana_pubkey::pubkey!("Fg12tB1tz8w6zJSQ4ZAGotWoCztdMJF9hqK8R11pakog"),
143        solana_pubkey::pubkey!("GEWSkfWgHkpiLbeKaAnwvqnECGdRNf49at5nFccVey7c"),
144        solana_pubkey::pubkey!("CND6ZjRTzaCFVdX7pSSWgjTfHZuhxqFDoUBqWBJguNoA"),
145        solana_pubkey::pubkey!("2WWb1gRzuXDd5viZLQF7pNRR6Y7UiyeaPpaL35X6j3ve"),
146        solana_pubkey::pubkey!("BUnRE27mYXN9p8H1Ay24GXhJC88q2CuwLoNU2v2CrW4W"),
147        solana_pubkey::pubkey!("CsUqV42gVQLJwQsKyjWHqGkfHarxn9hcY4YeSjgaaeTd"),
148        solana_pubkey::pubkey!("5khMKAcvmsFaAhoKkdg3u5abvKsmjUQNmhTNP624WB1F"),
149        solana_pubkey::pubkey!("GpYnVDgB7dzvwSgsjQFeHznjG6Kt1DLBFYrKxjGU1LuD"),
150        solana_pubkey::pubkey!("DQQGPtj7pphPHCLzzBuEyDDQByUcKGrsJdsH7SP3hAug"),
151        solana_pubkey::pubkey!("FwfaykN7ACnsEUDHANzGHqTGQZMcGnUSsahAHUqbdPrz"),
152        solana_pubkey::pubkey!("JCwT5Ygmq3VeBEbDjL8s8E82Ra2rP9bq45QfZE7Xyaq7"),
153        solana_pubkey::pubkey!("H3Ni7vG1CsmJZdTvxF7RkAf9UM5qk4RsohJsmPvtZNnu"),
154        solana_pubkey::pubkey!("CVgyXrbEd1ctEuvq11QdpnCQVnPit8NLdhyqXQHLprM2"),
155        solana_pubkey::pubkey!("EAJJD6nDqtXcZ4DnQb19F9XEz8y8bRDHxbWbahatZNbL"),
156        solana_pubkey::pubkey!("6o5v1HC7WhBnLfRHp8mQTtCP2khdXXjhuyGyYEoy2Suy"),
157        solana_pubkey::pubkey!("3ZrsTmNM6AkMcqFfv3ryfhQ2jMfqP64RQbqVyAaxqhrQ"),
158        solana_pubkey::pubkey!("6zw7em7uQdmMpuS9fGz8Nq9TLHa5YQhEKKwPjo5PwDK4"),
159        solana_pubkey::pubkey!("CuatS6njAcfkFHnvai7zXCs7syA9bykXWsDCJEWfhjHG"),
160        solana_pubkey::pubkey!("Hz9nydgN1k15wnwffKX7CSmZp4VFTnTwLXAEdomFGNXy"),
161        solana_pubkey::pubkey!("Ep5Y58PaSyALPrdFxDVAdfKtVdP55vApvsWjb3jSmXsG"),
162        solana_pubkey::pubkey!("EziVYi3Sv5kJWxmU77PnbrT8jmkVuqwdiFLLzZpLVEn7"),
163        solana_pubkey::pubkey!("H1rt8KvXkNhQExTRfkY8r9wjZbZ8yCih6J4wQ5Fz9HGP"),
164        solana_pubkey::pubkey!("6nN69B4uZuESZYxr9nrLDjmKRtjDZQXrehwkfQTKw62U"),
165        solana_pubkey::pubkey!("Hm9JW7of5i9dnrboS8pCUCSeoQUPh7JsP1rkbJnW7An4"),
166        solana_pubkey::pubkey!("5D5NxsNVTgXHyVziwV7mDFwVDS6voaBsyyGxUbhQrhNW"),
167        solana_pubkey::pubkey!("EMAY24PrS6rWfvpqffFCsTsFJypeeYYmtUc26wdh3Wup"),
168        solana_pubkey::pubkey!("Br3aeVGapRb2xTq17RU2pYZCoJpWA7bq6TKBCcYtMSmt"),
169        solana_pubkey::pubkey!("BUjkdqUuH5Lz9XzcMcR4DdEMnFG6r8QzUMBm16Rfau96"),
170        solana_pubkey::pubkey!("Es13uD2p64UVPFpEWfDtd6SERdoNR2XVgqBQBZcZSLqW"),
171        solana_pubkey::pubkey!("AVYpwVou2BhdLivAwLxKPALZQsY7aZNkNmGbP2fZw7RU"),
172        solana_pubkey::pubkey!("DrKzW5koKSZp4mg4BdHLwr72MMXscd2kTiWgckCvvPXz"),
173        solana_pubkey::pubkey!("9hknftBZAQL4f48tWfk3bUEV5YSLcYYtDRqNmpNnhCWG"),
174        solana_pubkey::pubkey!("GLUmCeJpXB8veNcchPwibkRYwCwvQbKodex5mEjrgToi"),
175        solana_pubkey::pubkey!("9S2M3UYPpnPZTBtbcUvehYmiWFK3kBhwfzV2iWuwvaVy"),
176        solana_pubkey::pubkey!("HUAkU5psJXZuw54Lrg1ksbXzHv2fzczQ9sNbmisVMeJU"),
177        solana_pubkey::pubkey!("GK8R4uUmrawcREZ5xJy5dAzVV5V7aFvYg77id37pVTK"),
178        solana_pubkey::pubkey!("4vuWt1oHRqLMhf8Nv1zyEXZsYaeK7dipwrfKLoYU9Riq"),
179        solana_pubkey::pubkey!("EMhn1U3TMimW3bvWYbPUvN2eZnCfsuBN4LGWhzzYhiWR"),
180        solana_pubkey::pubkey!("BsKsunvENxAraBrL77UfAn1Gi7unVEmQAdCbhsjUN6tU"),
181        solana_pubkey::pubkey!("CTvhdUVf8KNyMbyEdnvRrBCHJjBKtQwkbj6zwoqcEssG"),
182        solana_pubkey::pubkey!("3fV2GaDKa3pZxyDcpMh5Vrh2FVAMUiWUKbYmnBFv8As3"),
183        solana_pubkey::pubkey!("4pV47TiPzZ7SSBPHmgUvSLmH9mMSe8tjyPhQZGbi1zPC"),
184        solana_pubkey::pubkey!("P8aKfWQPeRnsZtpBrwWTYzyAoRk74KMz56xc6NEpC4J"),
185        solana_pubkey::pubkey!("HuqDWJodFhAEWh6aWdsDVUqsjRket5DYXMYyDYtD8hdN"),
186        solana_pubkey::pubkey!("Ab1UcdsFXZVnkSt1Z3vcYU65GQk5MvCbs54SviaiaqHb"),
187        solana_pubkey::pubkey!("Dc2oHxFXQaC2QfLStuU7txtD3U5HZ82MrCSGDooWjbsv"),
188        solana_pubkey::pubkey!("3iPvAS4xdhYr6SkhVDHCLr7tJjMAFK4wvvHWJxFQVg15"),
189        solana_pubkey::pubkey!("GmyW1nqYcrw7P7JqrcyP9ivU9hYNbrgZ1r5SYJJH41Fs"),
190        solana_pubkey::pubkey!("E8jcgWvrvV7rwYHJThwfiBeQ8VAH4FgNEEMG9aAuCMAq"),
191        solana_pubkey::pubkey!("CY7X5o3Wi2eQhTocLmUS6JSWyx1NinBfW7AXRrkRCpi8"),
192        solana_pubkey::pubkey!("HQJtLqvEGGxgNYfRXUurfxV8E1swvCnsbC3456ik27HY"),
193        solana_pubkey::pubkey!("9xbcBZoGYFnfJZe81EDuDYKUm8xGkjzW8z4EgnVhNvsv"),
194    ]
195    .into()
196}
197
198// Withdraw authority for autostaked accounts on mainnet-beta
199pub fn withdraw_authority() -> Vec<Pubkey> {
200    [
201        solana_pubkey::pubkey!("8CUUMKYNGxdgYio5CLHRHyzMEhhVRMcqefgE6dLqnVRK"),
202        solana_pubkey::pubkey!("3FFaheyqtyAXZSYxDzsr5CVKvJuvZD1WE1VEsBtDbRqB"),
203        solana_pubkey::pubkey!("FdGYQdiRky8NZzN9wZtczTBcWLYYRXrJ3LMDhqDPn5rM"),
204        solana_pubkey::pubkey!("4e6KwQpyzGQPfgVr5Jn3g5jLjbXB4pKPa2jRLohEb1QA"),
205        solana_pubkey::pubkey!("FjiEiVKyMGzSLpqoB27QypukUfyWHrwzPcGNtopzZVdh"),
206        solana_pubkey::pubkey!("DwbVjia1mYeSGoJipzhaf4L5hfer2DJ1Ys681VzQm5YY"),
207        solana_pubkey::pubkey!("GeMGyvsTEsANVvcT5cme65Xq5MVU8fVVzMQ13KAZFNS2"),
208        solana_pubkey::pubkey!("Bj3aQ2oFnZYfNR1njzRjmWizzuhvfcYLckh76cqsbuBM"),
209        solana_pubkey::pubkey!("4ZJhPQAgUseCsWhKvJLTmmRRUV74fdoTpQLNfKoekbPY"),
210        solana_pubkey::pubkey!("HXdYQ5gixrY2H6Y9gqsD8kPM2JQKSaRiohDQtLbZkRWE"),
211    ]
212    .into()
213}
214
215#[cfg(test)]
216mod tests {
217    use {
218        super::*,
219        crate::genesis_utils::genesis_sysvar_and_builtin_program_lamports,
220        solana_account::{Account, AccountSharedData},
221        solana_epoch_schedule::EpochSchedule,
222        solana_genesis_config::{ClusterType, GenesisConfig},
223        solana_stake_interface::state::{Authorized, Lockup, Meta},
224        std::{collections::BTreeMap, sync::Arc},
225    };
226
227    fn new_from_parent(parent: Arc<Bank>) -> Bank {
228        let slot = parent.slot() + 1;
229        let collector_id = Pubkey::default();
230        Bank::new_from_parent(parent, &collector_id, slot)
231    }
232
233    #[test]
234    fn test_calculate_non_circulating_supply() {
235        let mut accounts: BTreeMap<Pubkey, Account> = BTreeMap::new();
236        let balance = 10;
237        let num_genesis_accounts = 10;
238        for _ in 0..num_genesis_accounts {
239            accounts.insert(
240                solana_pubkey::new_rand(),
241                Account::new(balance, 0, &Pubkey::default()),
242            );
243        }
244        let non_circulating_accounts = non_circulating_accounts();
245        let num_non_circulating_accounts = non_circulating_accounts.len() as u64;
246        for key in non_circulating_accounts.clone() {
247            accounts.insert(key, Account::new(balance, 0, &Pubkey::default()));
248        }
249
250        let num_stake_accounts = 3;
251        for _ in 0..num_stake_accounts {
252            let pubkey = solana_pubkey::new_rand();
253            let meta = Meta {
254                authorized: Authorized::auto(&pubkey),
255                lockup: Lockup {
256                    epoch: 1,
257                    ..Lockup::default()
258                },
259                ..Meta::default()
260            };
261            let stake_account = Account::new_data_with_space(
262                balance,
263                &StakeStateV2::Initialized(meta),
264                StakeStateV2::size_of(),
265                &stake::program::id(),
266            )
267            .unwrap();
268            accounts.insert(pubkey, stake_account);
269        }
270
271        let slots_per_epoch = 32;
272        let genesis_config = GenesisConfig {
273            accounts,
274            epoch_schedule: EpochSchedule::new(slots_per_epoch),
275            cluster_type: ClusterType::MainnetBeta,
276            ..GenesisConfig::default()
277        };
278        let mut bank = Arc::new(Bank::new_for_tests(&genesis_config));
279        assert_eq!(
280            bank.capitalization(),
281            (num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance
282                + genesis_sysvar_and_builtin_program_lamports(),
283        );
284
285        let non_circulating_supply = calculate_non_circulating_supply(&bank).unwrap();
286        assert_eq!(
287            non_circulating_supply.lamports,
288            (num_non_circulating_accounts + num_stake_accounts) * balance
289        );
290        assert_eq!(
291            non_circulating_supply.accounts.len(),
292            num_non_circulating_accounts as usize + num_stake_accounts as usize
293        );
294
295        bank = Arc::new(new_from_parent(bank));
296        let new_balance = 11;
297        for key in non_circulating_accounts {
298            bank.store_account(
299                &key,
300                &AccountSharedData::new(new_balance, 0, &Pubkey::default()),
301            );
302        }
303        let non_circulating_supply = calculate_non_circulating_supply(&bank).unwrap();
304        assert_eq!(
305            non_circulating_supply.lamports,
306            (num_non_circulating_accounts * new_balance) + (num_stake_accounts * balance)
307        );
308        assert_eq!(
309            non_circulating_supply.accounts.len(),
310            num_non_circulating_accounts as usize + num_stake_accounts as usize
311        );
312
313        // Advance bank an epoch, which should unlock stakes
314        for _ in 0..slots_per_epoch {
315            bank = Arc::new(new_from_parent(bank));
316        }
317        assert_eq!(bank.epoch(), 1);
318        let non_circulating_supply = calculate_non_circulating_supply(&bank).unwrap();
319        assert_eq!(
320            non_circulating_supply.lamports,
321            num_non_circulating_accounts * new_balance
322        );
323        assert_eq!(
324            non_circulating_supply.accounts.len(),
325            num_non_circulating_accounts as usize
326        );
327    }
328}