diff --git a/programs/mpl-core/src/plugins/external_plugin_adapters.rs b/programs/mpl-core/src/plugins/external_plugin_adapters.rs index 7068807d..1546cab2 100644 --- a/programs/mpl-core/src/plugins/external_plugin_adapters.rs +++ b/programs/mpl-core/src/plugins/external_plugin_adapters.rs @@ -8,7 +8,7 @@ use strum::EnumCount; use crate::{ error::MplCoreError, plugins::{approve, reject}, - state::{AssetV1, SolanaAccount}, + state::{AssetV1, DataBlob, SolanaAccount}, }; use super::{ @@ -39,6 +39,14 @@ pub enum ExternalPluginAdapterType { DataSection, } +impl DataBlob for ExternalPluginAdapterType { + const BASE_LEN: usize = 1; + + fn len(&self) -> usize { + Self::BASE_LEN + } +} + impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType { fn from(key: &ExternalPluginAdapterKey) -> Self { match key { @@ -398,6 +406,14 @@ pub enum HookableLifecycleEvent { Update, } +impl DataBlob for HookableLifecycleEvent { + const BASE_LEN: usize = 1; + + fn len(&self) -> usize { + Self::BASE_LEN + } +} + /// Prefix used with some of the `ExtraAccounts` that are PDAs. pub const MPL_CORE_PREFIX: &str = "mpl-core"; diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/add_blocker.rs b/programs/mpl-core/src/plugins/internal/authority_managed/add_blocker.rs index 9a2a4671..4a1af694 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/add_blocker.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/add_blocker.rs @@ -16,12 +16,10 @@ use crate::{ pub struct AddBlocker {} impl DataBlob for AddBlocker { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { - 0 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/attributes.rs b/programs/mpl-core/src/plugins/internal/authority_managed/attributes.rs index b228131b..1f6c0cc4 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/attributes.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/attributes.rs @@ -12,12 +12,11 @@ pub struct Attribute { } impl DataBlob for Attribute { - fn get_initial_size() -> usize { - 4 + 4 - } + const BASE_LEN: usize = 4 // The length of the Key string + + 4; // The length of the Value string - fn get_size(&self) -> usize { - 4 + self.key.len() + 4 + self.value.len() + fn len(&self) -> usize { + Self::BASE_LEN + self.key.len() + self.value.len() } } @@ -37,15 +36,15 @@ impl Attributes { } impl DataBlob for Attributes { - fn get_initial_size() -> usize { - 4 - } - - fn get_size(&self) -> usize { - 4 + self - .attribute_list - .iter() - .fold(0, |acc, attr| acc + attr.get_size()) + const BASE_LEN: usize = 4; // The length of the attribute list + + fn len(&self) -> usize { + Self::BASE_LEN + + self + .attribute_list + .iter() + .map(|attr| attr.len()) + .sum::() } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/immutable_metadata.rs b/programs/mpl-core/src/plugins/internal/authority_managed/immutable_metadata.rs index 04ecb80f..17f3fe79 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/immutable_metadata.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/immutable_metadata.rs @@ -14,11 +14,9 @@ use crate::{ pub struct ImmutableMetadata {} impl DataBlob for ImmutableMetadata { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { + fn len(&self) -> usize { 0 } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/master_edition.rs b/programs/mpl-core/src/plugins/internal/authority_managed/master_edition.rs index 21a18921..f2139b9f 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/master_edition.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/master_edition.rs @@ -18,15 +18,14 @@ pub struct MasterEdition { impl PluginValidation for MasterEdition {} impl DataBlob for MasterEdition { - fn get_initial_size() -> usize { - 1 + 1 + 1 - } + const BASE_LEN: usize = 1 // The max_supply option + + 1 // The name option + + 1; // The uri option - fn get_size(&self) -> usize { - 1 + self.max_supply.map_or(0, |_| 4) - + 1 + fn len(&self) -> usize { + Self::BASE_LEN + + self.max_supply.map_or(0, |_| 4) + self.name.as_ref().map_or(0, |name| 4 + name.len()) - + 1 + self.uri.as_ref().map_or(0, |uri| 4 + uri.len()) } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/royalties.rs b/programs/mpl-core/src/plugins/internal/authority_managed/royalties.rs index 209fb227..21d95337 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/royalties.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/royalties.rs @@ -18,12 +18,11 @@ pub struct Creator { } impl DataBlob for Creator { - fn get_initial_size() -> usize { - 33 - } + const BASE_LEN: usize = 32 // The address + + 1; // The percentage - fn get_size(&self) -> usize { - 33 + fn len(&self) -> usize { + Self::BASE_LEN } } @@ -39,16 +38,15 @@ pub enum RuleSet { } impl DataBlob for RuleSet { - fn get_initial_size() -> usize { - 1 - } - - fn get_size(&self) -> usize { - 1 + match self { - RuleSet::ProgramAllowList(allow_list) => 4 + allow_list.len() * 32, - RuleSet::ProgramDenyList(deny_list) => 4 + deny_list.len() * 32, - RuleSet::None => 0, - } + const BASE_LEN: usize = 1; // The rule set discriminator + + fn len(&self) -> usize { + Self::BASE_LEN + + match self { + RuleSet::ProgramAllowList(allow_list) => 4 + allow_list.len() * 32, + RuleSet::ProgramDenyList(deny_list) => 4 + deny_list.len() * 32, + RuleSet::None => 0, + } } } @@ -64,14 +62,15 @@ pub struct Royalties { } impl DataBlob for Royalties { - fn get_initial_size() -> usize { - 1 - } + const BASE_LEN: usize = 2 // basis_points + + 4 // creators length + + RuleSet::BASE_LEN; // rule_set - fn get_size(&self) -> usize { + fn len(&self) -> usize { 2 // basis_points - + (4 + self.creators.len() * Creator::get_initial_size()) // creators - + self.rule_set.get_size() // rule_set + + 4 // creators length + + self.creators.iter().map(|creator| creator.len()).sum::() + + self.rule_set.len() // rule_set } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs b/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs index d305a00d..97ec938a 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs @@ -38,12 +38,10 @@ impl Default for UpdateDelegate { } impl DataBlob for UpdateDelegate { - fn get_initial_size() -> usize { - 4 - } + const BASE_LEN: usize = 4; // The additional delegates length - fn get_size(&self) -> usize { - 4 + self.additional_delegates.len() * 32 + fn len(&self) -> usize { + Self::BASE_LEN + self.additional_delegates.len() * 32 } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/verified_creators.rs b/programs/mpl-core/src/plugins/internal/authority_managed/verified_creators.rs index e90d7706..cc51396f 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/verified_creators.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/verified_creators.rs @@ -18,12 +18,11 @@ pub struct VerifiedCreatorsSignature { } impl DataBlob for VerifiedCreatorsSignature { - fn get_initial_size() -> usize { - 32 + 1 - } + const BASE_LEN: usize = 32 // The address + + 1; // The verified boolean - fn get_size(&self) -> usize { - 32 + 1 + fn len(&self) -> usize { + Self::BASE_LEN } } @@ -35,12 +34,10 @@ pub struct VerifiedCreators { } impl DataBlob for VerifiedCreators { - fn get_initial_size() -> usize { - 4 - } + const BASE_LEN: usize = 4; // The signatures length - fn get_size(&self) -> usize { - 4 + self.signatures.len() * VerifiedCreatorsSignature::get_initial_size() + fn len(&self) -> usize { + Self::BASE_LEN + self.signatures.iter().map(|sig| sig.len()).sum::() } } diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/autograph.rs b/programs/mpl-core/src/plugins/internal/owner_managed/autograph.rs index b7a923f3..4c5272b5 100644 --- a/programs/mpl-core/src/plugins/internal/owner_managed/autograph.rs +++ b/programs/mpl-core/src/plugins/internal/owner_managed/autograph.rs @@ -19,12 +19,11 @@ pub struct AutographSignature { } impl DataBlob for AutographSignature { - fn get_initial_size() -> usize { - 32 + 4 - } + const BASE_LEN: usize = 32 // The address + + 4; // The message length - fn get_size(&self) -> usize { - 32 + 4 + self.message.len() + fn len(&self) -> usize { + Self::BASE_LEN + self.message.len() } } @@ -135,14 +134,9 @@ impl PluginValidation for Autograph { } impl DataBlob for Autograph { - fn get_initial_size() -> usize { - 4 - } + const BASE_LEN: usize = 4; // The signatures length - fn get_size(&self) -> usize { - 4 + self - .signatures - .iter() - .fold(0, |acc, sig| acc + sig.get_size()) + fn len(&self) -> usize { + Self::BASE_LEN + self.signatures.iter().map(|sig| sig.len()).sum::() } } diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/burn_delegate.rs b/programs/mpl-core/src/plugins/internal/owner_managed/burn_delegate.rs index 15075fb3..ff9843c8 100644 --- a/programs/mpl-core/src/plugins/internal/owner_managed/burn_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/owner_managed/burn_delegate.rs @@ -26,11 +26,9 @@ impl Default for BurnDelegate { } impl DataBlob for BurnDelegate { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { + fn len(&self) -> usize { 0 } } diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/freeze_delegate.rs b/programs/mpl-core/src/plugins/internal/owner_managed/freeze_delegate.rs index e9e2574f..87a842e2 100644 --- a/programs/mpl-core/src/plugins/internal/owner_managed/freeze_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/owner_managed/freeze_delegate.rs @@ -32,12 +32,10 @@ impl Default for FreezeDelegate { } impl DataBlob for FreezeDelegate { - fn get_initial_size() -> usize { - 1 - } + const BASE_LEN: usize = 1; // The frozen boolean - fn get_size(&self) -> usize { - 1 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/transfer_delegate.rs b/programs/mpl-core/src/plugins/internal/owner_managed/transfer_delegate.rs index 0ef04138..7da1ccc4 100644 --- a/programs/mpl-core/src/plugins/internal/owner_managed/transfer_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/owner_managed/transfer_delegate.rs @@ -27,12 +27,10 @@ impl Default for TransferDelegate { } impl DataBlob for TransferDelegate { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { - 0 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/permanent/edition.rs b/programs/mpl-core/src/plugins/internal/permanent/edition.rs index 7ea3b475..b71cf533 100644 --- a/programs/mpl-core/src/plugins/internal/permanent/edition.rs +++ b/programs/mpl-core/src/plugins/internal/permanent/edition.rs @@ -48,11 +48,9 @@ impl PluginValidation for Edition { } impl DataBlob for Edition { - fn get_initial_size() -> usize { - 4 - } + const BASE_LEN: usize = 4; // The edition number - fn get_size(&self) -> usize { - 4 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/permanent/permanent_burn_delegate.rs b/programs/mpl-core/src/plugins/internal/permanent/permanent_burn_delegate.rs index 9717ffdd..3515c66a 100644 --- a/programs/mpl-core/src/plugins/internal/permanent/permanent_burn_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/permanent/permanent_burn_delegate.rs @@ -16,12 +16,10 @@ use crate::{ pub struct PermanentBurnDelegate {} impl DataBlob for PermanentBurnDelegate { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { - 0 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_delegate.rs b/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_delegate.rs index 04b3daf7..d6cba7dc 100644 --- a/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_delegate.rs @@ -31,12 +31,10 @@ impl Default for PermanentFreezeDelegate { } impl DataBlob for PermanentFreezeDelegate { - fn get_initial_size() -> usize { - 1 - } + const BASE_LEN: usize = 1; // The frozen boolean - fn get_size(&self) -> usize { - 1 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/internal/permanent/permanent_transfer_delegate.rs b/programs/mpl-core/src/plugins/internal/permanent/permanent_transfer_delegate.rs index e7435595..147c5cd7 100644 --- a/programs/mpl-core/src/plugins/internal/permanent/permanent_transfer_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/permanent/permanent_transfer_delegate.rs @@ -15,12 +15,10 @@ use crate::plugins::{ pub struct PermanentTransferDelegate {} impl DataBlob for PermanentTransferDelegate { - fn get_initial_size() -> usize { - 0 - } + const BASE_LEN: usize = 0; - fn get_size(&self) -> usize { - 0 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/lifecycle.rs b/programs/mpl-core/src/plugins/lifecycle.rs index 2f47c5ed..c3f758d4 100644 --- a/programs/mpl-core/src/plugins/lifecycle.rs +++ b/programs/mpl-core/src/plugins/lifecycle.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use crate::{ error::MplCoreError, - state::{Authority, Key, UpdateAuthority}, + state::{Authority, DataBlob, Key, UpdateAuthority}, }; use super::{ @@ -37,6 +37,14 @@ pub struct ExternalCheckResult { pub flags: u32, } +impl DataBlob for ExternalCheckResult { + const BASE_LEN: usize = 4; // u32 flags + + fn len(&self) -> usize { + Self::BASE_LEN + } +} + impl ExternalCheckResult { pub(crate) fn none() -> Self { Self { flags: 0 } diff --git a/programs/mpl-core/src/plugins/mod.rs b/programs/mpl-core/src/plugins/mod.rs index c93f9820..6b72d4ef 100644 --- a/programs/mpl-core/src/plugins/mod.rs +++ b/programs/mpl-core/src/plugins/mod.rs @@ -89,34 +89,33 @@ impl Plugin { impl Compressible for Plugin {} impl DataBlob for Plugin { - fn get_initial_size() -> usize { - 1 - } - - fn get_size(&self) -> usize { - 1 + match self { - Plugin::Royalties(royalties) => royalties.get_size(), - Plugin::FreezeDelegate(freeze_delegate) => freeze_delegate.get_size(), - Plugin::BurnDelegate(burn_delegate) => burn_delegate.get_size(), - Plugin::TransferDelegate(transfer_delegate) => transfer_delegate.get_size(), - Plugin::UpdateDelegate(update_delegate) => update_delegate.get_size(), - Plugin::PermanentFreezeDelegate(permanent_freeze_delegate) => { - permanent_freeze_delegate.get_size() - } - Plugin::Attributes(attributes) => attributes.get_size(), - Plugin::PermanentTransferDelegate(permanent_transfer_delegate) => { - permanent_transfer_delegate.get_size() + const BASE_LEN: usize = 1; + + fn len(&self) -> usize { + Self::BASE_LEN // The discriminator + + match self { + Plugin::Royalties(royalties) => royalties.len(), + Plugin::FreezeDelegate(freeze_delegate) => freeze_delegate.len(), + Plugin::BurnDelegate(burn_delegate) => burn_delegate.len(), + Plugin::TransferDelegate(transfer_delegate) => transfer_delegate.len(), + Plugin::UpdateDelegate(update_delegate) => update_delegate.len(), + Plugin::PermanentFreezeDelegate(permanent_freeze_delegate) => { + permanent_freeze_delegate.len() + } + Plugin::Attributes(attributes) => attributes.len(), + Plugin::PermanentTransferDelegate(permanent_transfer_delegate) => { + permanent_transfer_delegate.len() + } + Plugin::PermanentBurnDelegate(permanent_burn_delegate) => { + permanent_burn_delegate.len() + } + Plugin::Edition(edition) => edition.len(), + Plugin::MasterEdition(master_edition) => master_edition.len(), + Plugin::AddBlocker(add_blocker) => add_blocker.len(), + Plugin::ImmutableMetadata(immutable_metadata) => immutable_metadata.len(), + Plugin::VerifiedCreators(verified_creators) => verified_creators.len(), + Plugin::Autograph(autograph) => autograph.len(), } - Plugin::PermanentBurnDelegate(permanent_burn_delegate) => { - permanent_burn_delegate.get_size() - } - Plugin::Edition(edition) => edition.get_size(), - Plugin::MasterEdition(master_edition) => master_edition.get_size(), - Plugin::AddBlocker(add_blocker) => add_blocker.get_size(), - Plugin::ImmutableMetadata(immutable_metadata) => immutable_metadata.get_size(), - Plugin::VerifiedCreators(verified_creators) => verified_creators.get_size(), - Plugin::Autograph(autograph) => autograph.get_size(), - } } } @@ -169,12 +168,10 @@ pub enum PluginType { } impl DataBlob for PluginType { - fn get_initial_size() -> usize { - 1 - } + const BASE_LEN: usize = 1; - fn get_size(&self) -> usize { - 1 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/plugin_header.rs b/programs/mpl-core/src/plugins/plugin_header.rs index 366feda3..ec5bb107 100644 --- a/programs/mpl-core/src/plugins/plugin_header.rs +++ b/programs/mpl-core/src/plugins/plugin_header.rs @@ -15,12 +15,11 @@ pub struct PluginHeaderV1 { } impl DataBlob for PluginHeaderV1 { - fn get_initial_size() -> usize { - 1 + 8 - } + const BASE_LEN: usize = 1 // Key + + 8; // Offset - fn get_size(&self) -> usize { - 1 + 8 + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/plugins/plugin_registry.rs b/programs/mpl-core/src/plugins/plugin_registry.rs index 134069f3..b21b30e7 100644 --- a/programs/mpl-core/src/plugins/plugin_registry.rs +++ b/programs/mpl-core/src/plugins/plugin_registry.rs @@ -112,12 +112,22 @@ impl PluginRegistryV1 { } impl DataBlob for PluginRegistryV1 { - fn get_initial_size() -> usize { - 9 - } - - fn get_size(&self) -> usize { - 9 //TODO: Fix this + const BASE_LEN: usize = 1 // Key + + 4 // Registry Length + + 4; // External Registry Length + + fn len(&self) -> usize { + Self::BASE_LEN + + self + .registry + .iter() + .map(|record| record.len()) + .sum::() + + self + .external_registry + .iter() + .map(|record| record.len()) + .sum::() } } @@ -132,7 +142,7 @@ impl SolanaAccount for PluginRegistryV1 { #[derive(Clone, BorshSerialize, BorshDeserialize, Debug)] pub struct RegistryRecord { /// The type of plugin. - pub plugin_type: PluginType, // 2 + pub plugin_type: PluginType, // 1 /// The authority who has permission to utilize a plugin. pub authority: Authority, // Variable /// The offset to the plugin in the account. @@ -147,12 +157,12 @@ impl RegistryRecord { } impl DataBlob for RegistryRecord { - fn get_initial_size() -> usize { - 2 + 1 + 8 - } + const BASE_LEN: usize = PluginType::BASE_LEN + + Authority::BASE_LEN // Authority Discriminator + + 8; // Offset - fn get_size(&self) -> usize { - 2 + self.authority.get_size() + 8 + fn len(&self) -> usize { + self.plugin_type.len() + self.authority.len() + 8 } } @@ -198,3 +208,32 @@ impl ExternalRegistryRecord { Ok(()) } } + +impl DataBlob for ExternalRegistryRecord { + const BASE_LEN: usize = ExternalPluginAdapterType::BASE_LEN + + Authority::BASE_LEN // Authority Discriminator + + 1 // Lifecycle checks option + + 8 // Offset + + 1 // Data offset option + + 1; // Data len option + + fn len(&self) -> usize { + let mut len = self.plugin_type.len() + self.authority.len() + 1 + 8 + 1 + 1; + + if let Some(checks) = &self.lifecycle_checks { + len += 4 // 4 bytes for the length of the checks vector + + checks.len() + * (HookableLifecycleEvent::BASE_LEN + ExternalCheckResult::BASE_LEN); + } + + if self.data_offset.is_some() { + len += 8; + } + + if self.data_len.is_some() { + len += 8; + } + + len + } +} diff --git a/programs/mpl-core/src/plugins/utils.rs b/programs/mpl-core/src/plugins/utils.rs index bf2fdb7b..1fef2284 100644 --- a/programs/mpl-core/src/plugins/utils.rs +++ b/programs/mpl-core/src/plugins/utils.rs @@ -29,14 +29,14 @@ pub fn create_meta_idempotent<'a, T: SolanaAccount + DataBlob>( system_program: &AccountInfo<'a>, ) -> Result<(T, usize, PluginHeaderV1, PluginRegistryV1), ProgramError> { let core = T::load(account, 0)?; - let header_offset = core.get_size(); + let header_offset = core.len(); // Check if the plugin header and registry exist. if header_offset == account.data_len() { // They don't exist, so create them. let header = PluginHeaderV1 { key: Key::PluginHeaderV1, - plugin_registry_offset: header_offset + PluginHeaderV1::get_initial_size(), + plugin_registry_offset: header_offset + PluginHeaderV1::BASE_LEN, }; let registry = PluginRegistryV1 { key: Key::PluginRegistryV1, @@ -48,7 +48,7 @@ pub fn create_meta_idempotent<'a, T: SolanaAccount + DataBlob>( account, payer, system_program, - header.plugin_registry_offset + PluginRegistryV1::get_initial_size(), + header.plugin_registry_offset + PluginRegistryV1::BASE_LEN, )?; header.save(account, header_offset)?; @@ -71,12 +71,12 @@ pub fn create_plugin_meta<'a, T: SolanaAccount + DataBlob>( payer: &AccountInfo<'a>, system_program: &AccountInfo<'a>, ) -> Result<(usize, PluginHeaderV1, PluginRegistryV1), ProgramError> { - let header_offset = asset.get_size(); + let header_offset = asset.len(); // They don't exist, so create them. let header = PluginHeaderV1 { key: Key::PluginHeaderV1, - plugin_registry_offset: header_offset + PluginHeaderV1::get_initial_size(), + plugin_registry_offset: header_offset + PluginHeaderV1::BASE_LEN, }; let registry = PluginRegistryV1 { key: Key::PluginRegistryV1, @@ -88,7 +88,7 @@ pub fn create_plugin_meta<'a, T: SolanaAccount + DataBlob>( account, payer, system_program, - header.plugin_registry_offset + PluginRegistryV1::get_initial_size(), + header.plugin_registry_offset + PluginRegistryV1::BASE_LEN, )?; header.save(account, header_offset)?; @@ -102,7 +102,7 @@ pub fn assert_plugins_initialized(account: &AccountInfo) -> ProgramResult { let mut bytes: &[u8] = &(*account.data).borrow(); let asset = AssetV1::deserialize(&mut bytes)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginsNotInitialized.into()); } @@ -116,11 +116,11 @@ pub fn fetch_plugin( ) -> Result<(Authority, U, usize), ProgramError> { let asset = T::load(account, 0)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginNotFound.into()); } - let header = PluginHeaderV1::load(account, asset.get_size())?; + let header = PluginHeaderV1::load(account, asset.len())?; let PluginRegistryV1 { registry, .. } = PluginRegistryV1::load(account, header.plugin_registry_offset)?; @@ -155,15 +155,15 @@ pub fn fetch_wrapped_plugin( plugin_type: PluginType, ) -> Result<(Authority, Plugin), ProgramError> { let size = match core { - Some(core) => core.get_size(), + Some(core) => core.len(), None => { let asset = T::load(account, 0)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginNotFound.into()); } - asset.get_size() + asset.len() } }; @@ -191,15 +191,15 @@ pub fn fetch_wrapped_external_plugin_adapter( plugin_key: &ExternalPluginAdapterKey, ) -> Result<(ExternalRegistryRecord, ExternalPluginAdapter), ProgramError> { let size = match core { - Some(core) => core.get_size(), + Some(core) => core.len(), None => { let asset = T::load(account, 0)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::ExternalPluginAdapterNotFound.into()); } - asset.get_size() + asset.len() } }; @@ -225,11 +225,11 @@ pub fn fetch_wrapped_external_plugin_adapter( pub fn fetch_plugins(account: &AccountInfo) -> Result, ProgramError> { let asset = AssetV1::load(account, 0)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginNotFound.into()); } - let header = PluginHeaderV1::load(account, asset.get_size())?; + let header = PluginHeaderV1::load(account, asset.len())?; let PluginRegistryV1 { registry, .. } = PluginRegistryV1::load(account, header.plugin_registry_offset)?; @@ -240,11 +240,11 @@ pub fn fetch_plugins(account: &AccountInfo) -> Result, Progr pub fn list_plugins(account: &AccountInfo) -> Result, ProgramError> { let asset = AssetV1::load(account, 0)?; - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginNotFound.into()); } - let header = PluginHeaderV1::load(account, asset.get_size())?; + let header = PluginHeaderV1::load(account, asset.len())?; let PluginRegistryV1 { registry, .. } = PluginRegistryV1::load(account, header.plugin_registry_offset)?; @@ -267,7 +267,7 @@ pub fn initialize_plugin<'a, T: DataBlob + SolanaAccount>( system_program: &AccountInfo<'a>, ) -> ProgramResult { let plugin_type = plugin.into(); - let plugin_size = plugin.get_size(); + let plugin_size = plugin.len(); // You cannot add a duplicate plugin. if plugin_registry @@ -287,7 +287,7 @@ pub fn initialize_plugin<'a, T: DataBlob + SolanaAccount>( }; let size_increase = plugin_size - .checked_add(new_registry_record.get_size()) + .checked_add(new_registry_record.len()) .ok_or(MplCoreError::NumericalOverflow)?; let new_registry_offset = plugin_header @@ -521,7 +521,7 @@ pub fn update_external_plugin_adapter_data<'a, T: DataBlob + SolanaAccount>( plugin_registry.external_registry[record_index].data_len = Some(new_data_len); plugin_registry.save(account, new_registry_offset as usize)?; - plugin_header.save(account, core.map_or(0, |core| core.get_size()))?; + plugin_header.save(account, core.map_or(0, |core| core.len()))?; Ok(()) } @@ -564,12 +564,12 @@ pub fn delete_plugin<'a, T: DataBlob>( payer: &AccountInfo<'a>, system_program: &AccountInfo<'a>, ) -> ProgramResult { - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::PluginNotFound.into()); } //TODO: Bytemuck this. - let mut header = PluginHeaderV1::load(account, asset.get_size())?; + let mut header = PluginHeaderV1::load(account, asset.len())?; let mut plugin_registry = PluginRegistryV1::load(account, header.plugin_registry_offset)?; if let Some(index) = plugin_registry @@ -617,7 +617,7 @@ pub fn delete_plugin<'a, T: DataBlob>( ); header.plugin_registry_offset = new_registry_offset; - header.save(account, asset.get_size())?; + header.save(account, asset.len())?; // Move offsets for existing registry records. plugin_registry.bump_offsets(plugin_offset, -(serialized_plugin.len() as isize))?; @@ -640,12 +640,12 @@ pub fn delete_external_plugin_adapter<'a, T: DataBlob>( payer: &AccountInfo<'a>, system_program: &AccountInfo<'a>, ) -> ProgramResult { - if asset.get_size() == account.data_len() { + if asset.len() == account.data_len() { return Err(MplCoreError::ExternalPluginAdapterNotFound.into()); } //TODO: Bytemuck this. - let mut header = PluginHeaderV1::load(account, asset.get_size())?; + let mut header = PluginHeaderV1::load(account, asset.len())?; let mut plugin_registry = PluginRegistryV1::load(account, header.plugin_registry_offset)?; let result = find_external_plugin_adapter(&plugin_registry, plugin_key, account)?; @@ -695,7 +695,7 @@ pub fn delete_external_plugin_adapter<'a, T: DataBlob>( ); header.plugin_registry_offset = new_registry_offset; - header.save(account, asset.get_size())?; + header.save(account, asset.len())?; // Move offsets for existing registry records. plugin_registry.bump_offsets(plugin_offset, -(serialized_plugin_len as isize))?; diff --git a/programs/mpl-core/src/processor/update.rs b/programs/mpl-core/src/processor/update.rs index 23c6d9db..e3c255dd 100644 --- a/programs/mpl-core/src/processor/update.rs +++ b/programs/mpl-core/src/processor/update.rs @@ -128,7 +128,7 @@ fn update<'a>( // Increment sequence number and save only if it is `Some(_)`. asset.increment_seq_and_save(ctx.accounts.asset)?; - let asset_size = asset.get_size() as isize; + let asset_size = asset.len() as isize; let mut dirty = false; if let Some(new_update_authority) = args.new_update_authority { @@ -283,7 +283,7 @@ pub(crate) fn update_collection<'a>( Some(HookableLifecycleEvent::Update), )?; - let collection_size = collection.get_size() as isize; + let collection_size = collection.len() as isize; let mut dirty = false; if let Some(new_update_authority) = ctx.accounts.new_update_authority { @@ -326,7 +326,7 @@ fn process_update<'a, T: DataBlob + SolanaAccount>( (plugin_header.clone(), plugin_registry.clone()) { // The new size of the asset and new offset of the plugin header. - let new_core_size = core.get_size() as isize; + let new_core_size = core.len() as isize; // The difference in size between the new and old asset which is used to calculate the new size of the account. let size_diff = new_core_size @@ -347,7 +347,7 @@ fn process_update<'a, T: DataBlob + SolanaAccount>( // The offset of the first plugin is the core size plus the size of the plugin header. let plugin_offset = core_size - .checked_add(plugin_header.get_size() as isize) + .checked_add(plugin_header.len() as isize) .ok_or(MplCoreError::NumericalOverflow)?; let new_plugin_offset = plugin_offset @@ -372,7 +372,7 @@ fn process_update<'a, T: DataBlob + SolanaAccount>( plugin_registry.save(account, new_registry_offset as usize)?; } else { - resize_or_reallocate_account(account, payer, system_program, core.get_size())?; + resize_or_reallocate_account(account, payer, system_program, core.len())?; } core.save(account, 0)?; diff --git a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs index ed6d8622..a0398d9e 100644 --- a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs @@ -250,7 +250,7 @@ fn process_update_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( src.len(), ); - plugin_header.save(account, core.get_size())?; + plugin_header.save(account, core.len())?; // Move offsets for existing registry records. plugin_registry.bump_offsets(registry_record.offset, plugin_size_diff)?; diff --git a/programs/mpl-core/src/processor/update_plugin.rs b/programs/mpl-core/src/processor/update_plugin.rs index a4810f36..64fc9adf 100644 --- a/programs/mpl-core/src/processor/update_plugin.rs +++ b/programs/mpl-core/src/processor/update_plugin.rs @@ -196,7 +196,7 @@ fn process_update_plugin<'a, T: DataBlob + SolanaAccount>( src.len(), ); - plugin_header.save(account, core.get_size())?; + plugin_header.save(account, core.len())?; plugin_registry.bump_offsets(registry_record.offset, size_diff)?; diff --git a/programs/mpl-core/src/state/asset.rs b/programs/mpl-core/src/state/asset.rs index 30ec3c56..5cbfccdc 100644 --- a/programs/mpl-core/src/state/asset.rs +++ b/programs/mpl-core/src/state/asset.rs @@ -21,7 +21,6 @@ pub struct AssetV1 { pub key: Key, //1 /// The owner of the asset. pub owner: Pubkey, //32 - //TODO: Fix this for dynamic size /// The update authority of the asset. pub update_authority: UpdateAuthority, //33 /// The name of the asset. @@ -60,9 +59,6 @@ impl AssetV1 { Ok(()) } - /// The base length of the asset account with an empty name and uri and no seq. - pub const BASE_LENGTH: usize = 1 + 32 + 33 + 4 + 4 + 1; - /// Check permissions for the create lifecycle event. pub fn check_create() -> CheckResult { CheckResult::CanApprove @@ -358,12 +354,22 @@ impl AssetV1 { impl Compressible for AssetV1 {} impl DataBlob for AssetV1 { - fn get_initial_size() -> usize { - AssetV1::BASE_LENGTH - } + /// The base length of the asset account with an empty name and uri and no seq. + const BASE_LEN: usize = 1 // Key + + 32 // Owner + + 1 // Update Authority discriminator + + 4 // Name length + + 4 // URI length + + 1; // Seq option + + fn len(&self) -> usize { + let mut size = AssetV1::BASE_LEN + self.name.len() + self.uri.len(); + + if let UpdateAuthority::Address(_) | UpdateAuthority::Collection(_) = self.update_authority + { + size += 32; + } - fn get_size(&self) -> usize { - let mut size = AssetV1::BASE_LENGTH + self.name.len() + self.uri.len(); if self.seq.is_some() { size += size_of::(); } diff --git a/programs/mpl-core/src/state/collection.rs b/programs/mpl-core/src/state/collection.rs index f59fd388..78da0bea 100644 --- a/programs/mpl-core/src/state/collection.rs +++ b/programs/mpl-core/src/state/collection.rs @@ -27,9 +27,6 @@ pub struct CollectionV1 { } impl CollectionV1 { - /// The base length of the collection account with an empty name and uri. - pub const BASE_LENGTH: usize = 1 + 32 + 4 + 4 + 4 + 4; - /// Create a new collection. pub fn new( update_authority: Pubkey, @@ -351,12 +348,16 @@ impl CollectionV1 { } impl DataBlob for CollectionV1 { - fn get_initial_size() -> usize { - Self::BASE_LENGTH - } - - fn get_size(&self) -> usize { - Self::BASE_LENGTH + self.name.len() + self.uri.len() + /// The base length of the collection account with an empty name and uri. + const BASE_LEN: usize = 1 // Key + + 32 // Update Authority + + 4 // Name Length + + 4 // URI Length + + 4 // num_minted + + 4; // current_size + + fn len(&self) -> usize { + Self::BASE_LEN + self.name.len() + self.uri.len() } } diff --git a/programs/mpl-core/src/state/hashed_asset.rs b/programs/mpl-core/src/state/hashed_asset.rs index 647062c0..279d05e6 100644 --- a/programs/mpl-core/src/state/hashed_asset.rs +++ b/programs/mpl-core/src/state/hashed_asset.rs @@ -13,9 +13,6 @@ pub struct HashedAssetV1 { } impl HashedAssetV1 { - /// The length of the hashed asset account. - pub const LENGTH: usize = 1 + 32; - /// Create a new hashed asset. pub fn new(hash: [u8; 32]) -> Self { Self { @@ -26,12 +23,11 @@ impl HashedAssetV1 { } impl DataBlob for HashedAssetV1 { - fn get_initial_size() -> usize { - HashedAssetV1::LENGTH - } + const BASE_LEN: usize = 1 // The Key + + 32; // The hash - fn get_size(&self) -> usize { - HashedAssetV1::LENGTH + fn len(&self) -> usize { + Self::BASE_LEN } } diff --git a/programs/mpl-core/src/state/mod.rs b/programs/mpl-core/src/state/mod.rs index 26548c62..9d1e6872 100644 --- a/programs/mpl-core/src/state/mod.rs +++ b/programs/mpl-core/src/state/mod.rs @@ -57,16 +57,15 @@ pub enum Authority { } impl DataBlob for Authority { - fn get_initial_size() -> usize { - 1 - } + const BASE_LEN: usize = 1; // 1 byte for the discriminator - fn get_size(&self) -> usize { - 1 + if let Authority::Address { .. } = self { - 32 - } else { - 0 - } + fn len(&self) -> usize { + Self::BASE_LEN + + if let Authority::Address { .. } = self { + 32 + } else { + 0 + } } } @@ -89,9 +88,17 @@ pub enum Key { CollectionV1, } -impl Key { - /// Get the size of the Key. - pub fn get_initial_size() -> usize { - 1 +impl DataBlob for Key { + const BASE_LEN: usize = 1; // 1 byte for the discriminator + + fn len(&self) -> usize { + Self::BASE_LEN } } + +// impl Key { +// /// Get the size of the Key. +// pub fn get_initial_size() -> usize { +// 1 +// } +// } diff --git a/programs/mpl-core/src/state/traits.rs b/programs/mpl-core/src/state/traits.rs index 008b6c45..9c656c78 100644 --- a/programs/mpl-core/src/state/traits.rs +++ b/programs/mpl-core/src/state/traits.rs @@ -9,10 +9,16 @@ use super::UpdateAuthority; /// A trait for generic blobs of data that have size. pub trait DataBlob: BorshSerialize + BorshDeserialize { - /// Get the size of an empty instance of the data blob. - fn get_initial_size() -> usize; - /// Get the current size of the data blob. - fn get_size(&self) -> usize; + /// The base length of the data blob. + const BASE_LEN: usize; + + /// Get the current length of the data blob. + fn len(&self) -> usize; + + /// Check if the data blob is empty. + fn is_empty(&self) -> bool { + self.len() == Self::BASE_LEN + } } /// A trait for Solana accounts. diff --git a/programs/mpl-core/src/utils/mod.rs b/programs/mpl-core/src/utils/mod.rs index 96fbf998..5438007f 100644 --- a/programs/mpl-core/src/utils/mod.rs +++ b/programs/mpl-core/src/utils/mod.rs @@ -89,8 +89,8 @@ pub fn fetch_core_data( ) -> Result<(T, Option, Option), ProgramError> { let asset = T::load(account, 0)?; - if asset.get_size() != account.data_len() { - let plugin_header = PluginHeaderV1::load(account, asset.get_size())?; + if asset.len() != account.data_len() { + let plugin_header = PluginHeaderV1::load(account, asset.len())?; let plugin_registry = PluginRegistryV1::load(account, plugin_header.plugin_registry_offset)?;