Emit Messages from Query calls

I’m not sure if this is possible or already planned, but as a developer it would be useful to be able to emit messages from Query calls in “Fire and Forget” style.

A potential use-case I can imagine might be: I built a FooService specialized in serving multiple foos

service {
  getFoo query -> (nat : id) : async Foo;
  getBar query -> (nat : id) : async Bar;
  getBaz query -> (nat : id) : async Baz
}

My exposed methods are only serve their types, but I want to track how many times these methods are being called over time. Each time they’re called I’d like to emit a message to an analytics service.

Another example might be if I want to limit the number of times a specific caller access an endpoint, but I can accept if they burst their allocated capacity as long as they’re eventually limited.

in both cases I don’t care or need the response, I just want some service to process the message eventually.

2 Likes

This porposal comes up every now and then. There are some interesting questions to be answered first, though (who gets charged for these calls? what security guarantees we provide around these calls, as they’d original on a single node, and thus could be malicious? how to protect against DOS attacks), so don’t hold your breath.

Good question, honestly I don’t have any answers, but I’d be interested to hear what you think about the following thoughts:

who gets charged for these calls

I would say the canister emitting the messages, since they’d be charged for the query call anyways. It would be up-to the developer to guard their code.

security guarantees we provide around these calls

  1. The message and its contents haven’t been tampered with.
  2. It would be “provable” whom the message came from.

I don’t know the real shape of these messages, but I thought all data was signed, and therefore verifiable.

How to protect against DOS attacks

No idea here! How does the IC prevent bad actors from draining canisters using query calls today?

Ah, and there the rabbit is buried (German proverb). The query call is executed by a single, possibly untrustworthy node. So even if you put code in the query method that, say, makes sure you don’t invoke too many of these calls, there is nothing stopping a malicoius node to ignore that code and still do these calls. Or any other calls like that.

The security guarantees you list are precisely the desirable ones. But it is not obivious to see how to achieve them, given that the (possibly untrustworthy) node is the one that calculates the message and the content.

There are surely ideas worth exploring (e.g. making this opt-in, so that canisters can choose to accept the risks, or maybe re-processing the query on ingress to verifly that the submitting node didn’t lie…)

Query calls are charged separately, and there are quotas. I believe. But that’s a different problem than protecting replicated calls (e.g. going through consensus, possibly changing state) that originate from a possibly untrustworthy party (a single node).

2 Likes

eeek, I consider that!

There are surely ideas worth exploring (e.g. making this opt-in, so that canisters can choose to accept the risks, or maybe re-processing the query on ingress to verifly that the submitting node didn’t lie…)

With the above in mind I would definitely advocate for this being something a canister had to opt-into using. Hopefully something like this will be considered in the future, not needed today or in the immediate future, but I think this could open up some interesting doors! Thanks for sharing your thoughts!

2 Likes