-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(asyncFlow): E
support
#9322
base: markm-asyncFlow-no-E
Are you sure you want to change the base?
Conversation
Deploying agoric-sdk with Cloudflare Pages
|
e8e56d9
to
7575a6c
Compare
596304e
to
4cb7ed6
Compare
f40cf7e
to
a0198f0
Compare
a0198f0
to
055c780
Compare
174eb1c
to
97b8266
Compare
e9420ab
to
98c12fb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass, but I'm confused about the handling of the result vow. I understand we have the logic about interpreter nesting, but I think it would be simpler to include the result vow in the checkSend
log entry, and have a synthetic doReturn
with no result (and ignore the outcome completely on replay because it either succeeds or panics, a throw
outcome should not happen for a checkSend
)
const hostPromise = optVerb | ||
? E(hostTarget)[optVerb](...hostArgs) | ||
: E(hostTarget)(...hostArgs); | ||
resolver.resolve(hostPromise); // TODO does this always work? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah thinking about this, if hostTarget
is a local object for which call returns a promise, we will fail during an upgrade. Unlike the checkCall
case, we're not in a position to do any enforcment and fail unconditionally, unless we can somehow sniff the type of the hostTarget
(if it has an eventual handler or not), and bypass the E
call if it doesn't. If the hostTarget
object does not return a promise, then the hostPromise will be fulfilled in the same crank, so it's safe.
: E(hostTarget)(...hostArgs); | ||
resolver.resolve(hostPromise); // TODO does this always work? | ||
} catch (hostProblem) { | ||
throw Fail`internal: eventual send synchrously failed ${hostProblem}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I didn't understand this right originally, let's add a comment: Since a well behaved eventual-send should not synchronously fail (it doesn't synchronously interact with the target), a synchronous throw does not represent a failure we should commit to, but instead is a panic.
// TODO FIX BUG this is not quite right. When guestResultP is returned | ||
// as the resolution of guestResultP, it create a visious cycle error. | ||
const hostResultKit = makeVowKit(); | ||
bijection.init(guestReturnedP, hostResultKit.vow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify how this cycle could actually happen?
const hostResultKit = makeVowKit(); | ||
bijection.init(guestReturnedP, hostResultKit.vow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we're replaying we need to use the vow
that was previously created for the send, no?
I also don't see how we're rewiring the guestReturnedP
to the watched vow on replay.
} catch (problem) { | ||
throw panic(problem); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't the caller of performSend
already panic on exceptions?
const promise = new HandledPromise((res, rej, _resPres) => { | ||
resolve = res; | ||
reject = rej; | ||
}, guestHandler); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, makePromiseKit
has some logic to sever references from the resolvers to the promise once resolved, but I think in this case all resolver users are well behaved and drop resolvers after usage, so we're good.
case 'throw': { | ||
throw outcome.problem; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this can ever happen, can it?
? E(hostTarget)[optVerb](...hostArgs) | ||
: E(hostTarget)(...hostArgs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of host vows, we should be using the V
helper instead of E
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After talking with @michaelfig we clarified that V
is heap only, and does not queue sends durably. We need to structure the membrane handling of sends to vows such that they are only sent after the vow has settled. We can rely on the fact that the membrane has replayed (no need to durably store the pending sends, instead use the guest promise).
9fc7e06
to
81c8c76
Compare
81c8c76
to
660cacc
Compare
660cacc
to
e495bc2
Compare
Staged on #9443
closes: #9299
refs: #9097 #9336
Description
To support guest uses of
E
to do eventual sends,Not yet implemented
applyMethod
to translate an eventual send on the guest wrapper into a corresponding eventual send to the host target, logging it as acheckSend
, by analogy with acheckCall
. Like acheckCall
that immediately returns a promise, it will be followed immediately by a correspondingdoReturn
of the corresponding vow. UnlikecheckCall
/doReturn
, there is no possible callback interleaving between acheckSend
and itsdoReturn
. Later, when the target vow has settled, that will cause a correspondingdoFulfill
ordoReject
. UnlikecheckCall
, the target of acheckSend
can be either a remotable or a promise.Security Considerations
just more surface area and more tricky things that might be wrong.
Scaling Considerations
should not be significantly different than the existing support for
checkCall
.Documentation Considerations
one less restriction that needs to be documented. Once this PR works, it should "just work" in the sense of merely removing a surprise.
Testing Considerations
Upgrade Considerations
Prior to this PR, a guest use of
E(guestWrapper).foo()
would, in a later turn, do a guest-sideguestWrapper.foo()
causing acheckCall
/doReturn
to get logged. This is not incorrect on its own terms. But we need not to commit to any such durable logs prior to this PR. With this PR, that same expression will immediately causecheckSend
to get logged with an immediatedoReturn
of a promise that later settles with adoFulfill
ordoReject
. With this change in the log, we expect we have durable logs we're willing to commit to.Note that we have that even before we implement the
applyMethod
handler. In its absence, this PR should cause any such guest use ofE
to be an error. First, we must test that. Second, we need to decide how the asyncFlow mechanism should treat such errors.