Skip to content

Commit

Permalink
Changes for AppData, LinkedAppData, and DataSection DAS indexin…
Browse files Browse the repository at this point in the history
…g and updates to related js tests (#174)

* Serialize external JSON data as JSON object rather than String

* Do not convert MsgPack encoded data to String in tests

Also add MsgPack to LinkedAppData tests

* Fix test for MsgPack case
  • Loading branch information
danenbm authored Jul 26, 2024
1 parent 0c5c8f3 commit 2406166
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 44 deletions.
42 changes: 22 additions & 20 deletions clients/js/test/externalPlugins/appData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ type TestContext = {
dataAuthority: PluginAuthority;
wrongDataAuthoritySigner?: Signer;
wrongDataAuthority?: PluginAuthority;
data: string;
otherData: string;
data: Uint8Array;
otherData: Uint8Array;
};

async function generateTestContext(
Expand Down Expand Up @@ -76,19 +76,21 @@ async function generateTestContext(
}
}

let data = '';
let otherData = '';
let data = new Uint8Array();
let otherData = new Uint8Array();

if (schema === ExternalPluginAdapterSchema.Binary) {
data = 'Hello, world!';
otherData = 'Hello, world! Hello, world!';
const binaryData = 'Hello, world!';
const binaryOtherData = 'Hello, world! Hello, world!';
data = Uint8Array.from(Buffer.from(binaryData));
otherData = Uint8Array.from(Buffer.from(binaryOtherData));
} else if (schema === ExternalPluginAdapterSchema.Json) {
data = JSON.stringify({ message: 'Hello', target: 'world' });
otherData = JSON.stringify({
message: 'Hello hello',
target: 'big wide world',
});
const dataJson = { message: 'Hello', target: 'world' };
const otherDataJson = { message: 'Hello hello', target: 'big wide world' };
data = Uint8Array.from(Buffer.from(JSON.stringify(dataJson)));
otherData = Uint8Array.from(Buffer.from(JSON.stringify(otherDataJson)));
} else if (schema === ExternalPluginAdapterSchema.MsgPack) {
data = msgpack.encode({ message: 'Hello', target: 'msgpack' }).toString();
data = msgpack.encode({ message: 'Hello', target: 'msgpack' });
}

if (!dataAuthoritySigner) {
Expand Down Expand Up @@ -181,7 +183,7 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
dataAuthority,
},
authority: dataAuthoritySigner,
data: Uint8Array.from(Buffer.from(data)),
data,
asset: asset.publicKey,
}).sendAndConfirm(umi);

Expand All @@ -190,9 +192,9 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = Uint8Array.from(Buffer.from(data));
assertData = data;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(data);
assertData = JSON.parse(Buffer.from(data).toString());
}

await assertAsset(t, umi, {
Expand Down Expand Up @@ -262,9 +264,9 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = Uint8Array.from(Buffer.from(data));
assertData = data;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(data);
assertData = JSON.parse(Buffer.from(data).toString());
}

await assertAsset(t, umi, {
Expand Down Expand Up @@ -296,9 +298,9 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = Uint8Array.from(Buffer.from(otherData));
assertData = otherData;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(otherData);
assertData = JSON.parse(Buffer.from(otherData).toString());
}

await assertAsset(t, umi, {
Expand Down Expand Up @@ -452,7 +454,7 @@ test(`updating a plugin before a secure app data does not corrupt the data`, asy
asset: asset.publicKey,
}).sendAndConfirm(umi);

const assertData = JSON.parse(data);
const assertData = JSON.parse(Buffer.from(data).toString());

await assertAsset(t, umi, {
...DEFAULT_ASSET,
Expand Down
46 changes: 27 additions & 19 deletions clients/js/test/externalPlugins/linkedAppData.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import test from 'ava';
import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests';
import { Signer, Umi } from '@metaplex-foundation/umi';
import * as msgpack from '@msgpack/msgpack';
import {
assertAsset,
assertCollection,
Expand Down Expand Up @@ -35,8 +36,8 @@ type TestContext = {
dataAuthority: PluginAuthority;
wrongDataAuthoritySigner?: Signer;
wrongDataAuthority?: PluginAuthority;
data: string;
otherData: string;
data: Uint8Array;
otherData: Uint8Array;
};

async function generateTestContext(
Expand Down Expand Up @@ -81,17 +82,21 @@ async function generateTestContext(
}
}

let data = '';
let otherData = '';
let data = new Uint8Array();
let otherData = new Uint8Array();

if (schema === ExternalPluginAdapterSchema.Binary) {
data = 'Hello, world!';
otherData = 'Hello, world! Hello, world!';
const binaryData = 'Hello, world!';
const binaryOtherData = 'Hello, world! Hello, world!';
data = Uint8Array.from(Buffer.from(binaryData));
otherData = Uint8Array.from(Buffer.from(binaryOtherData));
} else if (schema === ExternalPluginAdapterSchema.Json) {
data = JSON.stringify({ message: 'Hello', target: 'world' });
otherData = JSON.stringify({
message: 'Hello hello',
target: 'big wide world',
});
const dataJson = { message: 'Hello', target: 'world' };
const otherDataJson = { message: 'Hello hello', target: 'big wide world' };
data = Uint8Array.from(Buffer.from(JSON.stringify(dataJson)));
otherData = Uint8Array.from(Buffer.from(JSON.stringify(otherDataJson)));
} else if (schema === ExternalPluginAdapterSchema.MsgPack) {
data = msgpack.encode({ message: 'Hello', target: 'msgpack' });
}

if (!dataAuthoritySigner) {
Expand Down Expand Up @@ -202,9 +207,9 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = Uint8Array.from(Buffer.from(data));
assertData = data;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(data);
assertData = JSON.parse(Buffer.from(data).toString());
}

// check the derived asset sdk correctly injects the data
Expand Down Expand Up @@ -299,9 +304,9 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = Uint8Array.from(Buffer.from(data));
assertData = data;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(data);
assertData = JSON.parse(Buffer.from(data).toString());
}

// check the derived asset sdk correctly injects the data
Expand Down Expand Up @@ -350,10 +355,13 @@ DATA_AUTHORITIES.forEach((dataAuthorityType) => {
asset: asset.publicKey,
}).sendAndConfirm(umi);

if (schema === ExternalPluginAdapterSchema.Binary) {
assertData = Uint8Array.from(Buffer.from(otherData));
if (
schema === ExternalPluginAdapterSchema.Binary ||
schema === ExternalPluginAdapterSchema.MsgPack
) {
assertData = otherData;
} else if (schema === ExternalPluginAdapterSchema.Json) {
assertData = JSON.parse(otherData);
assertData = JSON.parse(Buffer.from(otherData).toString());
}

// check the derived asset sdk correctly injects the data
Expand Down Expand Up @@ -559,7 +567,7 @@ test(`updating a plugin before a secure app data does not corrupt the data`, asy
],
});

const assertData = Uint8Array.from(Buffer.from(data));
const assertData = data;

// check the derived asset sdk correctly injects the data
await assertAsset(
Expand Down
49 changes: 44 additions & 5 deletions clients/rust/src/indexable_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,40 @@ pub struct IndexableUnknownPluginSchemaV1 {
pub data: String,
}

#[cfg(feature = "serde")]
mod custom_serde {
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value as JsonValue;

pub fn serialize<S>(data: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match data {
Some(s) => {
if let Ok(json_value) = serde_json::from_str::<JsonValue>(s) {
json_value.serialize(serializer)
} else {
serializer.serialize_str(s)
}
}
None => serializer.serialize_none(),
}
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let json_value: Option<JsonValue> = Option::deserialize(deserializer)?;
match json_value {
Some(JsonValue::String(s)) => Ok(Some(s)),
Some(json_value) => Ok(Some(json_value.to_string())),
None => Ok(None),
}
}
}

/// Schema used for indexing known external plugin types.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
Expand All @@ -57,7 +91,10 @@ pub struct IndexableExternalPluginSchemaV1 {
pub data_offset: Option<u64>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub data_len: Option<u64>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Option::is_none", with = "custom_serde")
)]
pub data: Option<String>,
}

Expand Down Expand Up @@ -228,11 +265,13 @@ impl ProcessedExternalPlugin {
let (data_offset, data_len, data) = match external_plugin_data_info {
Some(data_info) => {
let schema = match &adapter_config {
ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => {
&lifecycle_hook.schema
}
ExternalPluginAdapter::LifecycleHook(lc_hook) => &lc_hook.schema,
ExternalPluginAdapter::AppData(app_data) => &app_data.schema,
_ => &ExternalPluginAdapterSchema::Binary, // is this possible
ExternalPluginAdapter::LinkedLifecycleHook(l_lc_hook) => &l_lc_hook.schema,
ExternalPluginAdapter::LinkedAppData(l_app_data) => &l_app_data.schema,
ExternalPluginAdapter::DataSection(data_section) => &data_section.schema,
// Assume binary for `Oracle`, but this should never happen.
ExternalPluginAdapter::Oracle(_) => &ExternalPluginAdapterSchema::Binary,
};

(
Expand Down

0 comments on commit 2406166

Please sign in to comment.