Inter-Canister Query Calls (Status: done)

Summary

Currently, smart contract canisters can send update calls to any canister. These calls can even form “chains” of calls such as the following:

Imagine you have three canisters: A, B, and C.

A.updateCall() → B.updateCall() → C
Result: A gets a response in around 4 seconds*

*(if it’s within the same subnet, it could be much faster or as slow as 5 seconds per call if its cross-subnet)

This is helpful in making an application composed of multiple canisters calling each other. The “catch” is that update calls are replicated using consensus so they take around 2 seconds each. This means that if A calls B which calls C, then it may take 2 seconds (A → B) + 2 seconds (B → C) or 4 seconds for A to get a response. If one had a system where 10 canisters had to linearly call each other with update calls, it may take up to 20 seconds for the initial canister to get a response as each canister update call takes 2 seconds. Not great user experience.

Fortunately, we have query calls that are very very fast (around 200 ms) and can also be sent to any canister, but currently, they cannot be chained in the same way as “inter-canister query calls.” This project is about adding inter-canister query calls as a native feature to the IC.

This would allow the following chain to happen:

A.queryCall() → B.queryCall() → C
Result: A gets a response in around 400 milliseconds.

Rationale

This feature has been asked about many times and is the most popular in the community megathread. Here are some examples of the community asking for it:

  1. Megathread: Community Submissions for DFINITY Foundation’s Roadmap - #5 by wang
  2. Megathread: Community Submissions for DFINITY Foundation’s Roadmap - #34 by witter
  3. Fast Inter-Canister Query Calls - #3 by Steve
  4. Consensus and inter-canister calls - #7 by pie-silo

What you can do to help

  • Ask questions on intent, design, trade-offs
  • Propose design ideas
  • Propose a narrower or different scope for the project
  • Say whether you like or dislike prioritizing this project
  • Vote on proposals

Want to see what to expect? Check out project to get a sense of the emerging process: Increased Canister Smart Contract Memory

Documentation

This project is just starting, but there has been significant design thought put into this in the past (but not enough time to prioritize its implementation). More documentation will be posted here, but there are some helpful links to add context: https://sdk.dfinity.org/docs/developers-guide/tutorials/intercanister-calls.html

Key people involved

Ulan (@ulan ), Akhilesh Singhania (@akhilesh.singhania), bogdan warinschi (@bogwar )

34 Likes

Some questions to get started (nothing too surprising).

  • Will this work across subnets?
  • What happens when a query method is doing such a call during replicated execution (e.g. when itself called from another canister like now, or when itself called via update calls)?
  • Will adding this feature make it harder to add “certified queries” (i.e. queries that don’t go through ordering consensus, but are still signed by the subnet) in the future? Or maybe it makes that feature actually more likely (because with certified queries, we can actually implement inter-canister query-from-update calls that way, instead of falling back to crossnet messaging)?
14 Likes

Voicing a :+1: :pray: for this. Ideally after canisters can move ICP.

+1 on Nomeata’s questions.

5 Likes

For inter-canister calls, I think it would good if in addition to caller(), we have a command like original_caller() that gets the id of the first caller in a chain of calls. This would be like the meta data in the transaction for an Ethereum transaction.

2 Likes

That has been discussed a long time ago internally, and while it seems at first like an innocent feature, if you are coming from Ethereum, some of us deemed it possibly dangerous. But we should take this to a dedicated thread, as it isn’t really about inter-canister query calls, so if you want to hear my reasons, just start one :slight_smile:

4 Likes

I have created a new thread for your (as well as others’) thoughts and comments. :slight_smile:

2 Likes

Just voicing my support for this. I think creating a better experience within IC is more important than the integrations with BTC/ETH currently.

I think understanding resources requirements to do this would be helpful, what do we give up by having people work on making this possible, or is this a fairly easy thing to change? Are there any risks to this?

5 Likes

What is the reason for the previous restriction?

1 Like

could you please link the thread?

This feature has highest priority in our project. Our project has large amount of data distributed acros many canisters (possibly subnets).
For calculation we are planning implement MapReduce and execute it across those canisters and “eventually consistent” data just fine for us.

7 Likes

Cant wait to see this implemented!
Top priority for us!

3 Likes

Just an update for readers: the folks who own this project are a bit underwater at the moment, specially Ulan (you may have seen his video on memory management) but I hope to get this back up soon.

5 Likes

Is there any update on this?

Thank you for asking. I have been aiming to update but I keep getting pulled away.

Here is the status:

The team who can work on this has been pulled away on three major things so they have not spent much time on this.

For transparency, those big things are:

5 Likes

Those do sound important as well.

I’m curious if you know whether Rust canisters are somehow able to make inter-canister queries? I’ve heard that it’s possible in Rust but not Motoko—but it’s not documented anywhere.

2 Likes

Good question. I’m not aware so let me ask.

3 Likes

@jzxchiang, curious where you heard that, but that information is incorrect. Inter-canister queries are not currently supported by the IC, so not available in any language.

1 Like

I heard it here: https://twitter.com/lastmjs/status/1441637144024403974?t=0fWyxOndErg37zbxiX3YSQ&s=19

1 Like

The replica that shipped with dfx had an incomplete “tech preview” of that feature for a while. It was never a feature on “the” IC, but it might explain the confusion.

2 Likes

Interesting, didn’t know.

Well, quick plug for why inter-canister queries are important… I think it’s especially critical for multi-canister apps. For example, if there’s an auth canister that other canisters call to authorize requests they receive from end users, that would need to be a quick query and not a slow update.

Another situation is a BigMap-like setup, where a frontend canister queries a set of backend canisters to get the requested data. It’d be much simpler to have the client just interact with that one frontend canister, instead of having to get an index from the canister and then make the call directly to the appropriate backend canister.

I’m sure there are other use cases, but I do think this feature would make a big impact on developer productivity and the ability to scale apps to multiple canisters.

Personally, I think it’s important to make existing things work better—in addition to building new things (i.e. the BTC <> ICP integration).

5 Likes