-
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
Pagination queries for balances
endpoint
#2490
base: master
Are you sure you want to change the base?
Conversation
…tion_for_balances
@@ -79,8 +79,6 @@ impl BalanceQuery { | |||
Ok(balance) | |||
} | |||
|
|||
// TODO: This API should be migrated to the indexer for better support and | |||
// discontinued within fuel-core. | |||
#[graphql(complexity = "query_costs().balance_query")] |
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.
#[graphql(complexity = "query_costs().balance_query")] | |
#[graphql(complexity = "query_costs().balance_query + query_costs().storage_iterator \ | |
+ (query_costs().storage_read + first.unwrap_or_default() as usize) * child_complexity \ | |
+ (query_costs().storage_read + last.unwrap_or_default() as usize) * child_complexity\")] |
We need to limit the number of requested balances=)
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.
It also makes this change breaking
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.
Updated in fd2b019
@@ -233,15 +233,48 @@ impl OffChainDatabase for OffChainIterableKeyValueView { | |||
} | |||
} | |||
|
|||
fn balances( | |||
&self, | |||
fn balances<'a>( |
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.
Yeah, it is a tricky function because of how we handle balances.
Hmm, do you remember why we decided to skip balances during iteration and add them at the begin?
I remember: if you don't have coins but have messages, they will not appear during the iteration.
The problem with the current solution is when start == base_asset_id
. The current code will return an incorrect iterator.
Either we need to handle it differently, or come up with another solution. It would be nice if we could insert base asset balance into the mid of the iterator. Maybe we could change the indexation and make it always add empy indexation for the base asset(like entry in the balances table with 0 amount just for balances)?
Then during iteration we call always fetch its value by using self.base_asset_balance
?
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.
…tion_for_balances
Converting to draft, some rework is needed here. |
…tion_for_balances
…tion_for_balances
.into_boxed() | ||
} | ||
(IterDirection::Forward, Some(asset_id)) => { | ||
let start = (asset_id != *base_asset_id) |
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 asset_id == base_asset_id
, you will skip base asset while we should return it, since it is starting entry=)
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.
Ok, I was wondering why it actually works... :)
It turned out that even if we return the bass asset id here, it'll be skipped by the logic inside query_pagination
here. Internally, it kinda changes the notion of start
to actually mean after
.
So now the updated behavior always includes the start
entry in the output, even though it'll be filtered by the query. While it won't change the returned balances, it is now consistent with other pagination queries. This consistency might be actually important because the query code makes some further calculations about has_next_page
and other flags.
…tion_for_balances
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.
Very good usage of rust syntax and bricks. Liked it :)
@@ -79,9 +79,11 @@ impl BalanceQuery { | |||
Ok(balance) | |||
} | |||
|
|||
// TODO: This API should be migrated to the indexer for better support and |
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.
This is not something we want to do in the future anymore ? In my mind it's still something we want to do in the future to decouple both use cases of the node.
#[graphql(complexity = "query_costs().balance_query")] | ||
#[graphql( | ||
complexity = "query_costs().balance_query + query_costs().storage_iterator \ | ||
+ (query_costs().storage_read + first.unwrap_or_default() as usize) * child_complexity \ |
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.
The cost computation is hard to understand for me, maybe it's normal but it might requires a comment. What I don't understand :
- Why are we making pay for
first * child_complexity
+last * child_complexity
. Example :(4 * 10) + (9 * 10) = 130
. Inner question : Why are we paying if the first is far away and why are we paying again for all the numbers from0
tolast
some where already included in thefirst
computation.
What is logic to me is two solutions :
- Either we want people to pay for numbers before their first and so it would be :
(query_costs().storage_read + last.unwrap_or_default() as usize) * child_complexity
(because last is higher and include all the precents numbers)
- Either we just want to pay for the interval :
(query_costs().storage_read + (last.unwrap_or_default() as usize - first.unwrap_or_default() as usize)) * child_complexity
let start = (asset_id != *base_asset_id) | ||
.then_some(CoinBalancesKey::new(owner, &asset_id)); |
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.
Why are we redoing the comparaison here as we are already in the else
let start = (asset_id != *base_asset_id) | |
.then_some(CoinBalancesKey::new(owner, &asset_id)); | |
let start = Some(CoinBalancesKey::new(owner, &asset_id)); |
self.non_base_assets_first(start, owner, base_asset_id, direction) | ||
} | ||
(IterDirection::Reverse, Some(asset_id)) => { | ||
if asset_id == *base_asset_id { |
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 can leverage pattern matching as you did in non_base_asset_balances
don't really know if it's better or not. up to you :)
start.as_ref(), | ||
Some(direction), | ||
) | ||
.filter_map(move |result| match result { |
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.
It would be valuable in the future to have a comment about this behavior because reading the comments on the review helped me but it's not really future proof and without it I wouldn't understand why None
on base asset etc..
Closes #2023
TODO:
Description
This PR enables the paginated queries for balances, but only if the balance indexation is enabled. Otherwise, the attempt to send paginated query will result with
Can not use pagination when balances indexation is not available
error.Checklist
Before requesting review