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

[FA migration] Dynamically process FA mapping #698

Merged
merged 8 commits into from
Feb 4, 2025
Merged

Conversation

bowenyang007
Copy link
Collaborator

@bowenyang007 bowenyang007 commented Jan 27, 2025

Summary

We were getting the FA mapping via a hardcoded list of top 100 coins. Now we want to generate this dynamically. The idea is to:

  1. Maintain a mapping of v1 coin type to fungible asset address (derived from coin type)
  2. Persist that mapping in a new table called coin_to_fungible_asset_mapping
  3. When starting processor, bootstrap the mapping from postgres table.
  4. Update and use mapping locally
  5. Store new entries into postgres for next time.

This strategy works because the mapping is guaranteed to be idempotent.

Also to be absolutely correct we're still using the constants file. Only if it can't find it in the constants file will we look in the dynamic mapping.

[WARNING] This only applies to processors built on top of SDK because we can't easily persist a mapping with the old code.

Backfill

Genesis because we need to create the mapping table
Testnet: 0
Mainnet: 0

Testing

@bowenyang007 bowenyang007 requested review from rtso and yuunlimm January 27, 2025 21:39
@bowenyang007 bowenyang007 changed the title [] [FA migration] Dynamically process FA mapping Jan 27, 2025
Copy link

codecov bot commented Jan 27, 2025

Codecov Report

Attention: Patch coverage is 76.56766% with 71 lines in your changes missing coverage. Please review.

Project coverage is 50.2%. Comparing base (279ad33) to head (4928c52).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ocessor/src/processors/fungible_asset_processor.rs 71.4% 32 Missing ⚠️
...t_fungible_asset_processor/parquet_fa_extractor.rs 0.0% 17 Missing ⚠️
...t_models/raw_v2_fungible_asset_to_coin_mappings.rs 83.7% 7 Missing ⚠️
...ngible_asset_processor/fungible_asset_extractor.rs 79.3% 6 Missing ⚠️
...uet_processors/parquet_fungible_asset_processor.rs 0.0% 4 Missing ⚠️
.../fungible_asset_processor/fungible_asset_storer.rs 85.1% 4 Missing ⚠️
rust/integration-tests/src/models/fa_v2_models.rs 0.0% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main    #698     +/-   ##
=======================================
+ Coverage   50.0%   50.2%   +0.1%     
=======================================
  Files        251     253      +2     
  Lines      28335   28575    +240     
=======================================
+ Hits       14181   14352    +171     
- Misses     14154   14223     +69     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@bowenyang007 bowenyang007 requested a review from rtso January 30, 2025 07:30
@bowenyang007 bowenyang007 marked this pull request as ready for review January 30, 2025 23:33
Copy link
Contributor

@just-in-chang just-in-chang left a comment

Choose a reason for hiding this comment

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

few comments but overall looks good

Comment on lines 105 to 108
let mut fa_extractor = FungibleAssetExtractor::new();
fa_extractor
.bootstrap_coin_to_fa_mapping(self.db_pool.clone())
.await?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe instead just call the bootstrapping method in the new method/merge the new and bootstrap methods? And just pass the db pool into the new method

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i thought about it but it's the norm to have new not async. In this case it's probably a nonissue but I can imagine some cases (e.g. singleton) where that delineation avoids bugs.

#[derive(Clone, Debug, Deserialize, FieldCount, Identifiable, Insertable, Serialize)]
#[diesel(primary_key(coin_type))]
#[diesel(table_name = coin_to_fungible_asset_mappings)]
pub struct CoinToFungibleAssetMapping {
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need to duplicate this struct for tests lol

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess they include whatever here for testing. If it's not here then it won't be used in tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

the current paradigm is for those models with inserted at column, seems like this table doesn't, then we can probably reuse the model struct defined in the db.

Comment on lines 74 to 76
pub trait CoinToFungibleAssetMappingConvertible {
fn from_raw(raw: RawCoinToFungibleAssetMapping) -> Self;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think we need an explicit trait just for this

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Maybe. I'm just following the existing paradigm. I agree that it feels a bit redundant vs just using From. Let's keep discussing in slack.

Copy link
Contributor

Choose a reason for hiding this comment

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

good point @just-in-chang yeah since we don't do any batch conversion,and will have distinct structs for parquet and postgres models I think we can simply use From here instead. I can do as a part of refactoring I am doing

Comment on lines 26 to 34
impl CoinToFungibleAssetMappingConvertible for CoinToFungibleAssetMapping {
fn from_raw(raw: RawCoinToFungibleAssetMapping) -> Self {
Self {
coin_type: raw.coin_type,
fungible_asset_metadata_address: raw.fungible_asset_metadata_address,
last_transaction_version: raw.last_transaction_version,
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of having a custom trait, u could just impl From<RawCoinToFungibleAssetMapping> for CoinToFungibleAssetMapping and call .into() when needed

Copy link
Contributor

Choose a reason for hiding this comment

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

nvm seems like all the other models have a trait like this lol... dunno why but ok

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yup.

Comment on lines 504 to 510
let mut kv_mapping: CoinToFungibleAssetMappings = AHashMap::new();
for mapping in data {
kv_mapping.extend(mapping);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hmm this is also the existing paradigm let's fix it together in a different PR lol.

// TODO: make this more generic to load all fields, then we should be able to run tests for all processor in one test case.

* this is created b/c there is inserted_at field which isn't defined in the Event struct, we can't just load the events directly without specifying the fields.
* TODO: make this more generic to load all fields, then we should be able to run tests for all processor in one test case.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: TODO comment can be removed

#[derive(Clone, Debug, Deserialize, FieldCount, Identifiable, Insertable, Serialize)]
#[diesel(primary_key(coin_type))]
#[diesel(table_name = coin_to_fungible_asset_mappings)]
pub struct CoinToFungibleAssetMapping {
Copy link
Contributor

Choose a reason for hiding this comment

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

the current paradigm is for those models with inserted at column, seems like this table doesn't, then we can probably reuse the model struct defined in the db.

}
}

/// Get the asset_type_v1 (coin type) from either the mapping or the constant mapping
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: comment was a bit confusing to me. either the dynamic mapping table or the static ?

Comment on lines 74 to 76
pub trait CoinToFungibleAssetMappingConvertible {
fn from_raw(raw: RawCoinToFungibleAssetMapping) -> Self;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

good point @just-in-chang yeah since we don't do any batch conversion,and will have distinct structs for parquet and postgres models I think we can simply use From here instead. I can do as a part of refactoring I am doing

@bowenyang007 bowenyang007 force-pushed the fix_balance branch 2 times, most recently from ee8e9b5 to 6b65601 Compare February 1, 2025 22:20
Copy link
Contributor

@just-in-chang just-in-chang left a comment

Choose a reason for hiding this comment

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

Left few nits but could also just address these in a separate PR cuz they aren't specific to the changes here

Comment on lines +175 to +177
pub trait FungibleAssetToCoinMappingConvertible {
fn from_raw(raw: RawFungibleAssetToCoinMapping) -> Self;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets just get rid of this cuz we're stopping with this pattern

Comment on lines +26 to +34
impl FungibleAssetToCoinMappingConvertible for FungibleAssetToCoinMapping {
fn from_raw(raw: RawFungibleAssetToCoinMapping) -> Self {
Self {
fungible_asset_metadata_address: raw.fungible_asset_metadata_address,
coin_type: raw.coin_type,
last_transaction_version: raw.last_transaction_version,
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@@ -355,6 +395,11 @@ impl ProcessorTrait for FungibleAssetProcessor {
.map(CurrentUnifiedFungibleAssetBalance::from_raw)
.collect();

let postgres_fa_to_coin_mappings: Vec<FungibleAssetToCoinMapping> = fa_to_coin_mappings
.into_iter()
.map(FungibleAssetToCoinMapping::from_raw)
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of the trait we can just Into::into

@yuunlimm yuunlimm mentioned this pull request Feb 3, 2025
@bowenyang007 bowenyang007 merged commit 9bcb77e into main Feb 4, 2025
11 checks passed
@bowenyang007 bowenyang007 deleted the fix_balance branch February 4, 2025 06:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants