Skip to content

Commit

Permalink
Merge pull request #156 from metaplex-foundation/danenbm/asset-collec…
Browse files Browse the repository at this point in the history
…tion-ext-plugin-data

Add external plugin data to Asset and Collection in Rust client
  • Loading branch information
danenbm authored Jul 3, 2024
2 parents de40bab + 9a30d6a commit 58c0db7
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 52 deletions.
27 changes: 24 additions & 3 deletions clients/rust/src/hooked/advanced_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,33 @@ pub struct PluginsList {

#[derive(Debug, Default)]
pub struct ExternalPluginAdaptersList {
pub lifecycle_hooks: Vec<LifecycleHook>,
pub lifecycle_hooks: Vec<LifecycleHookWithData>,
pub linked_lifecycle_hooks: Vec<LinkedLifecycleHook>,
pub oracles: Vec<Oracle>,
pub app_data: Vec<AppData>,
pub app_data: Vec<AppDataWithData>,
pub linked_app_data: Vec<LinkedAppData>,
pub data_sections: Vec<DataSection>,
pub data_sections: Vec<DataSectionWithData>,
}

#[derive(Debug)]
pub struct LifecycleHookWithData {
pub base: LifecycleHook,
pub data_offset: usize,
pub data_len: usize,
}

#[derive(Debug)]
pub struct AppDataWithData {
pub base: AppData,
pub data_offset: usize,
pub data_len: usize,
}

#[derive(Debug)]
pub struct DataSectionWithData {
pub base: DataSection,
pub data_offset: usize,
pub data_len: usize,
}

#[derive(Debug)]
Expand Down
91 changes: 51 additions & 40 deletions clients/rust/src/hooked/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ use solana_program::{account_info::AccountInfo, pubkey::Pubkey};

use crate::{
accounts::{BaseAssetV1, PluginHeaderV1},
convert_external_plugin_adapter_data_to_string,
errors::MplCoreError,
types::{
ExternalPluginAdapter, ExternalPluginAdapterKey, ExternalPluginAdapterType, LinkedDataKey,
Plugin, PluginAuthority, PluginType, RegistryRecord,
},
AddBlockerPlugin, AttributesPlugin, AutographPlugin, BaseAuthority, BasePlugin,
BurnDelegatePlugin, DataBlob, EditionPlugin, ExternalPluginAdaptersList,
ExternalRegistryRecordSafe, FreezeDelegatePlugin, ImmutableMetadataPlugin, MasterEditionPlugin,
AddBlockerPlugin, AppDataWithData, AttributesPlugin, AutographPlugin, BaseAuthority,
BasePlugin, BurnDelegatePlugin, DataBlob, DataSectionWithData, EditionPlugin,
ExternalPluginAdaptersList, ExternalRegistryRecordSafe, FreezeDelegatePlugin,
ImmutableMetadataPlugin, LifecycleHookWithData, MasterEditionPlugin,
PermanentBurnDelegatePlugin, PermanentFreezeDelegatePlugin, PermanentTransferDelegatePlugin,
PluginRegistryV1Safe, PluginsList, RegistryRecordSafe, RoyaltiesPlugin, SolanaAccount,
TransferDelegatePlugin, UpdateDelegatePlugin, VerifiedCreatorsPlugin,
Expand Down Expand Up @@ -151,49 +151,37 @@ pub fn fetch_wrapped_external_plugin_adapter<T: DataBlob + SolanaAccount>(
Ok((registry_record, plugin))
}

/// Fetch the external_plugin_adapter data from the registry.
pub fn fetch_external_plugin_adapter_data<T: DataBlob + SolanaAccount>(
account: &AccountInfo,
core: Option<&T>,
plugin_key: &ExternalPluginAdapterKey,
) -> Result<(String, usize, usize), std::io::Error> {
let (registry_record, external_plugin) =
fetch_wrapped_external_plugin_adapter(account, core, plugin_key)?;

let schema = match external_plugin {
ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => lifecycle_hook.schema,
ExternalPluginAdapter::AppData(app_data) => app_data.schema,
ExternalPluginAdapter::DataSection(data_section) => data_section.schema,
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
MplCoreError::UnsupportedOperation.to_string(),
));
}
};

let data_offset = registry_record.data_offset.ok_or(std::io::Error::new(
// Helper to unwrap optional data offset and data length.
fn unwrap_data_offset_and_data_len(
data_offset: Option<u64>,
data_len: Option<u64>,
) -> Result<(usize, usize), std::io::Error> {
let data_offset = data_offset.ok_or(std::io::Error::new(
std::io::ErrorKind::Other,
MplCoreError::InvalidPlugin.to_string(),
))?;

let data_len = registry_record.data_len.ok_or(std::io::Error::new(
let data_len = data_len.ok_or(std::io::Error::new(
std::io::ErrorKind::Other,
MplCoreError::InvalidPlugin.to_string(),
))?;

let end = data_offset
.checked_add(data_len)
.ok_or(std::io::Error::new(
std::io::ErrorKind::Other,
MplCoreError::NumericalOverflow.to_string(),
))?;
Ok((data_offset as usize, data_len as usize))
}

let data_slice = &(*account.data).borrow()[data_offset as usize..end as usize];
let data_string = convert_external_plugin_adapter_data_to_string(&schema, data_slice);
/// Fetch the external plugin adapter data offset and length. These can be used to
/// directly slice the account data for use of the external plugin adapter data.
pub fn fetch_external_plugin_adapter_data_info<T: DataBlob + SolanaAccount>(
account: &AccountInfo,
core: Option<&T>,
plugin_key: &ExternalPluginAdapterKey,
) -> Result<(usize, usize), std::io::Error> {
let registry_record = fetch_external_registry_record(account, core, plugin_key)?;
let (data_offset, data_len) =
unwrap_data_offset_and_data_len(registry_record.data_offset, registry_record.data_len)?;

// Return the data and its offset.
Ok((data_string, data_offset as usize, data_len as usize))
// Return the data offset and length.
Ok((data_offset, data_len))
}

// Internal helper to fetch just the external registry record for the external plugin key.
Expand Down Expand Up @@ -365,18 +353,41 @@ pub(crate) fn registry_records_to_external_plugin_adapter_list(

match plugin {
ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => {
acc.lifecycle_hooks.push(lifecycle_hook)
let (data_offset, data_len) =
unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?;

acc.lifecycle_hooks.push(LifecycleHookWithData {
base: lifecycle_hook,
data_offset,
data_len,
})
}
ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => {
acc.linked_lifecycle_hooks.push(lifecycle_hook)
}
ExternalPluginAdapter::Oracle(oracle) => acc.oracles.push(oracle),
ExternalPluginAdapter::AppData(app_data) => acc.app_data.push(app_data),
ExternalPluginAdapter::AppData(app_data) => {
let (data_offset, data_len) =
unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?;

acc.app_data.push(AppDataWithData {
base: app_data,
data_offset,
data_len,
})
}
ExternalPluginAdapter::LinkedAppData(app_data) => {
acc.linked_app_data.push(app_data)
}
ExternalPluginAdapter::DataSection(data_section) => {
acc.data_sections.push(data_section)
let (data_offset, data_len) =
unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?;

acc.data_sections.push(DataSectionWithData {
base: data_section,
data_offset,
data_len,
})
}
}
}
Expand Down
1 change: 1 addition & 0 deletions clients/rust/tests/add_external_plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ async fn test_temporarily_cannot_add_lifecycle_hook_on_collection() {
num_minted: 0,
current_size: 0,
plugins: vec![],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down
5 changes: 5 additions & 0 deletions clients/rust/tests/create_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async fn test_create_collection() {
num_minted: 0,
current_size: 0,
plugins: vec![],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down Expand Up @@ -76,6 +77,7 @@ async fn create_collection_with_different_payer() {
num_minted: 0,
current_size: 0,
plugins: vec![],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down Expand Up @@ -132,6 +134,7 @@ async fn create_collection_with_plugins() {
rule_set: RuleSet::ProgramDenyList(vec![]),
}),
}],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down Expand Up @@ -172,6 +175,7 @@ async fn create_collection_with_different_update_authority() {
num_minted: 0,
current_size: 0,
plugins: vec![],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down Expand Up @@ -233,6 +237,7 @@ async fn create_collection_with_plugins_with_different_plugin_authority() {
rule_set: RuleSet::ProgramDenyList(vec![]),
}),
}],
external_plugin_adapters: vec![],
},
)
.await;
Expand Down
Loading

0 comments on commit 58c0db7

Please sign in to comment.