From 75af1ceecbaadf5c6f38790da15649596cd8eb41 Mon Sep 17 00:00:00 2001 From: Juanito Date: Mon, 2 Oct 2023 16:14:53 -0300 Subject: [PATCH] Main (#104) * Fix raw name build (#122) * Added fetch trees tool (#123) Fetches a list of trees from an RPC endpoint. --------- Co-authored-by: Linus Kendall --- Cargo.lock | 38 ++++---- Cargo.toml | 1 + .../m20230918_182123_add_raw_name_symbol.rs | 1 + tools/fetch_trees/Cargo.toml | 17 ++++ tools/fetch_trees/src/main.rs | 88 +++++++++++++++++++ 5 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 tools/fetch_trees/Cargo.toml create mode 100644 tools/fetch_trees/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 285d7653e..506d0129d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ dependencies = [ "log", "mpl-token-metadata", "plerkle_messenger", - "plerkle_serialization 1.5.3", + "plerkle_serialization", "prometheus", "reqwest", "serde_json", @@ -715,7 +715,7 @@ dependencies = [ "mpl-candy-guard", "mpl-candy-machine-core", "mpl-token-metadata", - "plerkle_serialization 1.5.2", + "plerkle_serialization", "solana-sdk", "spl-account-compression", "spl-noop", @@ -1756,6 +1756,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "fetch_trees" +version = "0.7.12" +dependencies = [ + "anyhow", + "async-trait", + "borsh 0.9.3", + "clap 4.2.2", + "mpl-bubblegum", + "solana-account-decoder", + "solana-client", + "solana-sdk", + "spl-account-compression", + "tokio", +] + [[package]] name = "figment" version = "0.10.8" @@ -2846,7 +2862,7 @@ dependencies = [ "num-integer", "num-traits", "plerkle_messenger", - "plerkle_serialization 1.5.2", + "plerkle_serialization", "rand 0.8.5", "redis", "regex", @@ -3350,20 +3366,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "plerkle_serialization" -version = "1.5.3" -source = "git+https://github.com/metaplex-foundation/digital-asset-validator-plugin.git?rev=35a8801c#35a8801cebd2eba2a343e1c051dddcb506284061" -dependencies = [ - "bs58 0.4.0", - "chrono", - "flatbuffers", - "serde", - "solana-sdk", - "solana-transaction-status", - "thiserror", -] - [[package]] name = "polling" version = "2.6.0" @@ -6030,7 +6032,7 @@ dependencies = [ "lazy_static", "log", "plerkle_messenger", - "plerkle_serialization 1.5.3", + "plerkle_serialization", "prometheus", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 4028d7fb3..e335b5f99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "nft_ingester", "tools/acc_forwarder", "tools/bgtask_creator", + "tools/fetch_trees", "tools/load_generation", "tools/tree-status", "tools/txn_forwarder", diff --git a/migration/src/m20230918_182123_add_raw_name_symbol.rs b/migration/src/m20230918_182123_add_raw_name_symbol.rs index 88d488911..6851e871e 100644 --- a/migration/src/m20230918_182123_add_raw_name_symbol.rs +++ b/migration/src/m20230918_182123_add_raw_name_symbol.rs @@ -1,3 +1,4 @@ +use digital_asset_types::dao::asset_data; use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] diff --git a/tools/fetch_trees/Cargo.toml b/tools/fetch_trees/Cargo.toml new file mode 100644 index 000000000..e97671dcf --- /dev/null +++ b/tools/fetch_trees/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "fetch_trees" +version = "0.7.12" +edition = "2021" +publish = false + +[dependencies] +anyhow = "1.0.70" +async-trait = "0.1.53" +borsh = "0.9.1" +clap = { version = "4.2.2", features = ["derive", "cargo"] } +mpl-bubblegum = { git = "https://github.com/metaplex-foundation/mpl-bubblegum.git", rev = "3cb3976d", features = ["no-entrypoint"] } +solana-account-decoder = "~1.14" +solana-client = "~1.14" +solana-sdk = "~1.14" +spl-account-compression = "0.1.8" +tokio = { version = "1.26.0", features = ["full", "tracing"] } diff --git a/tools/fetch_trees/src/main.rs b/tools/fetch_trees/src/main.rs new file mode 100644 index 000000000..9bfad437b --- /dev/null +++ b/tools/fetch_trees/src/main.rs @@ -0,0 +1,88 @@ +use { + borsh::{BorshDeserialize, BorshSerialize}, + clap::Parser, + solana_account_decoder::UiAccountEncoding, + solana_client::{ + nonblocking::rpc_client::RpcClient, + rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, + rpc_filter::{Memcmp, RpcFilterType}, + rpc_request::MAX_MULTIPLE_ACCOUNTS, + }, + solana_sdk::{ + account::Account, + pubkey::{Pubkey, PUBKEY_BYTES}, + }, + spl_account_compression::state::{ConcurrentMerkleTreeHeader, ConcurrentMerkleTreeHeaderData}, +}; + +#[derive(Debug, Parser)] +struct Args { + // Solana RPC endpoint + #[arg(long, short)] + rpc: String, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let client = RpcClient::new(args.rpc); + + // Initialized SPL Account Compression accounts + let config = RpcProgramAccountsConfig { + filters: Some(vec![RpcFilterType::Memcmp(Memcmp::new_raw_bytes( + 0, + vec![1u8], + ))]), + account_config: RpcAccountInfoConfig { + encoding: Some(UiAccountEncoding::Base64), + ..Default::default() + }, + ..Default::default() + }; + let accounts: Vec<(Pubkey, Account)> = client + .get_program_accounts_with_config(&spl_account_compression::id(), config) + .await?; + println!("Received {} accounts", accounts.len()); + + // Trying to extract authority pubkey + let accounts = accounts + .into_iter() + .filter_map(|(pubkey, account)| { + get_authority(&account.data) + .ok() + .map(|authority| (pubkey, authority)) + }) + .collect::>(); + println!("Successfully parsed {} accounts", accounts.len()); + + // Print only accounts where authority owner is bubblegum + let mut id = 1; + for accounts in accounts.chunks(MAX_MULTIPLE_ACCOUNTS) { + let pubkeys = accounts + .iter() + .map(|(_pubkey, authority)| *authority) + .collect::>(); + let authority_accounts = client.get_multiple_accounts(pubkeys.as_slice()).await?; + for (authority_account, (pubkey, _authority)) in authority_accounts.iter().zip(accounts) { + if let Some(account) = authority_account { + if account.owner == mpl_bubblegum::id() { + println!("{} {}", id, pubkey); + id += 1; + } + } + } + } + + Ok(()) +} + +fn get_authority(mut data: &[u8]) -> anyhow::Result { + // additional checks + let header = ConcurrentMerkleTreeHeader::deserialize(&mut data)?; + let ConcurrentMerkleTreeHeaderData::V1(header) = header.header; + let data = header.try_to_vec()?; + + let offset = 4 + 4; + Pubkey::try_from(&data[offset..offset + PUBKEY_BYTES]).map_err(Into::into) +}