Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing get_size for everything #197

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 72 additions & 4 deletions programs/mpl-core/src/plugins/external_plugin_adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError,
pubkey::Pubkey,
};
use strum::EnumCount;
use strum::{EnumCount, EnumIter};

use crate::{
error::MplCoreError,
plugins::{approve, reject},
state::{AssetV1, SolanaAccount},
state::{AssetV1, DataBlob, SolanaAccount},
};

use super::{
Expand All @@ -22,7 +22,17 @@ use super::{
/// List of third party plugin types.
#[repr(C)]
#[derive(
Clone, Copy, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq, EnumCount, PartialOrd, Ord,
Clone,
Copy,
Debug,
BorshSerialize,
BorshDeserialize,
Eq,
PartialEq,
EnumCount,
PartialOrd,
Ord,
EnumIter,
blockiosaurus marked this conversation as resolved.
Show resolved Hide resolved
)]
pub enum ExternalPluginAdapterType {
/// Lifecycle Hook.
Expand All @@ -39,6 +49,17 @@ pub enum ExternalPluginAdapterType {
DataSection,
}

impl ExternalPluginAdapterType {
/// A u8 enum.
const BASE_LEN: usize = 1;
}

impl DataBlob for ExternalPluginAdapterType {
fn len(&self) -> usize {
Self::BASE_LEN
}
}

impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType {
fn from(key: &ExternalPluginAdapterKey) -> Self {
match key {
Expand Down Expand Up @@ -383,7 +404,9 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapter {
}

#[repr(C)]
#[derive(Eq, PartialEq, Clone, BorshSerialize, BorshDeserialize, Debug, PartialOrd, Ord, Hash)]
#[derive(
Eq, PartialEq, Clone, BorshSerialize, BorshDeserialize, Debug, PartialOrd, Ord, Hash, EnumIter,
)]
/// An enum listing all the lifecyle events available for external plugin adapter hooks. Note that some
/// lifecycle events such as adding and removing plugins will be checked by default as they are
/// inherently part of the external plugin adapter system.
Expand All @@ -398,6 +421,17 @@ pub enum HookableLifecycleEvent {
Update,
}

impl HookableLifecycleEvent {
/// A u8 enum.
const BASE_LEN: usize = 1;
}

impl DataBlob for HookableLifecycleEvent {
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";

Expand Down Expand Up @@ -747,3 +781,37 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapterKey {
}
}
}

/// Test DataBlob sizing
#[cfg(test)]
mod test {
use strum::IntoEnumIterator;

use super::*;

#[test]
fn test_external_plugin_adapter_type_size() {
for fixture in ExternalPluginAdapterType::iter() {
let serialized = fixture.try_to_vec().unwrap();
assert_eq!(
serialized.len(),
fixture.len(),
"Serialized {:?} should match size returned by len()",
fixture
);
}
}

#[test]
fn test_hookable_lifecycle_event_size() {
for fixture in HookableLifecycleEvent::iter() {
let serialized = fixture.try_to_vec().unwrap();
assert_eq!(
serialized.len(),
fixture.len(),
"Serialized {:?} should match size returned by len()",
fixture
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ use crate::{
pub struct AddBlocker {}

impl DataBlob for AddBlocker {
fn get_initial_size() -> usize {
0
}

fn get_size(&self) -> usize {
fn len(&self) -> usize {
// Stateless data blob
0
}
}
Expand All @@ -41,3 +38,15 @@ impl PluginValidation for AddBlocker {
reject!()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_add_blocker_len() {
let add_blocker = AddBlocker {};
let serialized = add_blocker.try_to_vec().unwrap();
assert_eq!(serialized.len(), add_blocker.len());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,88 @@ use borsh::{BorshDeserialize, BorshSerialize};
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Default)]
pub struct Attribute {
/// The Key of the attribute.
pub key: String, // 4
pub key: String, // 4 + len
/// The Value of the attribute.
pub value: String, // 4
pub value: String, // 4 + len
}

impl Attribute {
const BASE_LEN: usize = 4 // The length of the Key string
+ 4; // The length of the Value string
}

impl DataBlob for Attribute {
fn len(&self) -> usize {
Self::BASE_LEN + self.key.len() + self.value.len()
}
}

/// The Attributes plugin allows the authority to add arbitrary Key-Value pairs to the asset.
#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Default)]
pub struct Attributes {
/// A vector of Key-Value pairs.
pub attribute_list: Vec<Attribute>, // 4
pub attribute_list: Vec<Attribute>, // 4 + len * Attribute
}

impl Attributes {
const BASE_LEN: usize = 4; // The length of the attribute list

/// Initialize the Attributes plugin, unfrozen by default.
pub fn new() -> Self {
Self::default()
}
}

impl DataBlob for Attributes {
fn get_initial_size() -> usize {
4
}

fn get_size(&self) -> usize {
4 // TODO: Implement this.
fn len(&self) -> usize {
Self::BASE_LEN
+ self
.attribute_list
.iter()
.map(|attr| attr.len())
.sum::<usize>()
}
}

impl PluginValidation for Attributes {}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_attribute_len() {
let attribute = Attribute {
key: "test".to_string(),
value: "test".to_string(),
};
let serialized = attribute.try_to_vec().unwrap();
assert_eq!(serialized.len(), attribute.len());
}

#[test]
fn test_attributes_default_len() {
let attributes = Attributes::new();
let serialized = attributes.try_to_vec().unwrap();
assert_eq!(serialized.len(), attributes.len());
}

#[test]
fn test_attributes_len() {
let attributes = Attributes {
attribute_list: vec![
Attribute {
key: "test".to_string(),
value: "test".to_string(),
},
Attribute {
key: "test2".to_string(),
value: "test2".to_string(),
},
],
};
let serialized = attributes.try_to_vec().unwrap();
assert_eq!(serialized.len(), attributes.len());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ use crate::{
pub struct ImmutableMetadata {}

impl DataBlob for ImmutableMetadata {
fn get_initial_size() -> usize {
0
}

fn get_size(&self) -> usize {
fn len(&self) -> usize {
// Stateless data blob
0
}
}
Expand All @@ -32,3 +29,15 @@ impl PluginValidation for ImmutableMetadata {
reject!()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_immutable_metadata_len() {
let immutable_metadata = ImmutableMetadata {};
let serialized = immutable_metadata.try_to_vec().unwrap();
assert_eq!(serialized.len(), immutable_metadata.len());
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,56 @@
use borsh::{BorshDeserialize, BorshSerialize};

use crate::plugins::PluginValidation;
use crate::{plugins::PluginValidation, state::DataBlob};

/// The master edition plugin allows the creator to specify details on the master edition including max supply, name, and uri.
/// The default authority for this plugin is the creator.
#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize, Default, Debug, PartialEq, Eq)]
pub struct MasterEdition {
/// The max supply of editions
pub max_supply: Option<u32>,
pub max_supply: Option<u32>, // 1 + optional 4
/// optional master edition name
pub name: Option<String>,
pub name: Option<String>, // 1 + optional 4
/// optional master edition uri
pub uri: Option<String>,
pub uri: Option<String>, // 1 + optional 4
}

impl MasterEdition {
const BASE_LEN: usize = 1 // The max_supply option
+ 1 // The name option
+ 1; // The uri option
}

impl PluginValidation for MasterEdition {}

impl DataBlob for MasterEdition {
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())
+ self.uri.as_ref().map_or(0, |uri| 4 + uri.len())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_master_edition_default_len() {
let master_edition = MasterEdition::default();
let serialized = master_edition.try_to_vec().unwrap();
assert_eq!(serialized.len(), master_edition.len());
}

#[test]
fn test_master_edition_len() {
let master_edition = MasterEdition {
max_supply: Some(100),
name: Some("test".to_string()),
uri: Some("test".to_string()),
};
let serialized = master_edition.try_to_vec().unwrap();
assert_eq!(serialized.len(), master_edition.len());
}
}
Loading
Loading