From 702b7a3574695d842a0431b38894a22823d7fea3 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:08:27 -0800 Subject: [PATCH 1/2] Remove Candy Machine V2 and V3 parsing --- Cargo.lock | 59 --- blockbuster/Cargo.toml | 2 - blockbuster/src/programs/candy_guard/mod.rs | 83 ---- blockbuster/src/programs/candy_machine/mod.rs | 91 ---- .../src/programs/candy_machine/state.rs | 123 ------ .../src/programs/candy_machine_core/mod.rs | 68 --- blockbuster/src/programs/mod.rs | 24 +- .../tests/candy_machine_parser_test.rs | 388 ------------------ 8 files changed, 15 insertions(+), 823 deletions(-) delete mode 100644 blockbuster/src/programs/candy_guard/mod.rs delete mode 100644 blockbuster/src/programs/candy_machine/mod.rs delete mode 100644 blockbuster/src/programs/candy_machine/state.rs delete mode 100644 blockbuster/src/programs/candy_machine_core/mod.rs delete mode 100644 blockbuster/tests/candy_machine_parser_test.rs diff --git a/Cargo.lock b/Cargo.lock index bd3b57c..9570f0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -652,8 +652,6 @@ dependencies = [ "lazy_static", "log", "mpl-bubblegum", - "mpl-candy-guard", - "mpl-candy-machine-core", "mpl-token-metadata", "plerkle_serialization", "rand 0.8.5", @@ -2169,50 +2167,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "mpl-candy-guard" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c5c2ffb233226e0c531f1cf800909e46120e98722eeb53dae68b0996303a38" -dependencies = [ - "anchor-lang", - "arrayref", - "mpl-candy-guard-derive", - "mpl-candy-machine-core", - "mpl-token-auth-rules", - "mpl-token-metadata", - "solana-gateway", - "solana-program", - "spl-associated-token-account", - "spl-token 4.0.0", - "spl-token-2022 0.9.0", -] - -[[package]] -name = "mpl-candy-guard-derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4d3002ea881e94a238798faf87a006a687297a24bd4b3f810fbb63611173d" -dependencies = [ - "quote 1.0.33", - "syn 1.0.109", -] - -[[package]] -name = "mpl-candy-machine-core" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db99e1aac3bdebf907338aec5f1785701b8a82e6bdac5f42a270750d37c5264" -dependencies = [ - "anchor-lang", - "arrayref", - "mpl-token-auth-rules", - "mpl-token-metadata", - "solana-program", - "spl-associated-token-account", - "spl-token 4.0.0", -] - [[package]] name = "mpl-token-auth-rules" version = "1.4.3" @@ -3676,19 +3630,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "solana-gateway" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d148eb75d0799f6825dc2a840b85c065e3d6d12212845add3e059163f98770e" -dependencies = [ - "borsh 0.10.3", - "num-derive 0.4.1", - "num-traits", - "solana-program", - "thiserror", -] - [[package]] name = "solana-geyser-plugin-interface" version = "1.16.16" diff --git a/blockbuster/Cargo.toml b/blockbuster/Cargo.toml index 21cb2ec..59a245b 100644 --- a/blockbuster/Cargo.toml +++ b/blockbuster/Cargo.toml @@ -12,8 +12,6 @@ readme = "../README.md" spl-account-compression = { version = "0.2.0", features = ["no-entrypoint"] } spl-noop = { version = "0.2.0", features = ["no-entrypoint"] } mpl-bubblegum = "=1.0.1-beta.4" -mpl-candy-guard = { version = "2.0.0", features = ["no-entrypoint"] } -mpl-candy-machine-core = { version = "2.0.0", features = ["no-entrypoint"] } mpl-token-metadata = { version = "2.0.0-beta.1", features = ["no-entrypoint", "serde-feature"] } plerkle_serialization = { version = "1.6.0" } spl-token = { version = "4.0.0", features = ["no-entrypoint"] } diff --git a/blockbuster/src/programs/candy_guard/mod.rs b/blockbuster/src/programs/candy_guard/mod.rs deleted file mode 100644 index 5cb46f7..0000000 --- a/blockbuster/src/programs/candy_guard/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::{ - error::BlockbusterError, - program_handler::{ParseResult, ProgramParser}, - programs::ProgramParseResult, -}; -use mpl_candy_guard::{ - guards::MintCounter, - state::{CandyGuard, CandyGuardData, DATA_OFFSET}, -}; -use plerkle_serialization::AccountInfo; -use solana_sdk::{borsh0_10::try_from_slice_unchecked, pubkey::Pubkey, pubkeys}; -use std::convert::TryInto; - -pubkeys!( - candy_guard_id, - "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g" -); - -// Anchor account discriminators. -const CANDY_GUARD_DISCRIMINATOR: [u8; 8] = [44, 207, 199, 184, 112, 103, 34, 181]; -const MINT_COUNTER_DISCRIMINATOR: [u8; 8] = [29, 59, 15, 69, 46, 22, 227, 173]; - -pub enum CandyGuardAccountData { - CandyGuard(CandyGuard, Box), - MintCounter(MintCounter), -} - -impl ParseResult for CandyGuardAccountData { - fn result_type(&self) -> ProgramParseResult { - ProgramParseResult::CandyGuard(self) - } -} - -pub struct CandyGuardParser; - -impl ProgramParser for CandyGuardParser { - fn key(&self) -> Pubkey { - candy_guard_id() - } - - fn key_match(&self, key: &Pubkey) -> bool { - key == &candy_guard_id() - } - fn handles_account_updates(&self) -> bool { - true - } - - fn handles_instructions(&self) -> bool { - false - } - fn handle_account( - &self, - account_info: &AccountInfo, - ) -> Result, BlockbusterError> { - let account_data = if let Some(account_info) = account_info.data() { - account_info.iter().collect::>() - } else { - return Err(BlockbusterError::DeserializationError); - }; - - let discriminator: [u8; 8] = account_data[0..8].try_into().unwrap(); - - let account_type = match discriminator { - CANDY_GUARD_DISCRIMINATOR => { - let candy_guard = try_from_slice_unchecked(&account_data[8..])?; - let candy_guard_data = - CandyGuardData::load(&account_data[DATA_OFFSET..]).map_err(|_| { - BlockbusterError::CustomDeserializationError( - "Candy Guard Data Deserialization Error".to_string(), - ) - })?; - CandyGuardAccountData::CandyGuard(candy_guard, candy_guard_data) - } - MINT_COUNTER_DISCRIMINATOR => { - let mint_counter = try_from_slice_unchecked(&account_data[8..])?; - CandyGuardAccountData::MintCounter(mint_counter) - } - _ => return Err(BlockbusterError::UnknownAccountDiscriminator), - }; - - Ok(Box::new(account_type)) - } -} diff --git a/blockbuster/src/programs/candy_machine/mod.rs b/blockbuster/src/programs/candy_machine/mod.rs deleted file mode 100644 index 5aabc34..0000000 --- a/blockbuster/src/programs/candy_machine/mod.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::{ - error::BlockbusterError, - program_handler::{ParseResult, ProgramParser}, - programs::{ - candy_machine::state::{CandyMachine, CollectionPDA, FreezePDA}, - ProgramParseResult, - }, -}; -use plerkle_serialization::AccountInfo; -use solana_sdk::{borsh0_10::try_from_slice_unchecked, pubkey::Pubkey, pubkeys}; -use std::convert::TryInto; - -pub mod state; - -pubkeys!( - candy_machine_id, - "cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ" -); - -// Anchor account discriminators. -pub const CANDY_MACHINE_DISCRIMINATOR: [u8; 8] = [51, 173, 177, 113, 25, 241, 109, 189]; -pub const COLLECTION_PDA_DISCRIMINATOR: [u8; 8] = [203, 128, 119, 125, 234, 89, 232, 157]; -pub const FREEZE_PDA_DISCRIMINATOR: [u8; 8] = [154, 58, 148, 24, 101, 200, 243, 127]; - -#[allow(clippy::large_enum_variant)] -pub enum CandyMachineAccountData { - CandyMachine(CandyMachine), - CollectionPDA(CollectionPDA), - FreezePDA(FreezePDA), -} - -impl ParseResult for CandyMachineAccountData { - fn result(&self) -> &Self - where - Self: Sized, - { - self - } - fn result_type(&self) -> ProgramParseResult { - ProgramParseResult::CandyMachine(self) - } -} - -pub struct CandyMachineParser; - -impl ProgramParser for CandyMachineParser { - fn key(&self) -> Pubkey { - candy_machine_id() - } - - fn key_match(&self, key: &Pubkey) -> bool { - key == &candy_machine_id() - } - fn handles_account_updates(&self) -> bool { - true - } - - fn handles_instructions(&self) -> bool { - false - } - fn handle_account( - &self, - account_info: &AccountInfo, - ) -> Result, BlockbusterError> { - let account_data = if let Some(account_info) = account_info.data() { - account_info.iter().collect::>() - } else { - return Err(BlockbusterError::DeserializationError); - }; - - let discriminator: [u8; 8] = account_data[0..8].try_into().unwrap(); - - let account_type = match discriminator { - CANDY_MACHINE_DISCRIMINATOR => { - let candy_machine = try_from_slice_unchecked(&account_data[8..])?; - CandyMachineAccountData::CandyMachine(candy_machine) - } - COLLECTION_PDA_DISCRIMINATOR => { - let collection_pda = try_from_slice_unchecked(&account_data[8..])?; - CandyMachineAccountData::CollectionPDA(collection_pda) - } - FREEZE_PDA_DISCRIMINATOR => { - let freeze_pda = try_from_slice_unchecked(&account_data[8..])?; - CandyMachineAccountData::FreezePDA(freeze_pda) - } - _ => return Err(BlockbusterError::UnknownAccountDiscriminator), - }; - - Ok(Box::new(account_type)) - } -} diff --git a/blockbuster/src/programs/candy_machine/state.rs b/blockbuster/src/programs/candy_machine/state.rs deleted file mode 100644 index f3d9f27..0000000 --- a/blockbuster/src/programs/candy_machine/state.rs +++ /dev/null @@ -1,123 +0,0 @@ -/// These are copied over from mpl-candy-machine due to current Solana/Anchor version conflict -/// between that program and mpl-bubblegum, spl-account-compression, and spl-noop. -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_sdk::pubkey::Pubkey; - -/// Candy machine state and config data. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Default, Debug, Clone)] -pub struct CandyMachine { - pub authority: Pubkey, - pub wallet: Pubkey, - pub token_mint: Option, - pub items_redeemed: u64, - pub data: CandyMachineData, - // there's a borsh vec u32 denoting how many actual lines of data there are currently (eventually equals items available) - // There is actually lines and lines of data after this but we explicitly never want them deserialized. - // here there is a borsh vec u32 indicating number of bytes in bitmask array. - // here there is a number of bytes equal to ceil(max_number_of_lines/8) and it is a bit mask used to figure out when to increment borsh vec u32 -} - -/// Collection PDA account -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Default, Debug, Clone)] -pub struct CollectionPDA { - pub mint: Pubkey, - pub candy_machine: Pubkey, -} - -/// Collection PDA account -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Default, Debug, Clone)] -pub struct FreezePDA { - // duplicate key in order to find the candy machine without txn crawling - pub candy_machine: Pubkey, // 32 - pub allow_thaw: bool, // 1 - pub frozen_count: u64, // 8 - pub mint_start: Option, // 1 + 8 - pub freeze_time: i64, // 8 - pub freeze_fee: u64, // 8 -} - -/// Candy machine settings data. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Default, Debug, Clone)] -pub struct CandyMachineData { - pub uuid: String, - pub price: u64, - /// The symbol for the asset - pub symbol: String, - /// Royalty basis points that goes to creators in secondary sales (0-10000) - pub seller_fee_basis_points: u16, - pub max_supply: u64, - pub is_mutable: bool, - pub retain_authority: bool, - pub go_live_date: Option, - pub end_settings: Option, - pub creators: Vec, - pub hidden_settings: Option, - pub whitelist_mint_settings: Option, - pub items_available: u64, - /// If [`Some`] requires gateway tokens on mint - pub gatekeeper: Option, -} - -/// Individual config line for storing NFT data pre-mint. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct ConfigLine { - pub name: String, - /// URI pointing to JSON representing the asset - pub uri: String, -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct EndSettings { - pub end_setting_type: EndSettingType, - pub number: u64, -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub enum EndSettingType { - Date, - Amount, -} - -// Unfortunate duplication of token metadata so that IDL picks it up. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct Creator { - pub address: Pubkey, - pub verified: bool, - // In percentages, NOT basis points ;) Watch out! - pub share: u8, -} - -/// Hidden Settings for large mints used with offline data. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct HiddenSettings { - pub name: String, - pub uri: String, - pub hash: [u8; 32], -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct WhitelistMintSettings { - pub mode: WhitelistMintMode, - pub mint: Pubkey, - pub presale: bool, - pub discount_price: Option, -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] -pub enum WhitelistMintMode { - // Only captcha uses the bytes, the others just need to have same length - // for front end borsh to not crap itself - // Holds the validation window - BurnEveryTime, - NeverBurn, -} - -/// Configurations options for the gatekeeper. -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Default, Debug, Clone)] -pub struct GatekeeperConfig { - /// The network for the gateway token required - pub gatekeeper_network: Pubkey, - /// Whether or not the token should expire after minting. - /// The gatekeeper network must support this if true. - pub expire_on_use: bool, -} diff --git a/blockbuster/src/programs/candy_machine_core/mod.rs b/blockbuster/src/programs/candy_machine_core/mod.rs deleted file mode 100644 index daea16b..0000000 --- a/blockbuster/src/programs/candy_machine_core/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::{ - error::BlockbusterError, - program_handler::{ParseResult, ProgramParser}, - programs::ProgramParseResult, -}; -use mpl_candy_machine_core::CandyMachine; -use plerkle_serialization::AccountInfo; -use solana_sdk::{borsh0_10::try_from_slice_unchecked, pubkey::Pubkey, pubkeys}; -use std::convert::TryInto; - -pubkeys!( - candy_machine_core_id, - "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR" -); - -// Anchor account discriminators. -const CANDY_MACHINE_DISCRIMINATOR: [u8; 8] = [51, 173, 177, 113, 25, 241, 109, 189]; - -pub enum CandyMachineCoreAccountData { - CandyMachineCore(CandyMachine), -} - -impl ParseResult for CandyMachineCoreAccountData { - fn result_type(&self) -> ProgramParseResult { - ProgramParseResult::CandyMachineCore(self) - } -} - -pub struct CandyMachineParser; - -impl ProgramParser for CandyMachineParser { - fn key(&self) -> Pubkey { - candy_machine_core_id() - } - - fn key_match(&self, key: &Pubkey) -> bool { - key == &candy_machine_core_id() - } - fn handles_account_updates(&self) -> bool { - true - } - - fn handles_instructions(&self) -> bool { - false - } - fn handle_account( - &self, - account_info: &AccountInfo, - ) -> Result, BlockbusterError> { - let account_data = if let Some(account_info) = account_info.data() { - account_info.iter().collect::>() - } else { - return Err(BlockbusterError::DeserializationError); - }; - - let discriminator: [u8; 8] = account_data[0..8].try_into().unwrap(); - - let account_type = match discriminator { - CANDY_MACHINE_DISCRIMINATOR => { - let candy_machine = try_from_slice_unchecked(&account_data[8..])?; - CandyMachineCoreAccountData::CandyMachineCore(candy_machine) - } - _ => return Err(BlockbusterError::UnknownAccountDiscriminator), - }; - - Ok(Box::new(account_type)) - } -} diff --git a/blockbuster/src/programs/mod.rs b/blockbuster/src/programs/mod.rs index 46aa0f0..1a47036 100644 --- a/blockbuster/src/programs/mod.rs +++ b/blockbuster/src/programs/mod.rs @@ -1,23 +1,29 @@ use bubblegum::BubblegumInstruction; -use candy_guard::CandyGuardAccountData; -use candy_machine::CandyMachineAccountData; -use candy_machine_core::CandyMachineCoreAccountData; use token_account::TokenProgramAccount; use token_metadata::TokenMetadataAccountState; pub mod bubblegum; -pub mod candy_guard; -pub mod candy_machine; -pub mod candy_machine_core; pub mod token_account; pub mod token_metadata; +// Note: `ProgramParseResult` used to contain the following variants that have been deprecated and +// removed from blockbuster since the `version-1.16` tag of blockbuster: +// CandyGuard(&'a CandyGuardAccountData), +// CandyMachine(&'a CandyMachineAccountData), +// CandyMachineCore(&'a CandyMachineCoreAccountData), +// +// The reason Candy Machine V3 parsing was removed was because Candy Guard (`mpl-candy-guard`) and +// Candy Machine V3 (`mpl-candy-machine-core`) were dependent upon a specific Solana version (1.16) +// at the time, there was no Candy Machine parsing in DAS (`digital-asset-rpc-infrastructure`), and +// we wanted to use the Rust clients for Token Metadata and Bubblegum so that going forward we could +// more easily update blockbuster to new Solana versions going forward. +// +// Candy Machine V2 (`mpl-candy-machine`) parsing did not depend on the `mpl-candy-machine` crate +// as its types were copied, but we removed V2 parsing at the same time as V3 parsing as it was not +// being used. pub enum ProgramParseResult<'a> { Bubblegum(&'a BubblegumInstruction), TokenMetadata(&'a TokenMetadataAccountState), TokenProgramAccount(&'a TokenProgramAccount), - CandyGuard(&'a CandyGuardAccountData), - CandyMachine(&'a CandyMachineAccountData), - CandyMachineCore(&'a CandyMachineCoreAccountData), Unknown, } diff --git a/blockbuster/tests/candy_machine_parser_test.rs b/blockbuster/tests/candy_machine_parser_test.rs deleted file mode 100644 index b42dd5a..0000000 --- a/blockbuster/tests/candy_machine_parser_test.rs +++ /dev/null @@ -1,388 +0,0 @@ -#[cfg(test)] -use blockbuster::{ - error::BlockbusterError, - instruction::InstructionBundle, - program_handler::ProgramParser, - programs::{ - candy_machine::{ - candy_machine_id, - state::{ - CandyMachine as CandyMachineAccountType, - CandyMachineData as CandyMachineDataAccountType, - CollectionPDA as CollectionPDAAccountType, Creator, EndSettingType, EndSettings, - FreezePDA as FreezePDAAccountType, GatekeeperConfig, HiddenSettings, - WhitelistMintMode, WhitelistMintSettings, - }, - CandyMachineAccountData::{CandyMachine, CollectionPDA, FreezePDA}, - CandyMachineParser, CANDY_MACHINE_DISCRIMINATOR, COLLECTION_PDA_DISCRIMINATOR, - FREEZE_PDA_DISCRIMINATOR, - }, - ProgramParseResult, - }, -}; -use helpers::{build_random_account_update, build_random_instruction, random_list, random_pubkey}; -use plerkle_serialization::root_as_compiled_instruction; - -use borsh::BorshSerialize; -use flatbuffers::FlatBufferBuilder; - -mod helpers; - -fn get_test_candy_machine() -> CandyMachineAccountType { - // Create CandyMachine test data. - let end_settings = EndSettings { - end_setting_type: EndSettingType::Amount, - number: 5000, - }; - - let creators = vec![ - Creator { - address: random_pubkey(), - verified: true, - share: 33, - }, - Creator { - address: random_pubkey(), - verified: false, - share: 33, - }, - Creator { - address: random_pubkey(), - verified: false, - share: 33, - }, - Creator { - address: random_pubkey(), - verified: true, - share: 1, - }, - ]; - - let hidden_settings = HiddenSettings { - name: String::from("name"), - uri: String::from("uri"), - hash: random_list(32, u8::MAX).try_into().unwrap(), - }; - - let whitelist_mint_settings = WhitelistMintSettings { - mode: WhitelistMintMode::BurnEveryTime, - mint: random_pubkey(), - presale: true, - discount_price: Some(12345), - }; - - let gatekeeper_config = GatekeeperConfig { - gatekeeper_network: random_pubkey(), - expire_on_use: true, - }; - - let candy_machine_data = CandyMachineDataAccountType { - uuid: String::from("uri"), - price: 991177, - symbol: String::from("ABC"), - seller_fee_basis_points: 44, - max_supply: 100000, - is_mutable: true, - retain_authority: false, - go_live_date: Some(1663833216), - end_settings: Some(end_settings), - creators, - hidden_settings: Some(hidden_settings), - whitelist_mint_settings: Some(whitelist_mint_settings), - items_available: 55, - gatekeeper: Some(gatekeeper_config), - }; - - CandyMachineAccountType { - authority: random_pubkey(), - wallet: random_pubkey(), - token_mint: Some(random_pubkey()), - items_redeemed: 33, - data: candy_machine_data, - } -} - -#[test] -fn test_setup() { - let subject = CandyMachineParser {}; - assert_eq!(subject.key(), candy_machine_id()); - assert!(subject.key_match(&candy_machine_id())); -} - -#[test] -fn test_unused_instruction_parsing() { - // Build a random test instruction. - let mut fbb = FlatBufferBuilder::new(); - let offset = build_random_instruction(&mut fbb, 10, 3); - fbb.finish_minimal(offset); - let data = fbb.finished_data(); - let outer_ix = root_as_compiled_instruction(data).expect("Could not create random instruction"); - - // Bundle the instruction with more random data. - let bundle = InstructionBundle { - txn_id: "", - program: plerkle_serialization::Pubkey(random_pubkey().to_bytes()), - instruction: Some(outer_ix), - inner_ix: None, - keys: &[plerkle_serialization::Pubkey(random_pubkey().to_bytes())], - slot: 0, - }; - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_instruction(&bundle); - - // Check `ProgramParseResult` and make sure it expected variant. - assert!(result.is_ok()); - match result.unwrap().result_type() { - ProgramParseResult::Unknown => (), - _ => panic!("Unexpected ProgramParseResult variant"), - } -} - -#[test] -fn test_zero_length_data_fails() { - // Empty byte slice. - let data: &[u8] = &[]; - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - - // Validate expected error. - assert!(result.is_err()); - if let Err(err) = result { - match err { - BlockbusterError::DeserializationError => (), - _ => panic!("Unexpected error: {}", err,), - } - } -} - -#[test] -fn test_unknown_discriminator_fails() { - // Borsh serialize the CandyMachine discriminator. - let mut data = CANDY_MACHINE_DISCRIMINATOR.to_vec(); - - // Corrupt the discriminator. - data[0] = 0; - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - - // Validate expected error. - assert!(result.is_err()); - if let Err(err) = result { - match err { - BlockbusterError::UnknownAccountDiscriminator => (), - _ => panic!("Unexpected error: {}", err), - } - } -} - -#[test] -fn test_basic_success_parsing_candy_machine_account() { - // Get CandyMachine test data. - let test_candy_machine = get_test_candy_machine(); - - // Borsh serialize the CandyMachine test data. - let mut data = CANDY_MACHINE_DISCRIMINATOR.to_vec(); - test_candy_machine - .serialize(&mut data) - .expect("Could not serialize candy machine data"); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - assert!(result.is_ok()); - - // Check `ProgramParseResult` and make sure the data is parsed and matches the test data. - if let ProgramParseResult::CandyMachine(candy_machine_account_data) = - result.unwrap().result_type() - { - match candy_machine_account_data { - CandyMachine(parsed_candy_machine) => { - assert_eq!(*parsed_candy_machine, test_candy_machine); - } - _ => panic!("Unexpected CandyMachineAccountData variant"), - } - } else { - panic!("Unexpected ProgramParseResult variant"); - } -} - -#[test] -fn test_wrong_size_candy_machine_account_fails() { - // Borsh serialize the CandyMachine discriminator. - let mut data = CANDY_MACHINE_DISCRIMINATOR.to_vec(); - // Add some random data. - data.append(&mut random_list(32, u8::MAX)); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - - // Validate expected error. - assert!(result.is_err()); - if let Err(err) = result { - match err { - BlockbusterError::IOError(_) => (), - _ => panic!("Unexpected error: {}", err), - } - } -} - -#[test] -fn test_basic_success_parsing_collection_pda_account() { - // Create CollectionPDA test data. - let test_collection_pda = CollectionPDAAccountType { - mint: random_pubkey(), - candy_machine: random_pubkey(), - }; - - // Borsh serialize the CandyMachine test data. - let mut data = COLLECTION_PDA_DISCRIMINATOR.to_vec(); - test_collection_pda - .serialize(&mut data) - .expect("Could not serialize CollectionPDA data"); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - assert!(result.is_ok()); - - // Check `ProgramParseResult` and make sure the data is parsed and matches the test data. - if let ProgramParseResult::CandyMachine(candy_machine_account_data) = - result.unwrap().result_type() - { - match candy_machine_account_data { - CollectionPDA(parsed_collection_pda) => { - assert_eq!(*parsed_collection_pda, test_collection_pda); - } - _ => panic!("Unexpected CandyMachineAccountData variant"), - } - } else { - panic!("Unexpected ProgramParseResult variant"); - } -} - -#[test] -fn test_wrong_size_collection_pda_account_fails() { - // Borsh serialize the CandyMachine discriminator. - let mut data = COLLECTION_PDA_DISCRIMINATOR.to_vec(); - // Add some random data. - data.append(&mut random_list(8, u8::MAX)); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - - // Validate expected error. - assert!(result.is_err()); - if let Err(err) = result { - match err { - BlockbusterError::IOError(_) => (), - _ => panic!("Unexpected error: {}", err), - } - } -} - -#[test] -fn test_basic_success_parsing_freeze_pda_account() { - // Create FreezePDA test data. - let test_freeze_pda = FreezePDAAccountType { - candy_machine: random_pubkey(), - allow_thaw: true, - frozen_count: 3, - mint_start: Some(1663833216), - freeze_time: 300, - freeze_fee: 1000000, - }; - - // Borsh serialize the CandyMachine test data. - let mut data = FREEZE_PDA_DISCRIMINATOR.to_vec(); - test_freeze_pda - .serialize(&mut data) - .expect("Could not serialize FreezePDA data"); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - assert!(result.is_ok()); - - // Check `ProgramParseResult` and make sure the data is parsed and matches the test data. - if let ProgramParseResult::CandyMachine(candy_machine_account_data) = - result.unwrap().result_type() - { - match candy_machine_account_data { - FreezePDA(parsed_freeze_pda) => { - assert_eq!(*parsed_freeze_pda, test_freeze_pda); - } - _ => panic!("Unexpected CandyMachineAccountData variant"), - } - } else { - panic!("Unexpected ProgramParseResult variant"); - } -} - -#[test] -fn test_wrong_size_freeze_pda_account_fails() { - // Borsh serialize the CandyMachine discriminator. - let mut data = FREEZE_PDA_DISCRIMINATOR.to_vec(); - // Add some random data. - data.append(&mut random_list(32, u8::MAX)); - - // Flatbuffer serialize the data. - let mut fbb = FlatBufferBuilder::new(); - let account_info = - build_random_account_update(&mut fbb, &data).expect("Could not build account update"); - - // Use `CandyMachineParser` to parse the account update. - let subject = CandyMachineParser {}; - let result = subject.handle_account(&account_info); - - // Validate expected error. - assert!(result.is_err()); - if let Err(err) = result { - match err { - BlockbusterError::IOError(_) => (), - _ => panic!("Unexpected error: {}", err), - } - } -} From 52c3ae55333a1067f8c445f4beb5309c89c52512 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:20:33 -0800 Subject: [PATCH 2/2] Update comment --- blockbuster/src/programs/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/blockbuster/src/programs/mod.rs b/blockbuster/src/programs/mod.rs index 1a47036..5b98e8a 100644 --- a/blockbuster/src/programs/mod.rs +++ b/blockbuster/src/programs/mod.rs @@ -7,20 +7,19 @@ pub mod token_account; pub mod token_metadata; // Note: `ProgramParseResult` used to contain the following variants that have been deprecated and -// removed from blockbuster since the `version-1.16` tag of blockbuster: +// removed from blockbuster since the `version-1.16` tag: // CandyGuard(&'a CandyGuardAccountData), // CandyMachine(&'a CandyMachineAccountData), // CandyMachineCore(&'a CandyMachineCoreAccountData), // -// The reason Candy Machine V3 parsing was removed was because Candy Guard (`mpl-candy-guard`) and -// Candy Machine V3 (`mpl-candy-machine-core`) were dependent upon a specific Solana version (1.16) -// at the time, there was no Candy Machine parsing in DAS (`digital-asset-rpc-infrastructure`), and -// we wanted to use the Rust clients for Token Metadata and Bubblegum so that going forward we could -// more easily update blockbuster to new Solana versions going forward. +// Candy Machine V3 parsing was removed because Candy Guard (`mpl-candy-guard`) and +// Candy Machine Core (`mpl-candy-machine-core`) were dependent upon a specific Solana +// version (1.16), there was no Candy Machine parsing in DAS (`digital-asset-rpc-infrastructure`), +// and we wanted to use the Rust clients for Bubblegum and Token Metadata so that going forward we +// could more easily update blockbuster to new Solana versions. // -// Candy Machine V2 (`mpl-candy-machine`) parsing did not depend on the `mpl-candy-machine` crate -// as its types were copied, but we removed V2 parsing at the same time as V3 parsing as it was not -// being used. +// Candy Machine V2 (`mpl-candy-machine`) parsing was removed at the same time as V3 because even +// though it did not depend on the `mpl-candy-machine` crate, it was also not being used by DAS. pub enum ProgramParseResult<'a> { Bubblegum(&'a BubblegumInstruction), TokenMetadata(&'a TokenMetadataAccountState),