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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

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 77.10438% with 68 lines in your changes missing coverage. Please review.

Project coverage is 49.7%. Comparing base (32af360) to head (617c462).

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 ⚠️
...uet_processors/parquet_fungible_asset_processor.rs 0.0% 4 Missing ⚠️
.../fungible_asset_processor/fungible_asset_storer.rs 85.1% 4 Missing ⚠️
...ngible_asset_processor/fungible_asset_extractor.rs 86.9% 3 Missing ⚠️
rust/integration-tests/src/models/fa_v2_models.rs 0.0% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main    #698     +/-   ##
=======================================
+ Coverage   49.5%   49.7%   +0.1%     
=======================================
  Files        252     254      +2     
  Lines      28535   28765    +230     
=======================================
+ Hits       14149   14315    +166     
- Misses     14386   14450     +64     

☔ 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 507
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

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