Agoric / agoric-sdk

monorepo for the Agoric Javascript smart contract platform
Apache License 2.0
327 stars 206 forks source link

what escalator should a multi-promise resolution notification bundle use? #2252

Open warner opened 3 years ago

warner commented 3 years ago

What is the Problem Being Solved?

Cyclic promise resolutions interfere with our desired "retire upon resolution" pattern (#1124). To overcome this, @FUDCo has been working on batched resolutions: a single dispatch.notify() crank resolves multiple promises at the same time, so they can all be deserialized before any of the identifiers are retired. This has an ordering side-effect: the secondary promises get resolved earlier than they would have otherwise (our current scheduler is straight FIFO).

It occurred to me to think about how this will interact with the escalator schedulers. Resolution notifications can cause just as much work as a message delivery, so we want the notifications to travel on escalators just like deliveries. However if we're resolving multiple promises in a single notification, which escalator should it use? The simplest answer is to use the first promise in the batch (the one which was resolved first, and which dragged in all the others).

With an escalator-based scheduler, this changes the ordering side-effect somewhat: the secondary promises might get resolved earlier or later than they would have otherwise. Whoever is paying for the primary notification will also wind up paying for the secondaries. The secondary might get higher priority than they paid for, or they might pay for higher priority but not get it because the primary isn't paying for it.

Potential Solutions

Other than accepting the scheduling side-effect, I can think of a few possible answers:

cc @erights @dtribble

FUDCo commented 3 years ago

Since delivering a bundle of promises in a batch is really about managing the vat-kernel relationship rather than about resolving the promises per se, another approach that occurs to me would be to split the action taken when a promise resolution is delivered into a vat into two steps: (1) note the resolution value somewhere inside liveslots, then (2) actually resolve the underlying JS promise. These two steps could take place in different cranks. Since step 1 is essentially just internal bookkeeping, it need not participate in escalator scheduling but rather could just be treated as constant cost overhead, while step 2, which actually results in user code being executed, could be scheduled using the escalator.