Thoughts on the token standard

I have explained above, we want to support, but due to security concerns, we have to give up support.
And the explanation of @mariop also allows us to see why it needs to be dropped.

Oh, wow, I didn’t know the IC architecture had such hard limitations. Especially the stuck calls. In that case, can any canister ever safely call another canister? Because I assume this is a problem for all inter-canister interactions.

Not sure if I am right or wrong here but…
The way I see it - if the canisters you wrote have correct code in them which will always work and has no bugs, then that kind of eliminates any possibility of an async method getting stuck, even though possibility exists ? Or are there any caveats that might happen in the canister that I am not aware of and cause a stuck method, breaking functionality? @mariop

I think Mario possibly gave this example about ledger canister getting stuck if we are “awaiting” execution of a callback method defined in a separate canister to which ledger canister should automatically make a call after each transaction to notify it, because some people might not know they must implement that callback method in their canister if they want to work with ledger canister that has that kind of functionality, which would undoubtedly happen.

But if YOU are writing your own canisters and making inter-canister calls that are async, code works etc, I don’t see how this might happen.

The scenario that @mariop has in mind is not that of a canister which does not implement the callback (in this case the IC will return an error message to the caller) but a malicious canister which never returns an answer to the call of the ledger.
So (as @AnonymousCoder says) notifying trusted canisters should be ok (provided that they are not buggy) but notifying arbitrary canisters (as I’m guessing @RmbRT suggests) is quite problematic.

2 Likes

Correct, this is what I suggested. But extrapolating from that fact, we now can’t have any open composable systems of canisters that can interact with other canisters. The only way to safely implement such an interaction is to output something that the user then has to pass to another canister in another transaction.
However, there are two problems with this:

  • The user is not guaranteed to issue this transaction, so the initial canister cannot possibly rely on an issued action being executed (not even guaranteed to happen eventually).
  • The recipient canister might have to verify that data, and for that, would have to query the source canister for verification. However, as I understand it, if the receiving canister does not explicitly trust the source canister, it cannot even contact it for verification.

Thus, the IC is extremely limited in what kinds of ecosystem you can design in it. You can only create closed groups of canisters that trust each other, but cannot really extend them. Unless you create a developer-authorised dynamic web of trust for canisters, which to me smells like attacking the problem from the wrong side. You have this one issue in the protocol of the IC regarding inter-canister calls, and that hinders all attempts to make a powerful, simple and safe to use token standard. This one technical limitation has now led to limited composability of canisters, needlessly complex transaction workflows, complex logic within canisters, and forced developers to maintain some form of whitelist for canisters to interact with.

Is it impossible to force a canister call to definitely return eventually at the protocol level, or to support making a call that does not expect a return message on the IC (therefore, does not wait for a reply)? If so, why? The second option seems trivially possible to me and I think it would solve a lot of problems regarding inter-canister event propagation. It would allow generic handling and issuing of events without having to make both canisters whitelist each other or forcing users to make multi-step transactions.
I know there is still the problem of a call being rejected or never being executed because of issues with the destination canister’s message queue, but at least a call would no longer have the ability to completely incapacitate the caller canister.

6 Likes

Please also see my thread here, glad you agree:

3 Likes

Completely agree, I think it makes much more sense for the IC to implement some form of time-out.

5 Likes

Good thread. It’d definitely be something we need sooner rather than later, as the IC is still fairly fresh and the roads towards different design choices aren’t completely blocked yet.

2 Likes

The Ledger notify method is another approach. It is more secure than the one you proposed because it gives the responsibility to deliver the notification to the sender.

I’m not sure I understand. Isn’t the “Ledger notify method” the first approach, where the sender calls the notify method of the ledger canister, which then calls some predefined method of a receiver canister? Do you mind sending a link to the Candid for this method?

Agreed with your concern. FWIW, I think the “one-shot messaging” solution proposed by @JensGroth would be a great-to-have option for canister developers. A developer can elect to send a “one-shot message” to an untrusted canister if they’d like.

1 Like

The method is here. notify is separate from send and must be triggered by the caller after send succeeded.

Ah I see. I’m not familiar with the Rosetta interface.

If a user calls this method, will the Rosetta node forward it directly to the receiver canister, or does it still go through the ICP ledger canister?

This isn’t the rosetta interface though. This is the old Ledger API that will be deprecated soon.

The method is in the ICP ledger canister so it will go through the Ledger canister and that’s unsafe.

It’s confusing because the URL’s directory structure implies otherwise at first glance.

Does this mean my application and canister is going to break? Is there a newer API I should be targeting instead?

Agreed and naming doesn’t help too. The structure was set in place before I joined and it’s hard to change it right now because of a lot of workflow, inside and outside Dfinity, that use that url.

At some point we would like applications to not use notify from the ledger because of the problems it has. The plan is to eventually remove notify, at least in the current form. New dapps should use only the public interface of the ledger.

I’m sorry, this link is guarded by an “dfinity account” login wall, but I can’t find any such saved login in my browser.

It should be fixed now.

Thanks. So the new flow is:

  1. User sends ICP to canister via ICP ledger, and receives the block index as a result.
  2. User sends information about where to find the TX to the canister.
  3. Canister calls ICP ledger’s query_blocks() with the block ID, and receives back the block containing the TX.

I take it the returned block does not have to be verified any further, and can be trusted, since it came from the ICP ledger?

1 Like

Yes. For additional security I suggest to call query_blocks as an update instead of a query. In this way the IC will guarantee that the response can be trusted.

2 Likes

Since @RmbRT wants to call query_blocks from another canister it has to be an update call anyway. There’s no way to do inter-canister query calls, in particular not across subnets.

2 Likes