Non-upgradeability due to infinite execution time (if any)?

I read somewhere that canister upgrades can be (e.g. maliciously) prevented by another canister called by it by not returning from the call.

But how come that a call could not return? It is limited by 40 Billion cycles, so any update call finishes in a finite time, doesn’t it? What is this time? Can a hacker prolong this time by doing repeated HTTPS outcalls (a slow operation)?

I see a contradiction: I read that canister update may not return in a finite time, but here it is limited. Explain me, please.

P.S. Kapa.AI: “we can estimate that 40 billion instructions would take approximately 2 seconds to execute”

1 Like

When processing a call, a canister either has to produce a response or make a call on its own. It can, as you suggest, simply keep doing slow operations forever (or as long as it has cycles). So it may not technically be forever, but in practice it is

But isn’t making a call considered as a separate update operation, so that the canister would be upgradeable interim?

public shared func f() {
  h();
  // would be upgradeable at this point
  await g(); // or for example doing HTTPS outcall
}

All of the calls between replicas are async so you are reliant on the replying canister to eventually return. If there are open contexts then you can’t upgrade.

This should be kind of fixed with scalable messaging which lets you set a timeout.


canister 1:

public shared func forever() {
  while(true){
     let x = await Random.blob();  //this will burn a ton of cycles, but never return
  };
};

canister 2:

public shared func f() {
  h();
  
  await canister1.forever(); // becomes never upgradable
};