Paginate get_cashtoken_addresses, get_unspent, and get_transactions#165
Open
yashasvi-ranawat wants to merge 2 commits into
Open
Paginate get_cashtoken_addresses, get_unspent, and get_transactions#165yashasvi-ranawat wants to merge 2 commits into
yashasvi-ranawat wants to merge 2 commits into
Conversation
Unbounded queries against the Chaingraph endpoint fail with a DB error for tokens with many holders (e.g. 4710 UTXOs). Add limit/offset pagination with CASHTOKEN_ADDRESSES_PAGE_SIZE=1000 and use LONG_DEFAULT_TIMEOUT=60 per page in NetworkAPI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
yashasvi-ranawat
marked this pull request as ready for review
April 29, 2026 20:06
Unbounded search_output queries fail or time out for addresses with many UTXOs or transactions. Add limit/offset pagination (PAGE_SIZE=1000) and use LONG_DEFAULT_TIMEOUT=60 per page, matching the pattern introduced for get_cashtoken_addresses. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses Chaingraph query failures for high-activity addresses/tokens by adding limit/offset pagination to previously unbounded GraphQL queries, and increasing timeouts to accommodate multi-page fetches.
Changes:
- Added page-size constants and implemented limit/offset pagination loops for Chaingraph
get_transactions,get_unspent, andget_cashtoken_addresses. - Introduced a longer default timeout for potentially large result sets and applied it to the above calls via
NetworkAPI. - Added a docstring note warning that cashtoken holder queries may take over a minute due to pagination.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
bitcash/network/services.py |
Adds a long timeout constant and uses it for large-result calls; updates docstring note for cashtoken address lookup. |
bitcash/network/APIs/ChaingraphAPI.py |
Adds pagination parameters and loops to split large Chaingraph result sets into pages. |
Comments suppressed due to low confidence (4)
bitcash/network/APIs/ChaingraphAPI.py:239
- The current de-duplication strategy
sorted(set(transactions), key=lambda x: transactions.index(x))is O(n^2) due to repeated index() calls. With pagination enabling tens of thousands of transactions, this can become a major bottleneck; consider an order-preserving linear-time approach (e.g., tracking aseenset while building the list).
transactions = [_[0] for _ in transactions][::-1]
# remove duplicates, when address pays itself, spending tx and locking
# tx are same transactions
transactions = sorted(set(transactions), key=lambda x: transactions.index(x))
return transactions
bitcash/network/APIs/ChaingraphAPI.py:336
- This paginated loop queries
block(limit: 1, order_by: {height: desc}, ...)on every page even though the block height is only used as a constant reference. Consider fetching the latest block height once (separate query) and then paginating only the search_output query to reduce per-page load and latency.
query GetUTXO($lb: _text!, $node: String!, $limit: Int!, $offset: Int!) {
block(
limit: 1
order_by: { height: desc }
where: { accepted_by: { node: { name: { _like: $node } } } }
) {
bitcash/network/APIs/ChaingraphAPI.py:360
- Offset/limit pagination is used here, but the search_output query does not specify an order_by. Without deterministic ordering, offset pagination can return overlapping pages or skip rows, causing missing UTXOs. Add a stable order_by (e.g., transaction_hash asc, output_index asc) when paginating.
]
}
limit: $limit
offset: $offset
) {
bitcash/network/APIs/ChaingraphAPI.py:547
- Offset/limit pagination is used for output holders, but the output query does not specify an order_by. Without deterministic ordering, offset pagination can skip/duplicate rows between pages and produce incomplete address sets. Add a stable order_by (e.g., by transaction_hash/output_index or another unique ordering) when paginating.
]
}
limit: $limit
offset: $offset
) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
31
to
+36
| # Default API call total time timeout | ||
| DEFAULT_TIMEOUT = 5 | ||
|
|
||
| # Timeout for queries that may fetch large result sets | ||
| LONG_DEFAULT_TIMEOUT = 60 | ||
|
|
| @@ -364,6 +367,8 @@ def get_cashtoken_addresses( | |||
| :param has_token: If True, only return addresses holding fungible tokens of this category. | |||
| :returns: A set of addresses holding the cashtoken. | |||
| :raises ConnectionError: If all API services fail. | |||
| @@ -161,6 +164,8 @@ def get_transactions(self, address: str, *args, **kwargs) -> list[str]: | |||
| } | |||
| ] | |||
| } | |||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Unbounded
search_outputqueries against the Chaingraph endpoint fail with a database error for addresses or tokens with many UTXOs/transactions. The previous implementation fetched all results in a single request withDEFAULT_TIMEOUT=5s.Changes
ChaingraphAPI.py: AddedCASHTOKEN_ADDRESSES_PAGE_SIZE,UNSPENT_PAGE_SIZE, andTRANSACTIONS_PAGE_SIZE(all 1000).get_cashtoken_addresses,get_unspent, andget_transactionsnow use$limit/$offsetGraphQL variables and loop with limit/offset pagination until a page returns fewer thanPAGE_SIZErows.services.py: AddedLONG_DEFAULT_TIMEOUT = 60and switched all three methods to use it (wasDEFAULT_TIMEOUT = 5).Real-world tests
Moria USD (
b38a33f750f84c5c169a6f23cb873e6e79605021585d4f3408789689ed87f366): fetched 4,710 UTXOs → 595 unique addresses in ~57 seconds — 5 pages of 1,000 at 2–19 seconds per page.bitcoincash:qpnezxnfun4vgwypja3j4f4fzjdyf7ddgvfwvza6f5: fetched 18,823 UTXOs in ~35 seconds via Chaingraph (19 pages) vs 4 seconds via Fulcrum; 41,274 transactions in 3 seconds via Fulcrum.