Skip to content
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

9449 membrane types #9685

Merged
merged 20 commits into from
Jul 11, 2024
Merged

9449 membrane types #9685

merged 20 commits into from
Jul 11, 2024

Conversation

turadg
Copy link
Member

@turadg turadg commented Jul 10, 2024

closes: #9449

Description

Address all the FIXMEs about types and vows in Orchestration. To do so I moved some stuff down to async-flow and zoe packages. I also made some small fixes in smart-wallet.

I believe this ticks the last box of #9449.

Security Considerations

none

Scaling Considerations

none

Documentation Considerations

none

Testing Considerations

This adds type tests and I used type-coverage to verify no regressions.

Upgrade Considerations

orchestration and async-flow not yet deployed.

The changes in zoe and smart-wallet are just typedefs so safe to deploy anytime.

Copy link

cloudflare-workers-and-pages bot commented Jul 10, 2024

Deploying agoric-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6b41829
Status: ✅  Deploy successful!
Preview URL: https://c7aaa4c8.agoric-sdk.pages.dev
Branch Preview URL: https://9449-membrane-vows.agoric-sdk.pages.dev

View logs

@turadg turadg changed the base branch from master to pc/9673-sync-continuing-offer July 11, 2024 00:56
@turadg turadg marked this pull request as ready for review July 11, 2024 01:00
Base automatically changed from pc/9673-sync-continuing-offer to master July 11, 2024 01:18
Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only reviewed asyncFlow changes so far. More soon...

@@ -154,14 +154,9 @@ export const makeReplayMembrane = ({
const passStyle = passStyleOf(h);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love that we can now stop tolerating host promises and instead reject them with errors!

However, this leaves the doc-comment above and the function name tolerate* stale. Please revise to be consistent either with consistent rejection, or at least as the function which decides whether to tolerate or to reject. I don't have a name to suggest.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok to fully remove tolerateHostPromiseToVow? I was trying to be surgical because I didn't know if you needed it to be there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removal is good

Comment on lines +40 to +45
export type GuestOf<F extends HostAsyncFuncWrapper> = F extends (
...args: infer A
) => Vow<infer R>
? (...args: A) => Promise<R>
: F;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow!

Thanks for translating all those type declarations into better .d.ts types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsc did the work! yarn prepack

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL! Good to know.

packages/async-flow/src/types.d.ts Outdated Show resolved Hide resolved
packages/async-flow/src/types.d.ts Outdated Show resolved Hide resolved
packages/async-flow/src/types.d.ts Outdated Show resolved Hide resolved
packages/async-flow/src/types.d.ts Outdated Show resolved Hide resolved
Copy link
Member

@0xpatrickdev 0xpatrickdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work 👏

async-flow/src/types.d.ts#L118-L252 is foreign to me but seems like its mostly porting things from js to ts

// XXX makeAccount returns a Promise for an exo but reserves being able to return a vow
// so we use heapVowE to shorten the promise path
// eslint-disable-next-line no-restricted-syntax -- will run in one turn
allVows([lcaP, heapVowE(lcaP).getAddress()]),
Copy link
Member

@0xpatrickdev 0xpatrickdev Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised we need to reach for heapVowE here. Original E + pipelining should work, since lcaP is a Promise and not a Vow. There's a test demonstrating the behavior mentioned in: #9591 (comment)

Maybe we need to improve the allVows type? ah E doesn't understand PromiseVow. Still, seems like it's maybe a type issue and we shouldn't need heapVowE

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to explain this in the comment. The value actually being returned is not a vow, but the return signature says it could be. @michaelfig wanted to reserve that option for the future. So this code should comply. (i.e. not to accelerate Hyrum's Law).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, thanks

/**
* Public topics are a map to different vstorage paths and subscribers that
* can be shared with on or offchain clients.
* When returned as part of a continuing invitation, it will appear
* in the {@link CurrentWalletRecord} in vstorage.
*/
getPublicTopics: () => Promise<TopicsRecord>;
getPublicTopics: () => Promise<Record<string, ResolvedPublicTopic<unknown>>>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Consider exporting a ResolvedTopicsRecord from zoe/contractSupport/topics.js

packages/async-flow/src/types.d.ts Outdated Show resolved Hide resolved
| 'Done';

/**
* `T` defaults to `any`, not `Passable`, because unwrapped guests include
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realize this is an existing comment, but consider an @internal directive

Copy link
Member Author

@turadg turadg Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I added it there was a jsdoc lint error the tag should be empty

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does @internal mean/do?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#9690 fixes the lint error. I'm still not sure whether this should be @internal.

type HostInterface<T> = {
[K in keyof T]: HostOf<T[K]>;
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on these. Do we also need a GuestInterface?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we define an interface it should be in the view of the guest.

return watch(h);
const e = Error('where promise detected');
console.error('vow expected, not promise', h, e);
throw e;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

@@ -21,6 +21,16 @@ export const PublicTopicShape = M.splitRecord(
* }} PublicTopic
*/

/**
* A {PublicTopic} in which the `storagePath` is a string.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a why to one of the Resolved* types

Suggested change
* A {PublicTopic} in which the `storagePath` is a string.
* A {PublicTopic} in which the `storagePath` is a string.
* Useful when working with Vows and async-flow.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea. we can use more "what this is for"

packages/smart-wallet/src/types.d.ts Show resolved Hide resolved
@turadg turadg added the force:integration Force integration tests to run on PR label Jul 11, 2024
@@ -83,7 +84,7 @@ export const IcaAccountHolderI = M.interface('IcaAccountHolder', {
undelegate: M.call(M.arrayOf(DelegationShape)).returns(VowShape),
});

/** @type {{ [name: string]: [description: string, valueShape: Pattern] }} */
/** @type {{ [name: string]: [description: string, valueShape: Matcher] }} */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change the type from Pattern to Matcher? Do you intend to exclude other patterns that are not themselves matchers, even if they contain matchers?

Likewise for other similar changes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change the type from Pattern to Matcher?

because makeRecordKit accepts only a Matcher for the valueShape:

* @param {TypedMatcher<T>} [valueShape]
* @returns {RecorderKit<T>}

Do you intend to exclude other patterns that are not themselves matchers, even if they contain matchers?

For now.

/**
* Stop-gap until https://github.com/Agoric/agoric-sdk/issues/6160
* explictly specify the type that the Pattern will verify through a match.
*
* This is a Pattern but since that's `any`, including in the typedef turns the
* whole thing to `any`.
*
* @template T
* @typedef {import('@endo/patterns').Matcher & { validatedType?: T }} TypedMatcher
*/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern is no longer any (thanks to you IIRC)

@typedef {Exclude<Passable, Error | Promise>} Pattern

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. From endojs/endo#2238

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, we can fix that now: 6b41829

@@ -59,7 +60,7 @@ const HolderI = M.interface('holder', {
executeTx: M.call(M.arrayOf(M.record())).returns(Vow$(M.record())),
});

/** @type {{ [name: string]: [description: string, valueShape: Pattern] }} */
/** @type {{ [name: string]: [description: string, valueShape: Matcher] }} */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pattern vs matcher

@turadg turadg requested a review from erights July 11, 2024 18:38
@turadg turadg added the automerge:rebase Automatically rebase updates, then merge label Jul 11, 2024
Copy link
Member Author

turadg commented Jul 11, 2024

@Mergifyio requeue main

Copy link
Contributor

mergify bot commented Jul 11, 2024

requeue main

✅ The queue state of this pull request has been cleaned. It can be re-embarked automatically

Copy link
Member Author

turadg commented Jul 11, 2024

@Mergifyio queue main

Copy link
Contributor

mergify bot commented Jul 11, 2024

queue main

🛑 The pull request has been removed from the queue main

The queue conditions cannot be satisfied due to failing checks.

You can take a look at Queue: Embarked in merge queue check runs for more details.

In case of a failure due to a flaky test, you should first retrigger the CI.
Then, re-embark the pull request into the merge queue by posting the comment
@mergifyio refresh on the pull request.

@turadg turadg removed the force:integration Force integration tests to run on PR label Jul 11, 2024
@turadg
Copy link
Member Author

turadg commented Jul 11, 2024

@Mergifyio requeue main

Copy link
Contributor

mergify bot commented Jul 11, 2024

requeue main

☑️ This pull request is already queued

@turadg
Copy link
Member Author

turadg commented Jul 11, 2024

This is failing only on getting-started link-cli because of a git status --porcelain porcelain check finding endo-sha.txt left over from an earlier run of CI. I'm going to bypass integration to land this.

@turadg turadg added the bypass:integration Prevent integration tests from running on PR label Jul 11, 2024
@mergify mergify bot merged commit 3915e4c into master Jul 11, 2024
84 of 86 checks passed
@mergify mergify bot deleted the 9449-membrane-vows branch July 11, 2024 23:14
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one behavioral change in this PR, and it is problematic

const { remoteChainInfo, connectionInfo } = this.state;
const stakingDenom = remoteChainInfo.stakingTokens?.[0]?.denom;
if (!stakingDenom) {
return asVow(Fail`chain info lacks staking denom`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not do what you expect, and throw an error instead of returning a rejected vow

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have been this?

Suggested change
return asVow(Fail`chain info lacks staking denom`);
return asVow(() => Fail`chain info lacks staking denom`);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work but I'm not sure why this PR removed the surrounding asVow in the first place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I the assume bug is that Fail throws immediately here instead of propoagating as a vow?

What's a good way to catch this in a test? When reviewing this, I made similar edits to cosmos-orch-acct and didn't see any of these tests break:

await t.throwsAsync(E(account).getBalances(), {
message: 'not yet implemented',
});
await t.throwsAsync(E(account).send(mockChainAddress, mockAmountArg), {
message: 'not yet implemented',
});
// XXX consider, positioning amount + address args the same for .send and .transfer
await t.throwsAsync(E(account).transfer(mockAmountArg, mockChainAddress), {
message: 'not yet implemented',
});
await t.throwsAsync(E(account).transferSteps(mockAmountArg, null as any), {
message: 'not yet implemented',
});
await t.throwsAsync(E(account).withdrawRewards(), {
message: 'Not Implemented. Try using withdrawReward.',
});

The above does not go through the membrane, though. Would the membrane catch this? On my short list to test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't see any of these tests break

yeah, we need breaking tests. Addressing in #9696

@turadg turadg mentioned this pull request Jul 12, 2024
mergify bot added a commit that referenced this pull request Jul 14, 2024
follow up on #9449 

## Description
#9685 unwrapped an `asVow()` to get the promise failure to propagate. This reverts that now that #9704 removed the need for it.

### Security Considerations
none

### Scaling Considerations
none

### Documentation Considerations
none

### Testing Considerations
CI

### Upgrade Considerations
not yet deployed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge bypass:integration Prevent integration tests from running on PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

orchestration facade returns promises backed by vows
5 participants