and suppose the value passed to ic0.msg_cycles_accept128 does not exceed the value reported by ic0.msg_cycles_available128 and I make no other calls to accept cycles in between. Then what are the exact conditions under which these calls can result in less cycles accepted than wanted? I read one condition is the accepting canister has reached its maximum cycle balance. But that is probably unlikely to happen or can be tested for.
So is it safe to rely on the second one going through as intended or not? I know that ic0.msg_cycles_accept128 tells me how much actually were accepted but I would still like to rely on it before making the call.
If it is safe then let’s assume there is a commit point (e.g. await in Motoko) between the calls. Then one thing that could happen is that the continuation traps in which ic0.msg_cycles_accept128 would never run. So having a commit point between them is likely not safe.
As an additional question are these statements correct?
It is not possible after accepting cycles to put (some of) them back, i.e. “unaccept” them
It is not possible to add cycles to a response with ic0.call_cycles_add
So is it safe to rely on the second one going through as intended or not?
If you call ic0.msg_cycles_available128 and ic0.msg_cycles_accept128 without yielding execution in between (e.g., due to await), then I don’t see why you wouldn’t be able to accept all the available cycles.
So having a commit point between them is likely not safe.
Indeed.
It is not possible after accepting cycles to put (some of) them back, i.e. “unaccept” them.
Indeed.
It is not possible to add recycles to a response with ic0.call_cycles_add
What do you mean by “recycles”? Response is not a call so you cannot attach cycles to a response using ic0.call_cycles_add. The cycles you do not accept are automatically refunded to the caller upon response.
Just cycles. Must have been a typo/auto-complete error.
Yes, unfortunately. Would be kind of nice to generalise either cycles_accept to negative values or cycles_add to response message. Then we could safely accept cycles and put them back if needed. And even make calls that are entirely “cycle withdrawals”, i.e. send 0 cycles in the first place but get some back. Especially in the light of asymmetry of trust and the fact that we shouldn’t call untrusted canisters this is useful.
Thanks for the answer above which answers everything.
I read one condition is the accepting canister has reached its maximum cycle balance.
I guess you refer to this section here. But even if the canister balance exceeded 2^128-1, all cycles would still be accepted and deducted from the available cycles of the call context. It’s just that the canister balance that will be capped at 2^128-1.