-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Create new index for tracking Asset metadata #2445
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need the test to be working before merging this.
Thanks for all your help @AurelienFT ❤️ |
@@ -2,6 +2,12 @@ scalar Address | |||
|
|||
scalar AssetId | |||
|
|||
type AssetInfoDetails { | |||
contractId: HexString! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure here, but maybe we want to use ContractId!
here, as in other places.
|
||
fn asset_info(&self, asset_id: &AssetId) -> StorageResult<Option<AssetDetails>>; | ||
|
||
fn asset_exists(&self, asset_id: &AssetId) -> StorageResult<bool>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like asset_exists
is not used, can we remove it?
}, | ||
}; | ||
|
||
/// Contract info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Contract info | |
/// Asset info |
/// Contract info | ||
pub struct AssetsInfo; | ||
|
||
pub type AssetDetails = (ContractId, Bytes32, u64); // (contract_id, sub_id, total_amount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use struct with named fields? Something similar to what we have here.
db.storage::<AssetsInfo>() | ||
.insert(&asset_id, &(*contract_id, **sub_id, current_count))?; | ||
} | ||
_ => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please enumerate all variants explicitly to avoid surprises when new variant is added in the future.
.map(|info| { | ||
info.2 | ||
.checked_add(*val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.map(|info| { | |
info.2 | |
.checked_add(*val) | |
.map(|info| { | |
let (_, _, count) = *info; | |
count | |
.checked_add(*val) |
May also affect the Receipt::Burn
branch.
let current_count = match db.storage::<AssetsInfo>().get(&asset_id) { | ||
Ok(count) => count, | ||
Err(_) => { | ||
// If asset doesn't exist yet, create it with 0 count | ||
db.storage::<AssetsInfo>() | ||
.insert(&asset_id, &(*contract_id, **sub_id, 0))?; | ||
Some(Cow::Owned((*contract_id, **sub_id, 0))) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shouldn't treat all storage errors as "value not found". Some of them should just be bubbled up.
Maybe something like this will work:
let current_count = match db.storage::<AssetsInfo>().get(&asset_id)? {
Some(count) => Some(count),
None => {
// If asset doesn't exist yet, create it with 0 count
db.storage::<AssetsInfo>()
.insert(&asset_id, &(*contract_id, **sub_id, 0))?;
Some(Cow::Owned((*contract_id, **sub_id, 0)))
}
}
If you agree, please note that now two branches always return Some
, so maybe we can get rid of the follow-up map()
as well.
}) | ||
.map(|info| { | ||
info.2 | ||
.checked_sub(*val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go down to 0
on Burn
should we remove the asset from the index? Unless we need to distinguish between "never minted" and "minted and totally burned" cases.
Anyway, currently the index may grow indefinitely.
Which also makes me think that I should consider this for the balances indexation I added recently :-)
cc: @xgreenx, wdyt?
.map(|info| { | ||
info.2 | ||
.checked_add(*val) | ||
.ok_or(anyhow::anyhow!("Asset count overflow")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may consider integrating this with the IndexationError
available here: https://github.com/FuelLabs/fuel-core/blob/master/crates/fuel-core/src/graphql_api/indexation.rs#L28
It's a common type for all errors related to integration and it'll grow even more variants after the "coins to spend" indexation is merged. See here.
.0; | ||
|
||
// Then | ||
// We should have the minted amount first |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// We should have the minted amount first | |
// We should have the minted amount reduced by the burned amount |
} | ||
.map(|info| { | ||
info.2 | ||
.checked_add(*val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider the following scenario:
- client v.0.40 running
- asset A in contract B is minted (count=10)
- we update the client to the one that supports index
- asset A in contract B is minted again (count=10, for a total count of 20)
- we query the asset info
- it notices there is no index, initializes it with 0 and adds 10
- we have inconsistency (10 vs 20)
I may not have full picture, but if you see this as a possible scenario, please consider enabling access to this endpoint conditionally, ie. it should be available only when the client was started with a clear database and have a chance to sync from genesis (and build the complete index). This is what we did with other indexes (see for example around here).
Linked Issues/PRs
Closes Add indexation
AssetId -> (ContractId, SubId)
#2425Related to Consider
assets
in check-account utility fuels-ts#3373Description
This introduces a new GraphQL endpoint that returns info about an asset.
The off-chain worker indexes
Mint
andBurn
events to store this metadata about anAssetId
Checklist
Before requesting review
After merging, notify other teams
[Add or remove entries as needed]