Skip to content

feat(graphql): add transactions_by_digest - #1450

Open
DaughterOfMars wants to merge 6 commits into
developfrom
feat/transactions-by-digest
Open

feat(graphql): add transactions_by_digest#1450
DaughterOfMars wants to merge 6 commits into
developfrom
feat/transactions-by-digest

Conversation

@DaughterOfMars

Copy link
Copy Markdown
Contributor

Adds a batched transaction fetch to the GraphQL client, backed by transactionsByDigests.

That field, unlike the transactionIds filter of transactionBlocks, also returns transactions that are not checkpointed yet. It is paged, but the caller already bounds the result by the digests it passes, so the pages are walked internally rather than handed back as a Page; a response that runs out of pages before every digest is accounted for is an error, so a HashMap short of a key always means "not found".

The test needs a localnet (make test-with-localnet) and has not been run here.

🤖 Generated with Claude Code

Backed by `transactionsByDigests`, which — unlike the `transactionIds`
filter of `transactionBlocks` — also covers transactions that are not
checkpointed yet. The server pages that field, but the caller already
bounds the result by the digests it passes, so the pages are walked
internally and the digests come back as a map.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Thoralf-M

Copy link
Copy Markdown
Member

For what are we adding this?

@Thoralf-M

Copy link
Copy Markdown
Member

Ok just because it's in the schema

Comment on lines +89 to +90
TransactionBlocksQueryArgs, TransactionBlocksWithEffectsQuery, TransactionsByDigestsPage,
TransactionsByDigestsQuery, TransactionsByDigestsQueryArgs, TransactionsFilter,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe more of a general question, but why are we making these part of the public API?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So, the thing is a user can use these types to interact with graphql when using Client::run_query. Without them, the user would have to define these types themselves.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And do they really need to interact with Client::run_query if we offer all the high lever APIs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Well, I don't know. But we added that fn so they could

pub async fn transactions_by_digest(
&self,
digests: Vec<Arc<TransactionDigest>>,
) -> Result<HashMap<Arc<TransactionDigest>, SignedTransaction>> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Apparently, HashMap in return position like that is unusable in Go and TS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hmm, do you know what the alternative is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably just a Vector in the same order as the request

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

that's a bummer

nodes_seen += page.nodes.len();
for node in page.nodes.into_iter().flatten() {
let transaction: SignedTransaction = node.try_into()?;
transactions.insert(transaction.transaction.digest(), transaction);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We already have the digests, order is kept, can we avoid recomputing them, it's actually quite heavy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

although I feel a bit uneasy trusting the server here

Comment on lines +104 to +108
let operation = TransactionsByDigestsQuery::build(TransactionsByDigestsQueryArgs {
digests: digest_strings.clone(),
limit,
cursor,
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about chunking the request itself? What if I want to request more digests than the maximum body size allowed? Default payload size is 5000 bytes so header excluded, there wouldn't be any way to request more than ~90 digests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm a little unclear about what the max length refers to. The doc comment says it's the length of the string, but is it actually byte length?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants