Agoric / agoric-sdk

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

deny passing Presences in arguments? #40

Open warner opened 5 years ago

warner commented 5 years ago

@erights @dtribble @Chris-Hibbert and I had a long discussion this morning about three-party handoff and WormholeOp and the "lost resolution bug". I won't be able to capture the full idea here, but one of the conclusions was that maybe we should change the swingset kernel to forbid passing Presences (i.e. objects) in the arguments of message sends (syscall.send()). They would be allowed as the target of syscall.send(), and in the arguments of syscall.resolve(), and could appear in dispatch.notify(). But they would never appear in the arguments of dispatch.notify(), and it would be a fatal error (terminating the vat) to include them in the arguments of syscall.send().

The rough issue is that three-party introductions between distant SwingSet machines are not synchronous. When Alice does bob!foo(carol), sending a Presence for carol to a Vat that does not yet have its own reference to carol, the message will arrive on Bob's Vat with instructions for how to contact Carol's vat, and an ID for some sort of handoff table entry on Carol. That will take a while to exercise, so Bob's vat won't have confirmation of the object's identity until Carol's vat responds. Since we want Presences to be canonical and comparable by identity, we (bob's vat) can't deliver/dispatch that foo message until after carol responds. But Alice may have sent another message right behind the foo, and we don't want Carol's vat to be able to deny liveness of messages that don't reference her. But we also want Alice's messages to be delivered in the order that she sent them.

We don't yet know how to deal with this for remote swingset machines, so we might want to forbid this case when the reference spans multiple machines. We can handle it for multiple vats within a single SwingSet machine, but it wouldn't be easy for a programmer to know when they can rely upon this (it kind of creates a new class of reference: Near, Far, and Further). So for consistency, maybe we should forbid it in all cases, not just the ones that involve multiple machines.

There are a couple of compromises that might help. One would be to make a rule that everything arrives as a promise: both presences and promises. Then we could deliver foo(carolPromise) just fine. Bob would have to wait for the promise to resolve (i.e. carolPromise.then(carolPresence => something()) before he could do any identity comparisons. But:

Another idea was to use Dean's Flow mechanism. Basically we make a rule that the messages on a given Flow will block until the referent responds (but messages on unrelated Flows continue unimpeded). Alice would be explicitly opting-in to having her second message block (allowing Carol's vat to delay it indefinitely) by putting it into the same Flow as the one which included a Presence to Carol.

A weak idea, that we rejected almost immediately, was to introduce another class of Presence. You'd have a Promise (on which you can queue messages, but not compare for identity), a Presence (that you get by resolving a Promise, or could receive in an argument), and then a super-Presence (that you can compare for identity, but the only way to get one is to wait a turn). There didn't seem to be a programmer-useful difference between the Promise and the Presence, so we didn't pursue it further.

Restricting programmers to only sending Promises as arguments makes the ERTP ordering behavior harder to manage, but it could be mitigate slightly with MarkM's antiResolve proposal, which we renamed Promise.now() for discussion purposes. This would be like a synchronous form of .then(): if the Promise is currently resolved, it returns the resolution, else it returns undefined. ERTP, on the receiving side, would reject transactions for which the arguments were not "now-able". This still puts the burden on the programmer of the sending side, but relieves the kernel from enforcing the no-Presence checks. However MarkM said the ERTP Amount records, that include an Issuer Presence, made this sound pretty painful.

The Flow thing might work in the longer run, but if we forbid passing Presences today, then adding Flows in the future would let us convert an error case into a working case, which is not a bad transition to make. Whereas allowing them in intra-machine messages but having them cause errors in inter-machine messages would be pretty confusion. "If you can't do something right, don't do it at all".

dtribble commented 5 years ago

Isn't this now obsolete. We have a solution to preserving presence identity now.

erights commented 3 years ago

Assigning to the four discussants mentioned + @michaelfig