Skip to content
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

Clarify ingress expiry semantics #5080

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

yvonneanne
Copy link
Contributor

@yvonneanne yvonneanne commented Feb 11, 2025

A request's ingress_expiry keeps raising questions.
This PR adds clarifications to the different semantics for call and read_state.

@github-actions github-actions bot added the interface-spec Changes to the IC Interface Specification label Feb 11, 2025
Copy link

github-actions bot commented Feb 11, 2025

🤖 Here's your preview: https://hhcgk-raaaa-aaaam-abahq-cai.icp0.io

@yvonneanne yvonneanne marked this pull request as ready for review February 12, 2025 10:29
@yvonneanne yvonneanne requested a review from a team as a code owner February 12, 2025 10:29

The synchronous call endpoint is useful for users as it removes the networking overhead of polling the IC to determine the status of their call.
The synchronous call endpoint is useful for users as it removes the networking overhead of polling the IC to determine the status of their call if a terminal state is reached quickly.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure how to best improve it but "reached quickly" is vague, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, but imo it is simply incorrect without it...

An alternative could be the following, wdyt?

Suggested change
The synchronous call endpoint is useful for users as it removes the networking overhead of polling the IC to determine the status of their call if a terminal state is reached quickly.
The synchronous call endpoint is useful for users as it reduces the networking overhead of polling the IC to determine the status of their call.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the alternative better! Thanks!

@@ -596,7 +596,7 @@ The Internet Computer has two HTTPS APIs for canister calling:

3. The IC asks the targeted canister if it is willing to accept this message and be charged for the expense of processing it. This uses the [Ingress message inspection](#system-api-inspect-message) API for normal calls. For calls to the management canister, the rules in [The IC management canister](#ic-management-canister) apply.

4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). At the time of this transition, the call has not yet expired. Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
Copy link
Contributor

Choose a reason for hiding this comment

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

I find point 8 a bit confusing as well:

In the case that the call has been retained for long enough, but the request has not expired yet

Can we be specific on "long enough" and "has not yet expired"?

Stupid question: does this relate to the "ingress_expiriry" field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this relates to the ingress_expiry field.
I added a few sentences about subnet time and call expiry above. Does this make it more clear what "has not expired" means here? If not, can you make a suggestion?

(let's discuss "long enough" in L646/647)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, thanks! That's helpful!

Copy link
Member

Choose a reason for hiding this comment

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

Not introduced by this PR, but what does "the user should be able to ask any endpoint about the status of the pending call" mean here? Doesn't the user have to go to read_state endpoint?

Copy link
Contributor

Choose a reason for hiding this comment

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

what does "the user should be able to ask any endpoint about the status of the pending call" mean here? Doesn't the user have to go to read_state endpoint?

I was confused by that: the user must use the read state endpoint for retrieve the status of a pending call.


Calls must stay in `replied` or `rejected` long enough for polling users to catch the response.
Calls stay in `replied` or `rejected` long enough for polling users to catch the response under good networking conditions with low load.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also be specific of what it means "long enough"?

Copy link
Contributor Author

@yvonneanne yvonneanne Feb 14, 2025

Choose a reason for hiding this comment

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

iirc, this is vague on purpose (I asked the same question some time ago and I don't remember the answer, maybe because it will always be too short in some case, so the precise value doesn't really matter?). Can someone more familiar with the interface spec history comment on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

It should be five minutes. Is there a reason to keep this private, @derlerd-dfinity ?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't remember details of this discussion, but I could imagine the following reasons why it was decided to remain vague:

  1. Not specifying how long we keep things around would allow to easily change it in the future.
  2. Under high load (i.e., when hitting the memory limits of the ingress history) both rejected and replied statuses might immediately be transitioned to done. So even if we specified 5 minutes here I can't see how it could be useful to an application, as the 5 minutes are just a good weather property rather than a guarantee. Applications should make sure to not rely on being able to observe replied or rejected anyways.

I think (2) is the more important reason.

I don't feel strongly about mentioning / not mentioning the 5 minutes, as long as it is clear that even if the application manages to get a request through and an answer back within 5 minutes it might miss the rejected/replied status nevertheless and instead only see the done status.

Copy link
Contributor

Choose a reason for hiding this comment

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

Under high load (i.e., when hitting the memory limits of the ingress history) both rejected and replied statuses might immediately be transitioned to done. So even if we specified 5 minutes here I can't see how it could be useful to an application, as the 5 minutes are just a good weather property rather than a guarantee.

What's the motivation behind distinguishing "done" and "pruned" then?

Copy link
Contributor

@derlerd-dfinity derlerd-dfinity Feb 20, 2025

Choose a reason for hiding this comment

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

By "pruned" you mean it is no longer in the tree? If so, the motivation is that done tells you that the message was processed and it might have been a rejected or a replied. For a status that is no longer in the tree (i.e., was "pruned") you know nothing, i.e., not even if it was processed.

Copy link
Contributor

Choose a reason for hiding this comment

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

By "pruned" you mean it is no longer in the tree?

Indeed.

If so, the motivation is that done tells you that the message was processed and it might have been a rejected or a replied. For a status that is no longer in the tree (i.e., was "pruned") you know nothing, i.e., not even if it was processed.

If the message times out here, then it can end up in the "done" status although it was never processed. So the "done" status only seems to make a difference if the subnet time is less than the ingress expiry.

Copy link
Contributor

Choose a reason for hiding this comment

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

So the "done" status only seems to make a difference if the subnet time is less than the ingress expiry.

Yeah, good point.

@@ -642,16 +645,20 @@ The characteristic property of the `processing` state is that *the initial effec
A call may be rejected by the IC or the canister. In either case, there is no guarantee about how much processing of the call has happened.

To avoid replay attacks, the transition from `done` or `received` to `pruned` must happen no earlier than the call's `ingress_expiry` field.
If a subnet's time is greater than a call's `ingress_expiry` field and it is still unknown to the IC (i.e, it was never in state `received`, `processing`, `replied`, `rejected`, or `done`), then the call will never be in one of these states.
Copy link
Contributor

Choose a reason for hiding this comment

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

it is still unknown to the IC (i.e, it was never in state

could we suggest how to check this, e.g., the state is unknown when the subnet's time exceeded the call's ingress expiry, but is less than the call's ingress expiry plus 5 minutes?

Copy link
Contributor

Choose a reason for hiding this comment

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

@@ -751,7 +758,7 @@ In order to read parts of the [The system state tree](#state-tree), the user mak

- `request_type` (`text`): Always `read_state`

- `sender`, `nonce`, `ingress_expiry`: See [Authentication](#authentication)
- `sender`, `nonce`, `ingress_expiry`: See [Authentication](#authentication). `ingress_expiry` refers to this request's expiry, not the expiry of an earlier call request.
Copy link
Contributor

Choose a reason for hiding this comment

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

This request might not refer to any earlier call request in which case the note can be confusing.

@@ -596,7 +599,7 @@ The Internet Computer has two HTTPS APIs for canister calling:

3. The IC asks the targeted canister if it is willing to accept this message and be charged for the expense of processing it. This uses the [Ingress message inspection](#system-api-inspect-message) API for normal calls. For calls to the management canister, the rules in [The IC management canister](#ic-management-canister) apply.

4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). At the time of this transition, the call has not yet expired. Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
Copy link
Member

@oggy-dfin oggy-dfin Feb 20, 2025

Choose a reason for hiding this comment

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

Suggested change
4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). At the time of this transition, the call has not yet expired. Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). This transition can only happen before the target canister's time (as visible in the [state tree](#state-tree-time)) exceeds the [`ingress_expiry`](#http-call) field of the request which submitted the call. Furthermore, the user should also be able to ask any endpoint about the status of the pending call.

Copy link
Contributor

Choose a reason for hiding this comment

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

ingress_time => ingress_expiry

Copy link
Member

Choose a reason for hiding this comment

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

thanks, fixed

@@ -588,6 +588,9 @@ The Internet Computer has two HTTPS APIs for canister calling:
- [*Asynchronous*](#http-async-call-overview) canister calling, where the user must poll the Internet Computer for the status of the canister call by _separate_ HTTPS requests.
- [*Synchronous*](#http-sync-call-overview) canister calling, where the status of the canister call is in the response of the original HTTPS request.

The publicly exposed state of a subnet (including the status of calls to its canisters) evolves in rounds. Each round is associated with a discrete timestamp, see [Time](#state-tree-time).
Copy link
Member

Choose a reason for hiding this comment

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

I'd propose to delete this discussion here and move it to where ingress_expiry is used, I'll make a suggestion below.

@@ -596,7 +596,7 @@ The Internet Computer has two HTTPS APIs for canister calling:

3. The IC asks the targeted canister if it is willing to accept this message and be charged for the expense of processing it. This uses the [Ingress message inspection](#system-api-inspect-message) API for normal calls. For calls to the management canister, the rules in [The IC management canister](#ic-management-canister) apply.

4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
4. At some point, the IC may accept the call for processing and set its status to `received`. This indicates that the IC as a whole has received the call and plans on processing it (although it may still not get processed if the IC is under high load). At the time of this transition, the call has not yet expired. Furthermore, the user should also be able to ask any endpoint about the status of the pending call.
Copy link
Member

Choose a reason for hiding this comment

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

Not introduced by this PR, but what does "the user should be able to ask any endpoint about the status of the pending call" mean here? Doesn't the user have to go to read_state endpoint?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interface-spec Changes to the IC Interface Specification
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants