diff --git a/integration_tests/run_postgres.sh b/integration_tests/run_postgres.sh index 95515a52f..308ffe75d 100755 --- a/integration_tests/run_postgres.sh +++ b/integration_tests/run_postgres.sh @@ -5,8 +5,8 @@ IMAGE_NAME="postgres:14" DB_USER="solana" DB_PASSWORD="solana" DB_NAME="solana" -DB_PATH="./db-data" -ROCKS_DUMP_PATH="./rocks_dump" +DB_PATH="$(pwd)/db-data" +ROCKS_DUMP_PATH="$(pwd)/rocks_dump" HOST_PORT="5432" CONTAINER_PORT="5432" diff --git a/integration_tests/src/common.rs b/integration_tests/src/common.rs index 442736d58..2cc02e997 100644 --- a/integration_tests/src/common.rs +++ b/integration_tests/src/common.rs @@ -65,7 +65,7 @@ const API_MAX_PAGE_LIMIT: usize = 100; const DUMP_SYNCHRONIZER_BATCH_SIZE: usize = 1000; const SYNCHRONIZER_PARALLEL_TASKS: usize = 1; -const SYNCHRONIZER_DUMP_PATH: &str = "rocks_dump"; +const SYNCHRONIZER_DUMP_PATH: &str = "./rocks_dump"; const POSTGRE_MIGRATIONS_PATH: &str = "../migrations"; const POSTGRE_BASE_DUMP_PATH: &str = "/aura/integration_tests/"; diff --git a/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq new file mode 100644 index 000000000..767786dfb Binary files /dev/null and b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq differ diff --git a/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v new file mode 100644 index 000000000..505357f6d Binary files /dev/null and b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v differ diff --git a/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/FGETo8T8wMcN2wCjav8VK6eh3dLk63evNDPxzLSJra8B b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/FGETo8T8wMcN2wCjav8VK6eh3dLk63evNDPxzLSJra8B new file mode 100644 index 000000000..37c701ac0 Binary files /dev/null and b/integration_tests/src/data/accounts/fungible_token_mint_freeze_authority/FGETo8T8wMcN2wCjav8VK6eh3dLk63evNDPxzLSJra8B differ diff --git a/integration_tests/src/data/largest_token_account_ids/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v b/integration_tests/src/data/largest_token_account_ids/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v new file mode 100644 index 000000000..c79216f37 --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v @@ -0,0 +1 @@ +ÓêŒõ¬¬¨Í u\CÎõJ]ÙžÞ ¡kU%78ó—Ü \ No newline at end of file diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index e000632d7..dd339e420 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -7,3 +7,4 @@ mod general_scenario_tests; mod mpl_core_tests; mod regular_nft_tests; mod synchronizer_tests; +mod token_tests; diff --git a/integration_tests/src/regular_nft_tests.rs b/integration_tests/src/regular_nft_tests.rs index 6bcd6623b..fbfbe9aff 100644 --- a/integration_tests/src/regular_nft_tests.rs +++ b/integration_tests/src/regular_nft_tests.rs @@ -1,11 +1,18 @@ use std::sync::Arc; -use entities::api_req_params::{GetAsset, GetAssetBatch, GetAssetsByGroup, SearchAssets}; +use entities::{ + api_req_params::{GetAsset, GetAssetBatch, GetAssetsByGroup, SearchAssets}, + enums::AssetType, +}; use function_name::named; use itertools::Itertools; +use nft_ingester::api::dapi::response::AssetList; use rocks_db::storage_traits::AssetIndexReader; use serial_test::serial; -use tokio::{sync::Mutex, task::JoinSet}; +use tokio::{ + sync::{broadcast, Mutex}, + task::JoinSet, +}; use super::common::*; diff --git a/integration_tests/src/snapshots/integration_tests__token_tests__fungible_token_mint_freeze_authority.snap b/integration_tests/src/snapshots/integration_tests__token_tests__fungible_token_mint_freeze_authority.snap new file mode 100644 index 000000000..86e016764 --- /dev/null +++ b/integration_tests/src/snapshots/integration_tests__token_tests__fungible_token_mint_freeze_authority.snap @@ -0,0 +1,73 @@ +--- +source: integration_tests/src/token_tests.rs +assertion_line: 38 +expression: response +snapshot_kind: text +--- +{ + "interface": "Custom", + "id": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "", + "files": [], + "metadata": { + "name": "USD Coin", + "symbol": "USDC" + }, + "links": {} + }, + "authorities": [ + { + "address": "2wmVCSfPxGPjrnMMn7rchp4uaeoTqN39mXFC2zhPdri9", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": 252 + }, + "mutable": true, + "burnt": false, + "lamports": 5616720, + "executable": false, + "metadata_owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", + "rent_epoch": 18446744073709551615, + "token_info": { + "supply": 9342137502207180, + "decimals": 6, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", + "freeze_authority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar" + } +} diff --git a/integration_tests/src/token_tests.rs b/integration_tests/src/token_tests.rs new file mode 100644 index 000000000..ca08989b2 --- /dev/null +++ b/integration_tests/src/token_tests.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; + +use entities::{api_req_params::GetAsset, enums::AssetType}; +use function_name::named; +use itertools::Itertools; +use nft_ingester::api::dapi::response::{AssetList, TokenAccountsList}; +use serial_test::serial; +use tokio::{ + sync::{broadcast, Mutex}, + task::JoinSet, +}; + +use crate::common::{ + index_seed_events, seed_token_mints, trim_test_name, Network, SeedEvent, TestSetup, + TestSetupOptions, +}; + +#[tokio::test] +#[serial] +#[named] +async fn test_fungible_token_mint_freeze_authority() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { network: Some(Network::Mainnet), clear_db: true }, + ) + .await; + + // USDC token + let seeds: Vec = seed_token_mints(&["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"]); + + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" + } + "#; + + let mutexed_tasks = Arc::new(Mutex::new(JoinSet::new())); + + let request: GetAsset = serde_json::from_str(request).unwrap(); + let response_value = setup.das_api.get_asset(request, mutexed_tasks.clone()).await.unwrap(); + let res: AssetList = serde_json::from_value(response_value.clone()).unwrap(); + + insta::assert_json_snapshot!(name, response_value.clone()); + + // assert_eq!( + // res.items[0].clone().token_info.unwrap().mint_authority.unwrap(), + // "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG".to_string() + // ); + // assert_eq!( + // res.items[0].clone().token_info.unwrap().freeze_authority.unwrap(), + // "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar".to_string() + // ); +} diff --git a/nft_ingester/tests/api_tests.rs b/nft_ingester/tests/api_tests.rs index 885a238f8..e81d33231 100644 --- a/nft_ingester/tests/api_tests.rs +++ b/nft_ingester/tests/api_tests.rs @@ -99,28 +99,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, generated_assets) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let limit = 10; @@ -472,28 +451,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -611,28 +569,7 @@ mod tests { async fn test_metadata_sanitizer() { let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, 0, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -760,28 +697,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -876,28 +792,8 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -1043,28 +939,8 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -1212,28 +1088,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -1365,28 +1220,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let first_tree = Pubkey::new_unique(); let second_tree = Pubkey::new_unique(); @@ -1578,28 +1412,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let token_updates_processor = TokenAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); @@ -1793,28 +1606,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let token_updates_processor = TokenAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); @@ -2039,28 +1831,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, generated_assets) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -2096,28 +1867,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, generated_assets) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -2154,28 +1904,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, generated_assets) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -2212,28 +1941,8 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, generated_assets) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); @@ -2461,6 +2170,7 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; + let api = nft_ingester::api::api_impl::DasApi::< MaybeProofChecker, JsonWorker, @@ -2483,6 +2193,7 @@ mod tests { Arc::new(RaydiumTokenPriceFetcher::default()), NATIVE_MINT_PUBKEY.to_string(), ); + let asset_id = Pubkey::new_unique(); let tree_id = Pubkey::new_unique(); env.rocks_env @@ -2514,28 +2225,8 @@ mod tests { let cnt = 20; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + + let api = create_api(&env, None); let asset_fees_count = 1000; let mut asset_ids = Vec::with_capacity(asset_fees_count); for _ in 0..asset_fees_count { @@ -2581,28 +2272,8 @@ mod tests { let total_assets = 2000; let cli = Cli::default(); let (env, _) = setup::TestEnvironment::create(&cli, total_assets, SLOT_UPDATED).await; - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = SearchAssets { @@ -2662,6 +2333,7 @@ mod tests { mock_account_balance_getter .expect_get_account_balance_lamports() .returning(move |_| Ok(10_u64.pow(9))); + let api = nft_ingester::api::api_impl::DasApi::< MaybeProofChecker, JsonWorker, @@ -2684,6 +2356,7 @@ mod tests { Arc::new(RaydiumTokenPriceFetcher::default()), NATIVE_MINT_PUBKEY.to_string(), ); + let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = SearchAssets { @@ -2786,28 +2459,7 @@ mod tests { ); o.await.unwrap(); - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = GetAsset { @@ -2937,28 +2589,7 @@ mod tests { write_version: 1000, }).unwrap(); - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = GetAsset { @@ -2991,6 +2622,211 @@ mod tests { assert_eq!(res.spl20, None); } + #[tokio::test(flavor = "multi_thread")] + async fn test_search_assets_get_all_spec_classes() { + let tasks = JoinSet::new(); + let mutexed_tasks = Arc::new(Mutex::new(tasks)); + + let number_items = 100; + let cli = Cli::default(); + + let (env, generated_assets) = setup::TestEnvironment::create_and_setup_from_closures( + &cli, + number_items, + 100, + &[ + SpecificationAssetClass::Unknown, + SpecificationAssetClass::ProgrammableNft, + SpecificationAssetClass::Nft, + SpecificationAssetClass::FungibleAsset, + SpecificationAssetClass::FungibleToken, + SpecificationAssetClass::MplCoreCollection, + SpecificationAssetClass::MplCoreAsset, + ], + RocksTestEnvironmentSetup::with_authority, + RocksTestEnvironmentSetup::test_one_owner, + RocksTestEnvironmentSetup::dynamic_data, + RocksTestEnvironmentSetup::collection_without_authority, + ) + .await; + + let api = create_api(&env, None); + let owner = generated_assets.owners[0].owner.value.unwrap(); + + let payload = SearchAssets { + limit: Some(1000), + page: Some(1), + owner_address: Some(owner.to_string()), + options: SearchAssetsOptions { + show_unverified_collections: true, + ..Default::default() + }, + token_type: Some(TokenType::All), + ..Default::default() + }; + let res = api.search_assets(payload, mutexed_tasks.clone()).await.unwrap(); + let res: AssetList = serde_json::from_value(res).unwrap(); + + assert_eq!(res.items.len(), number_items); + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_search_assets_freeze_delegate_authorities_for_fungible() { + let tasks = JoinSet::new(); + let mutexed_tasks = Arc::new(Mutex::new(tasks)); + + let number_items = 100; + let cli = Cli::default(); + + let (env, _) = setup::TestEnvironment::create_noise(&cli, number_items, 100).await; + + let fungible_token_mint = Pubkey::new_unique(); + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + let owner = Pubkey::new_unique(); + + let mint = Mint { + pubkey: fungible_token_mint, + supply: 100000, + decimals: 2, + mint_authority: Some(mint_authority.clone()), + freeze_authority: Some(freeze_authority), + token_program: Default::default(), + slot_updated: 10, + write_version: 10, + extensions: None, + }; + + let fungible_token_account = Pubkey::new_unique(); + let delegate = Pubkey::new_unique(); + + let token_account = TokenAccount { + pubkey: fungible_token_account, + mint: fungible_token_mint, + delegate: Some(delegate.clone()), + owner, + extensions: None, + frozen: false, + delegated_amount: 0, + slot_updated: 10, + amount: 0, + write_version: 10, + }; + + let ftm_complete = AssetCompleteDetails { + pubkey: fungible_token_mint, + static_details: Some(AssetStaticDetails { + pubkey: fungible_token_mint, + specification_asset_class: SpecificationAssetClass::FungibleAsset, + royalty_target_type: RoyaltyTargetType::Single, + created_at: 10, + edition_address: None, + }), + owner: Some(AssetOwner { + pubkey: fungible_token_mint, + owner: Updated::new(10, Some(UpdateVersion::WriteVersion(10)), None), + delegate: Default::default(), + owner_type: Default::default(), + owner_delegate_seq: Default::default(), + is_current_owner: Updated::new(12, Some(UpdateVersion::Sequence(12)), true), + }), + ..Default::default() + }; + + env.rocks_env + .storage + .db + .put_cf( + &env.rocks_env.storage.db.cf_handle(AssetCompleteDetails::NAME).unwrap(), + fungible_token_mint, + ftm_complete.convert_to_fb_bytes(), + ) + .unwrap(); + + let mut batch_storage = BatchSaveStorage::new( + env.rocks_env.storage.clone(), + 10, + Arc::new(IngesterMetricsConfig::new()), + ); + + let token_accounts_processor = + TokenAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); + + token_accounts_processor + .transform_and_save_fungible_token_account( + &mut batch_storage, + fungible_token_account, + &token_account, + ) + .unwrap(); + + token_accounts_processor + .transform_and_save_mint_account(&mut batch_storage, &mint) + .unwrap(); + batch_storage.flush().unwrap(); + let (_, rx) = tokio::sync::broadcast::channel::<()>(1); + + let synchronizer = nft_ingester::index_syncronizer::Synchronizer::new( + env.rocks_env.storage.clone(), + env.pg_env.client.clone(), + 200_000, + "".to_string(), + Arc::new(SynchronizerMetricsConfig::new()), + 1, + ); + let synchronizer = Arc::new(synchronizer); + let mut tasks = JoinSet::new(); + + for asset_type in ASSET_TYPES { + let rx = rx.resubscribe(); + let synchronizer = synchronizer.clone(); + match asset_type { + AssetType::Fungible => { + tasks.spawn(async move { + synchronizer.synchronize_fungible_asset_indexes(&rx, 0).await + }); + }, + AssetType::NonFungible => { + tasks.spawn( + async move { synchronizer.synchronize_nft_asset_indexes(&rx, 0).await }, + ); + }, + } + } + while let Some(res) = tasks.join_next().await { + if let Err(err) = res { + panic!("{err}"); + } + } + + let payload = SearchAssets { + limit: Some(1000), + page: Some(1), + owner_address: Some(owner.to_string()), + options: SearchAssetsOptions { + show_zero_balance: true, + show_unverified_collections: true, + ..Default::default() + }, + token_type: Some(TokenType::Fungible), + ..Default::default() + }; + + let api = create_api(&env, None); + let res = api.search_assets(payload, mutexed_tasks.clone()).await.unwrap(); + let res: AssetList = serde_json::from_value(res).unwrap(); + + assert_eq!(res.items.len(), 1); + assert_eq!( + res.items[0].clone().token_info.unwrap().mint_authority.unwrap(), + mint_authority.to_string() + ); + assert_eq!( + res.items[0].clone().token_info.unwrap().freeze_authority.unwrap(), + freeze_authority.to_string() + ); + } + #[tokio::test(flavor = "multi_thread")] async fn test_token_type() { let cnt = 100; @@ -3175,28 +3011,7 @@ mod tests { } } - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = SearchAssets { @@ -3413,28 +3228,7 @@ mod tests { .unwrap(); batch_storage.flush().unwrap(); - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = GetAsset { @@ -3480,7 +3274,7 @@ mod tests { &cli, cnt, 100, - RocksTestEnvironmentSetup::static_data_for_fungible, + &[SpecificationAssetClass::FungibleToken], RocksTestEnvironmentSetup::with_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, @@ -3605,28 +3399,7 @@ mod tests { } } - let api = nft_ingester::api::api_impl::DasApi::< - MaybeProofChecker, - JsonWorker, - JsonWorker, - MockAccountBalanceGetter, - RaydiumTokenPriceFetcher, - Storage, - >::new( - env.pg_env.client.clone(), - env.rocks_env.storage.clone(), - Arc::new(ApiMetricsConfig::new()), - None, - None, - 50, - None, - None, - JsonMiddlewareConfig::default(), - Arc::new(MockAccountBalanceGetter::new()), - None, - Arc::new(RaydiumTokenPriceFetcher::default()), - NATIVE_MINT_PUBKEY.to_string(), - ); + let api = create_api(&env, None); let tasks = JoinSet::new(); let mutexed_tasks = Arc::new(Mutex::new(tasks)); let payload = SearchAssets { @@ -3916,4 +3689,32 @@ mod tests { assert_eq!(idx_fungible_asset_iter.count(), 6); assert_eq!(idx_non_fungible_asset_iter.count(), 6); } + + fn create_api( + env: &setup::TestEnvironment, + json_middleware_config: Option, + ) -> nft_ingester::api::api_impl::DasApi< + MaybeProofChecker, + JsonWorker, + JsonWorker, + MockAccountBalanceGetter, + RaydiumTokenPriceFetcher, + Storage, + > { + nft_ingester::api::api_impl::DasApi::new( + env.pg_env.client.clone(), + env.rocks_env.storage.clone(), + Arc::new(ApiMetricsConfig::new()), + None, + None, + 50, + None, + None, + json_middleware_config.unwrap_or(JsonMiddlewareConfig::default()), + Arc::new(MockAccountBalanceGetter::new()), + None, + Arc::new(RaydiumTokenPriceFetcher::default()), + NATIVE_MINT_PUBKEY.to_string(), + ) + } } diff --git a/nft_ingester/tests/dump_tests.rs b/nft_ingester/tests/dump_tests.rs index 9d8e3393e..c31a82b99 100644 --- a/nft_ingester/tests/dump_tests.rs +++ b/nft_ingester/tests/dump_tests.rs @@ -123,7 +123,10 @@ mod tests { mod mtg_441_tests { use std::sync::Arc; - use entities::api_req_params::{GetAsset, Options}; + use entities::{ + api_req_params::{GetAsset, Options}, + enums::SpecificationAssetClass, + }; use interface::account_balance::MockAccountBalanceGetter; use metrics_utils::ApiMetricsConfig; use nft_ingester::{ @@ -189,7 +192,7 @@ mod mtg_441_tests { &cli, 20, SLOT_UPDATED, - RocksTestEnvironmentSetup::static_data_for_mpl, + &[SpecificationAssetClass::MplCoreAsset], RocksTestEnvironmentSetup::without_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, @@ -225,7 +228,7 @@ mod mtg_441_tests { &cli, 20, SLOT_UPDATED, - RocksTestEnvironmentSetup::static_data_for_mpl, + &[SpecificationAssetClass::MplCoreAsset], RocksTestEnvironmentSetup::with_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, @@ -260,7 +263,7 @@ mod mtg_441_tests { &cli, 20, SLOT_UPDATED, - RocksTestEnvironmentSetup::static_data_for_mpl, + &[SpecificationAssetClass::MplCoreAsset], RocksTestEnvironmentSetup::with_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, @@ -291,11 +294,11 @@ mod mtg_441_tests { #[tracing_test::traced_test] async fn authority_none_collection_authority_none() { let cli = Cli::default(); - let (env, generated_assets) = setup::TestEnvironment::create_and_setup_from_closures( + let (env, generated_assets) = TestEnvironment::create_and_setup_from_closures( &cli, 20, SLOT_UPDATED, - RocksTestEnvironmentSetup::static_data_for_mpl, + &[SpecificationAssetClass::MplCoreAsset], RocksTestEnvironmentSetup::without_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, diff --git a/tests/setup/src/lib.rs b/tests/setup/src/lib.rs index 927f12323..18b9f684a 100644 --- a/tests/setup/src/lib.rs +++ b/tests/setup/src/lib.rs @@ -4,11 +4,9 @@ pub mod rocks; use std::sync::Arc; -use entities::enums::{AssetType, ASSET_TYPES}; +use entities::enums::{AssetType, SpecificationAssetClass, ASSET_TYPES}; use metrics_utils::MetricsTrait; -use rocks_db::columns::asset::{ - AssetAuthority, AssetCollection, AssetDynamicDetails, AssetOwner, AssetStaticDetails, -}; +use rocks_db::columns::asset::{AssetAuthority, AssetCollection, AssetDynamicDetails, AssetOwner}; use solana_sdk::pubkey::Pubkey; use testcontainers::clients::Cli; use tokio::task::JoinSet; @@ -30,7 +28,33 @@ impl<'a> TestEnvironment<'a> { cli, cnt, slot, - RocksTestEnvironmentSetup::static_data_for_nft, + &[SpecificationAssetClass::Nft], + RocksTestEnvironmentSetup::with_authority, + RocksTestEnvironmentSetup::test_owner, + RocksTestEnvironmentSetup::dynamic_data, + RocksTestEnvironmentSetup::collection_without_authority, + ) + .await + } + + pub async fn create_noise( + cli: &'a Cli, + cnt: usize, + slot: u64, + ) -> (TestEnvironment<'a>, rocks::GeneratedAssets) { + Self::create_and_setup_from_closures( + cli, + cnt, + slot, + &[ + SpecificationAssetClass::Unknown, + SpecificationAssetClass::ProgrammableNft, + SpecificationAssetClass::Nft, + SpecificationAssetClass::FungibleAsset, + SpecificationAssetClass::FungibleToken, + SpecificationAssetClass::MplCoreCollection, + SpecificationAssetClass::MplCoreAsset, + ], RocksTestEnvironmentSetup::with_authority, RocksTestEnvironmentSetup::test_owner, RocksTestEnvironmentSetup::dynamic_data, @@ -44,7 +68,7 @@ impl<'a> TestEnvironment<'a> { cli: &'a Cli, cnt: usize, slot: u64, - static_details: fn(&[Pubkey], u64) -> Vec, + spec_asset_class_list: &[SpecificationAssetClass], authorities: fn(&[Pubkey]) -> Vec, owners: fn(&[Pubkey]) -> Vec, dynamic_details: fn(&[Pubkey], u64) -> Vec, @@ -57,7 +81,7 @@ impl<'a> TestEnvironment<'a> { .generate_from_closure( cnt, slot, - static_details, + spec_asset_class_list, authorities, owners, dynamic_details, diff --git a/tests/setup/src/rocks.rs b/tests/setup/src/rocks.rs index 8b2fd08d2..7ae982e8e 100644 --- a/tests/setup/src/rocks.rs +++ b/tests/setup/src/rocks.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use entities::{enums::SpecificationAssetClass, models::Updated}; use metrics_utils::red::RequestErrorDurationMetrics; -use rand::{random, Rng}; +use rand::{random, seq::SliceRandom, Rng}; use rocks_db::{ column::TypedColumn, columns::{ @@ -78,14 +78,21 @@ impl RocksTestEnvironment { &self, cnt: usize, slot: u64, - static_details: fn(&[Pubkey], u64) -> Vec, + spec_asset_class_list: &[SpecificationAssetClass], authorities: fn(&[Pubkey]) -> Vec, owners: fn(&[Pubkey]) -> Vec, dynamic_details: fn(&[Pubkey], u64) -> Vec, collections: fn(&[Pubkey]) -> Vec, ) -> GeneratedAssets { let pubkeys = (0..cnt).map(|_| self.generate_and_store_pubkey(slot)).collect::>(); - let static_details = static_details(&pubkeys, slot); + let static_details = + spec_asset_class_list.iter().cycle().take(cnt).cloned().collect::>(); + + let asset_static_details = RocksTestEnvironmentSetup::generate_static_data_with_asset_list( + &pubkeys, + cnt as u64, + &static_details, + ); let authorities = authorities(&pubkeys); let owners = owners(&pubkeys); let dynamic_details = dynamic_details(&pubkeys, slot); @@ -93,7 +100,7 @@ impl RocksTestEnvironment { let assets = GeneratedAssets { pubkeys, - static_details, + static_details: asset_static_details, authorities, owners, dynamic_details, @@ -131,6 +138,44 @@ impl RocksTestEnvironment { assets } + /// spec_asset_class_list: list of available Asset Classes that generator will use for generated data. + pub async fn generate_assets_with_specification_classes( + &self, + cnt: usize, + slot: u64, + spec_asset_class_list: Vec, + ) -> GeneratedAssets { + let mut rng = rand::thread_rng(); + let pubkeys = (0..cnt).map(|_| self.generate_and_store_pubkey(slot)).collect::>(); + let static_details = + spec_asset_class_list.choose_multiple(&mut rng, cnt).cloned().collect::>(); + + let static_details = RocksTestEnvironmentSetup::generate_static_data_with_asset_list( + &pubkeys, + slot, + &static_details, + ); + let authorities = RocksTestEnvironmentSetup::with_authority(&pubkeys); + let owners = RocksTestEnvironmentSetup::test_owner(&pubkeys); + let dynamic_details = RocksTestEnvironmentSetup::dynamic_data(&pubkeys, slot); + let collections = RocksTestEnvironmentSetup::collection_without_authority(&pubkeys); + + let assets = GeneratedAssets { + pubkeys, + static_details, + authorities, + owners, + dynamic_details, + collections, + }; + + self.put_everything_in_the_database(&assets) + .await + .expect("Cannot store 'GeneratedAssets' into storage."); + + assets + } + fn generate_and_store_pubkey(&self, slot: u64) -> Pubkey { let pubkey = Pubkey::new_unique(); self.storage.asset_updated(slot, pubkey).expect("Cannot update assets."); @@ -196,10 +241,6 @@ impl RocksTestEnvironmentSetup { Self::generate_static_data(pubkeys, slot, SpecificationAssetClass::Nft) } - pub fn static_data_for_fungible(pubkeys: &[Pubkey], slot: u64) -> Vec { - Self::generate_static_data(pubkeys, slot, SpecificationAssetClass::FungibleToken) - } - fn generate_static_data( pubkeys: &[Pubkey], slot: u64, @@ -217,6 +258,24 @@ impl RocksTestEnvironmentSetup { .collect() } + fn generate_static_data_with_asset_list( + pubkeys: &[Pubkey], + slot: u64, + spec_asset_class_list: &[SpecificationAssetClass], + ) -> Vec { + pubkeys + .iter() + .zip(spec_asset_class_list.iter()) + .map(|(pubkey, spec_class)| AssetStaticDetails { + pubkey: *pubkey, + created_at: slot as i64, + specification_asset_class: *spec_class, + royalty_target_type: entities::enums::RoyaltyTargetType::Creators, + edition_address: Default::default(), + }) + .collect() + } + pub fn without_authority(_: &[Pubkey]) -> Vec { Vec::new() } @@ -249,6 +308,23 @@ impl RocksTestEnvironmentSetup { .collect() } + pub fn test_one_owner(pubkeys: &[Pubkey]) -> Vec { + let owner_uuid = Pubkey::new_unique(); + pubkeys + .iter() + .map(|pubkey| AssetOwner { + pubkey: *pubkey, + owner: generate_test_updated(Some(owner_uuid)), + owner_type: generate_test_updated(entities::enums::OwnerType::Single), + owner_delegate_seq: generate_test_updated(Some( + rand::thread_rng().gen_range(0..100), + )), + delegate: generate_test_updated(Some(Pubkey::new_unique())), + is_current_owner: generate_test_updated(true), + }) + .collect() + } + pub fn dynamic_data(pubkeys: &[Pubkey], slot: u64) -> Vec { pubkeys .iter()