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

fix: collection hash indexing #2

Merged
merged 1 commit into from
Jul 27, 2023
Merged
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: 64 additions & 12 deletions blockbuster/src/programs/bubblegum/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ pub enum Payload {
data_hash: [u8; 32],
args: MetadataArgs,
},
SetAndVerifyCollection {
CollectionVerification {
collection: Pubkey,
args: MetadataArgs,
verify: bool,
},
}
//TODO add more of the parsing here to minimize program transformer code
Expand Down Expand Up @@ -195,18 +197,15 @@ impl ProgramParser for BubblegumParser {
Some(build_creator_verification_payload(keys, ix_data, true)?);
}
InstructionName::UnverifyCreator => {
let payload = build_creator_verification_payload(keys, ix_data, false)?;
b_inst.payload = Some(payload);
b_inst.payload =
Some(build_creator_verification_payload(keys, ix_data, false)?);
}
// We don't extract any additional info w.r.t. verify and unverify
// collection ops for now.
InstructionName::SetAndVerifyCollection => {
// Deserializing this to get to the second argument encoded in the slice,
// which is the collection address. Is there a (safe) way to get to that
// directly?
let _args: MetadataArgs = MetadataArgs::try_from_slice(ix_data)?;
let collection: Pubkey = Pubkey::try_from_slice(ix_data)?;
Comment on lines -207 to -208
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this never had the right offset for MetadataArgs or collection, which you figured out, and yesterday I found that SetAndVerify doesn't pass this parsing on mainline at the moment.

b_inst.payload = Some(Payload::SetAndVerifyCollection { collection });
InstructionName::VerifyCollection | InstructionName::SetAndVerifyCollection => {
b_inst.payload = Some(build_collection_verification_payload(ix_data)?);
}
InstructionName::UnverifyCollection => {
b_inst.payload =
Some(build_collection_unverification_payload(keys, ix_data)?);
}
InstructionName::Unknown => {}
_ => {}
Expand Down Expand Up @@ -252,3 +251,56 @@ fn build_creator_verification_payload(
args,
})
}

// See Bubblegum for offsets and positions:
// https://github.com/metaplex-foundation/mpl-bubblegum/blob/main/programs/bubblegum/README.md#-verify_collection-unverify_collection-and-set_and_verify_collection
// Note: Collection from the args is used to update the collection in Bubblegum, so use it as the source of truth (instead of collection via accounts).
fn build_collection_verification_payload(ix_data: &[u8]) -> Result<Payload, BlockbusterError> {
let metadata_offset = 108;
let collection_byte_size = 32;
let metadata_byte_end = ix_data.len() - collection_byte_size;

// Ensure data is valid.
if ix_data.len() < metadata_offset + collection_byte_size {
return Err(BlockbusterError::InstructionParsingError);
}

let args_raw = ix_data[metadata_offset..metadata_byte_end].to_vec();
let args = MetadataArgs::try_from_slice(&args_raw)?;
let collection_raw = ix_data[metadata_byte_end..].to_vec();
let collection: Pubkey = Pubkey::try_from_slice(&collection_raw)?;

Ok(Payload::CollectionVerification {
collection,
args,
verify: true,
})
}

// See Bubblegum for offsets and positions:
// https://github.com/metaplex-foundation/mpl-bubblegum/blob/main/programs/bubblegum/README.md#-verify_collection-unverify_collection-and-set_and_verify_collection
// NOTE: Unverfication does not include collection. This needs to be fixed in the README.
fn build_collection_unverification_payload(
keys: &[plerkle_serialization::Pubkey],
ix_data: &[u8],
) -> Result<Payload, BlockbusterError> {
let collection_index = 8;
let metadata_offset = 108;
if ix_data.len() < metadata_offset {
return Err(BlockbusterError::InstructionParsingError);
}

let args_raw = ix_data[metadata_offset..].to_vec();
let args = MetadataArgs::try_from_slice(&args_raw)?;
let collection_raw = keys
.get(collection_index)
.ok_or(BlockbusterError::InstructionParsingError)?
.0;
Comment on lines +295 to +298
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just an FYI, that I also had a draft PR for blockbuster that added explicit support for Verify and Unverify collection: github.com/metaplex-foundation/pull/21.

But I ended up not needing the change for the ordering PR since I added a verify flag and additional sequence number to manage the data out of order.

I don't think this results in a change for what you are doing, I'm just telling you as more of an FYI.

I suppose one thing you could consider is just using index 8 from the accounts to get collection every time, since its always in the same accounts location for VerifyCollection, UnverifyCollection, and SetAndVerifyCollection.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between the index 8 account and the one in the instruction args? Why do both exist?

let collection: Pubkey = Pubkey::try_from_slice(&collection_raw)?;

Ok(Payload::CollectionVerification {
collection,
args,
verify: false,
})
}