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

Bubblegum Update Metadata Version 1 #134

Merged
merged 49 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
09a599d
Add code to index Bubblegum Update Metadata
danenbm Oct 15, 2023
5ef2eb9
Update rust toolchain file
danenbm Oct 15, 2023
7dcf74b
Merge branch 'main' into danenbm/update-metadata-parsing
danenbm Oct 17, 2023
2084aa7
Fix moved variable after merge
danenbm Oct 17, 2023
269bf0d
Add code from mintV1 that allows for empty URI
danenbm Oct 17, 2023
bdf8e3c
Ordering using asset.seq initially applied to update_metadata
danenbm Oct 18, 2023
0240ce5
Add simple check for whether asset was decompressed to Bubblegum tran…
danenbm Oct 19, 2023
c26c693
Don't prevent sequence number update when already decompressed
danenbm Oct 19, 2023
dd891e8
Add sequence number to downloading metadata background task
danenbm Oct 19, 2023
97fe275
Add sequence number migration (Sea ORM not regenerated yet)
danenbm Oct 20, 2023
660a6ba
Regenerate Sea-ORM types
danenbm Oct 20, 2023
213dac5
Use new sequence numbers for Bubblegum Update Metadata
danenbm Oct 20, 2023
026c16a
Extra condition to protect out of order creator verification
danenbm Oct 21, 2023
e797adc
Remove base_info_seq for each creator and add creators_added_seq to a…
danenbm Oct 23, 2023
f2b1218
Regenerate Sea-ORM types
danenbm Oct 23, 2023
77020fa
Change creator metadata updates to use new creators_added_seq
danenbm Oct 23, 2023
ab1f1b4
Factor out common creator update code to helper function
danenbm Oct 23, 2023
3581269
Update to latest blockbuster beta
danenbm Dec 4, 2023
cb97203
Merge branch 'main' into danenbm/update-metadata-parsing
danenbm Dec 4, 2023
e62eb61
Use less than or equal for download metadata seq check
danenbm Dec 4, 2023
5808834
Index verified for token metadata collection
danenbm Dec 4, 2023
e38f64a
Add slot_updated to initial asset upsert, and removed duplicate items
danenbm Dec 4, 2023
933e299
Remove asset_was_decompressed
danenbm Dec 4, 2023
8732ba9
Rename royalty_amount_seq to base_info_seq
danenbm Dec 4, 2023
2500687
Fix typo in WHERE clause
danenbm Dec 4, 2023
fe1d522
Do not delete existing creators in mint_v1
danenbm Dec 4, 2023
d26fe00
Update comments around database txns
danenbm Dec 4, 2023
c4b1ab4
Use transaction in mint_V1 and update_metadata
danenbm Dec 4, 2023
9e305c9
Use transaction for other Bubblegum instructions asset table updates
danenbm Dec 4, 2023
c3798c0
Fix tree_id key index in update_metadata
danenbm Dec 4, 2023
7c0f9be
Remove use of was_decompressed flag on asset table
danenbm Dec 6, 2023
974966e
Add migration to remove was_decompressed and regenerate SeaORM types
danenbm Dec 6, 2023
6ccfb91
Combine upsert_asset_base_info and upsert_creators and add lock
danenbm Dec 9, 2023
b7c9ebe
Remove unneeded creators_added_seq
danenbm Dec 9, 2023
fa0839d
Switch to EXCLUSIVE mode lock
danenbm Dec 9, 2023
4b96e97
Add NULL condition check on asset.seq
danenbm Dec 13, 2023
8803152
Refactored creator indexing
danenbm Dec 18, 2023
1a80b98
Add conditions to creator upsert, add another check at DAS API level
danenbm Dec 18, 2023
2c14eeb
Rename asset_creators.verified_seq back to just regular seq
danenbm Dec 18, 2023
4c39726
Remove unneeded condition on asset_authority upsert
danenbm Dec 20, 2023
f669e76
Apply stale creator filtering to all DAS API queries
danenbm Dec 20, 2023
9155fa1
Use latest blockbuster beta release
danenbm Dec 21, 2023
6ccd27a
Remove download_metadata_seq and add URI match check instead
danenbm Dec 21, 2023
ef1f811
Fix task URI initial query
danenbm Dec 21, 2023
3dc3557
Regenerate Sea ORM types without download_metadata_seq
danenbm Dec 21, 2023
15d323e
Merge branch 'main' into danenbm/update-metadata-parsing
danenbm Dec 21, 2023
896af3d
asset_grouping.verified option remove
danenbm Dec 21, 2023
36df8e5
Fix filtering for getAssetsByCreator
danenbm Dec 21, 2023
c2875df
Update to blockbuster 0.9.0-beta.5 and mpl-bubblegum 1.0.1-beta.4
danenbm Jan 2, 2024
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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Because this is a multi component system the easiest way to develop or locally t
#### Regenerating DB Types
Edit the init.sql, then run `docker compose up db`
Then with a local `DATABASE_URL` var exported like this `export DATABASE_URL=postgres://solana:solana@localhost/solana` you can run
` sea-orm-cli generate entity -o ./digital_asset_types/src/dao/generated/ --database-url $DATABASE_URL --with-serde both --expanded-format`
`sea-orm-cli generate entity -o ./digital_asset_types/src/dao/generated/ --database-url $DATABASE_URL --with-serde both --expanded-format`

If you need to install `sea-orm-cli` run `cargo install sea-orm-cli`.

Expand Down
2 changes: 1 addition & 1 deletion das_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ schemars = "0.8.6"
schemars_derive = "0.8.6"
open-rpc-derive = { version = "0.0.4"}
open-rpc-schema = { version = "0.0.4"}
blockbuster = "0.9.0-beta.1"
blockbuster = "=0.9.0-beta.4"
anchor-lang = "0.28.0"
mpl-token-metadata = { version = "=2.0.0-beta.1", features = ["serde-feature"] }
mpl-candy-machine-core = { version = "2.0.1", features = ["no-entrypoint"] }
Expand Down
2 changes: 1 addition & 1 deletion digital_asset_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ solana-sdk = "~1.16.16"
num-traits = "0.2.15"
num-derive = "0.3.3"
thiserror = "1.0.31"
blockbuster = "0.9.0-beta.1"
blockbuster = "=0.9.0-beta.4"
jsonpath_lib = "0.3.0"
mime_guess = "2.0.4"
url = "2.3.1"
Expand Down
6 changes: 3 additions & 3 deletions digital_asset_types/src/dao/generated/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub struct Model {
pub data_hash: Option<String>,
pub creator_hash: Option<String>,
pub owner_delegate_seq: Option<i64>,
pub was_decompressed: bool,
pub leaf_seq: Option<i64>,
pub base_info_seq: Option<i64>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
Expand Down Expand Up @@ -76,8 +76,8 @@ pub enum Column {
DataHash,
CreatorHash,
OwnerDelegateSeq,
WasDecompressed,
LeafSeq,
BaseInfoSeq,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
Expand Down Expand Up @@ -131,8 +131,8 @@ impl ColumnTrait for Column {
Self::DataHash => ColumnType::Char(Some(50u32)).def().null(),
Self::CreatorHash => ColumnType::Char(Some(50u32)).def().null(),
Self::OwnerDelegateSeq => ColumnType::BigInteger.def().null(),
Self::WasDecompressed => ColumnType::Boolean.def(),
Self::LeafSeq => ColumnType::BigInteger.def().null(),
Self::BaseInfoSeq => ColumnType::BigInteger.def().null(),
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions digital_asset_types/src/dao/generated/asset_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ pub struct Model {
pub metadata: Json,
pub slot_updated: i64,
pub reindex: Option<bool>,
pub raw_name: Vec<u8>,
pub raw_symbol: Vec<u8>,
pub raw_name: Option<Vec<u8>>,
pub raw_symbol: Option<Vec<u8>>,
pub base_info_seq: Option<i64>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
Expand All @@ -40,6 +41,7 @@ pub enum Column {
Reindex,
RawName,
RawSymbol,
BaseInfoSeq,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
Expand Down Expand Up @@ -70,9 +72,10 @@ impl ColumnTrait for Column {
Self::MetadataMutability => Mutability::db_type(),
Self::Metadata => ColumnType::JsonBinary.def(),
Self::SlotUpdated => ColumnType::BigInteger.def(),
Self::Reindex => ColumnType::Boolean.def(),
Self::RawName => ColumnType::Binary.def(),
Self::RawSymbol => ColumnType::Binary.def(),
Self::Reindex => ColumnType::Boolean.def().null(),
Self::RawName => ColumnType::Binary.def().null(),
Self::RawSymbol => ColumnType::Binary.def().null(),
Self::BaseInfoSeq => ColumnType::BigInteger.def().null(),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions digital_asset_types/src/dao/generated/asset_grouping.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3

use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
Expand All @@ -12,15 +12,15 @@ impl EntityName for Entity {
}
}

#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize, Deserialize)]
pub struct Model {
pub id: i64,
pub asset_id: Vec<u8>,
pub group_key: String,
pub group_value: Option<String>,
pub seq: Option<i64>,
pub slot_updated: Option<i64>,
pub verified: Option<bool>,
pub verified: bool,
pub group_info_seq: Option<i64>,
}

Expand Down
2 changes: 1 addition & 1 deletion digital_asset_types/src/dao/generated/cl_audits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Model {
pub seq: i64,
pub level: i64,
pub hash: Vec<u8>,
pub created_at: Option<DateTime>,
pub created_at: DateTime,
pub tx: String,
}

Expand Down
112 changes: 56 additions & 56 deletions digital_asset_types/src/dao/generated/sea_orm_active_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,6 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "mutability")]
pub enum Mutability {
#[sea_orm(string_value = "immutable")]
Immutable,
#[sea_orm(string_value = "mutable")]
Mutable,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
enum_name = "v1_account_attachments"
)]
pub enum V1AccountAttachments {
#[sea_orm(string_value = "edition")]
Edition,
#[sea_orm(string_value = "edition_marker")]
EditionMarker,
#[sea_orm(string_value = "master_edition_v1")]
MasterEditionV1,
#[sea_orm(string_value = "master_edition_v2")]
MasterEditionV2,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "task_status")]
pub enum TaskStatus {
Expand All @@ -44,6 +16,22 @@ pub enum TaskStatus {
Success,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
enum_name = "specification_versions"
)]
pub enum SpecificationVersions {
#[sea_orm(string_value = "unknown")]
Unknown,
#[sea_orm(string_value = "v0")]
V0,
#[sea_orm(string_value = "v1")]
V1,
#[sea_orm(string_value = "v2")]
V2,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
Expand All @@ -60,6 +48,36 @@ pub enum RoyaltyTargetType {
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "owner_type")]
pub enum OwnerType {
#[sea_orm(string_value = "single")]
Single,
#[sea_orm(string_value = "token")]
Token,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "mutability")]
pub enum Mutability {
#[sea_orm(string_value = "immutable")]
Immutable,
#[sea_orm(string_value = "mutable")]
Mutable,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "chain_mutability")]
pub enum ChainMutability {
#[sea_orm(string_value = "immutable")]
Immutable,
#[sea_orm(string_value = "mutable")]
Mutable,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
Expand Down Expand Up @@ -88,38 +106,20 @@ pub enum SpecificationAssetClass {
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "chain_mutability")]
pub enum ChainMutability {
#[sea_orm(string_value = "immutable")]
Immutable,
#[sea_orm(string_value = "mutable")]
Mutable,
#[sea_orm(string_value = "unknown")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
enum_name = "specification_versions"
enum_name = "v1_account_attachments"
)]
pub enum SpecificationVersions {
#[sea_orm(string_value = "unknown")]
Unknown,
#[sea_orm(string_value = "v0")]
V0,
#[sea_orm(string_value = "v1")]
V1,
#[sea_orm(string_value = "v2")]
V2,
}
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "owner_type")]
pub enum OwnerType {
#[sea_orm(string_value = "single")]
Single,
#[sea_orm(string_value = "token")]
Token,
pub enum V1AccountAttachments {
#[sea_orm(string_value = "edition")]
Edition,
#[sea_orm(string_value = "edition_marker")]
EditionMarker,
#[sea_orm(string_value = "master_edition_v1")]
MasterEditionV1,
#[sea_orm(string_value = "master_edition_v2")]
MasterEditionV2,
#[sea_orm(string_value = "unknown")]
Unknown,
}
43 changes: 41 additions & 2 deletions digital_asset_types/src/dao/scopes/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,15 @@ pub async fn get_related_for_assets(
}
}

let creators = asset_creators::Entity::find()
let mut creators = asset_creators::Entity::find()
.filter(asset_creators::Column::AssetId.is_in(ids.clone()))
.order_by_asc(asset_creators::Column::AssetId)
.order_by_asc(asset_creators::Column::Position)
.all(conn)
.await?;

filter_out_stale_creators(&mut creators);

for c in creators.into_iter() {
if let Some(asset) = assets_map.get_mut(&c.asset_id) {
asset.creators.push(c);
Expand Down Expand Up @@ -371,11 +374,14 @@ pub async fn get_by_id(
.order_by_asc(asset_authority::Column::AssetId)
.all(conn)
.await?;
let creators: Vec<asset_creators::Model> = asset_creators::Entity::find()
let mut creators: Vec<asset_creators::Model> = asset_creators::Entity::find()
.filter(asset_creators::Column::AssetId.eq(asset.id.clone()))
.order_by_asc(asset_creators::Column::Position)
.all(conn)
.await?;

filter_out_stale_creators(&mut creators);

let grouping: Vec<asset_grouping::Model> = asset_grouping::Entity::find()
.filter(asset_grouping::Column::AssetId.eq(asset.id.clone()))
.filter(asset_grouping::Column::GroupValue.is_not_null())
Expand All @@ -397,3 +403,36 @@ pub async fn get_by_id(
groups: grouping,
})
}

fn filter_out_stale_creators(creators: &mut Vec<asset_creators::Model>) {
// If the first creator is an empty Vec, it means the creator array is empty (which is allowed
// for compressed assets in Bubblegum).
if !creators.is_empty() && creators[0].creator.is_empty() {
creators.clear();
} else {
// For both compressed and non-compressed assets, any creators that do not have the max
// `slot_updated` value are stale and should be removed.
let max_slot_updated = creators.iter().map(|creator| creator.slot_updated).max();
if let Some(max_slot_updated) = max_slot_updated {
creators.retain(|creator| creator.slot_updated == max_slot_updated);
}

// For compressed assets, any creators that do not have the max `seq` value are stale and
// should be removed. A `seq` value of 0 indicates a decompressed or never-compressed
// asset. So if a `seq` value of 0 is present, then all creators with nonzero `seq` values
// are stale and should be removed.
let seq = if creators
.iter()
.map(|creator| creator.seq)
.any(|seq| seq == Some(0))
{
Some(Some(0))
} else {
creators.iter().map(|creator| creator.seq).max()
};

if let Some(seq) = seq {
creators.retain(|creator| creator.seq == seq);
}
}
}
2 changes: 1 addition & 1 deletion digital_asset_types/src/dapi/common/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ pub fn to_grouping(
.filter_map(|model| {
let verified = match options.show_unverified_collections {
// Null verified indicates legacy data, meaning it is verified.
true => Some(model.verified.unwrap_or(true)),
true => Some(model.verified),
false => None,
};
// Filter out items where group_value is None.
Expand Down
9 changes: 5 additions & 4 deletions digital_asset_types/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ pub fn create_asset_data(
metadata: JsonValue::String("processing".to_string()),
slot_updated: 0,
reindex: None,
raw_name: metadata.name.into_bytes().to_vec().clone(),
raw_symbol: metadata.symbol.into_bytes().to_vec().clone(),
raw_name: Some(metadata.name.into_bytes().to_vec().clone()),
raw_symbol: Some(metadata.symbol.into_bytes().to_vec().clone()),
base_info_seq: Some(0),
},
)
}
Expand Down Expand Up @@ -155,8 +156,8 @@ pub fn create_asset(
alt_id: None,
creator_hash: None,
owner_delegate_seq: Some(0),
was_decompressed: false,
leaf_seq: Some(0),
base_info_seq: Some(0),
},
)
}
Expand Down Expand Up @@ -231,7 +232,7 @@ pub fn create_asset_grouping(
id: row_num,
group_key: "collection".to_string(),
slot_updated: Some(0),
verified: Some(false),
verified: false,
group_info_seq: Some(0),
},
)
Expand Down
Loading
Loading