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

promise that fires once a bundle is installed #4521

Closed
warner opened this issue Feb 10, 2022 · 2 comments · Fixed by #4590
Closed

promise that fires once a bundle is installed #4521

warner opened this issue Feb 10, 2022 · 2 comments · Fixed by #4590
Assignees
Labels
enhancement New feature or request SwingSet package: SwingSet
Milestone

Comments

@warner
Copy link
Member

warner commented Feb 10, 2022

What is the Problem Being Solved?

#3272 (comment) pointed out the utility of allowing Zoe to wait for a particular bundleID to be installed. It would allow a governance-gated zoe.install to happen with just a single (small) governance vote, even though the (large) bundle gets installed to the chain after the vote passes.

To accomplish this, we need something that can return a Promise, something with a signature of xxx(bundleID).then(bundlecap => stuff..).

If raw devices could return promises, we could use D(devices.bundle).waitForBundlecap(bundleID). I didn't include full promise support in #4419 , so I'm not sure how much additional work it would require.

Another option is to add a companion vat, like we do for timer and vat-admin. The bundle device would push a message to the bundle vat that says "bundleID XYZ has been installed", and the vat would resolve the promise. The userspace-visible invocation would then be E(vats.bundle).waitForBundlecap(bundleID). If we went that way, it'd be tempting to move the rest of the API over to the vat as well, but I added raw devices to avoid that sort of thing.

In either case, the device code (which can push messages onto the run queue, and knows who wants to be notified) needs to be invoked when the bundle is installed. But the external API is currently controller.validateAndInstallBundle(), on the controller. This highlights the close relationship between the bundle device and the controller: currently the controller writes to the DB, and the device (using kernel-provided endowments) can read from the DB. But adding a notification interface means that these two points want to talk to each other.

Let's see, for the mailbox device, external callers interact with the device's outer/input API surface, rather than going through the controller (neither the kernel nor the controller know anything special about the mailbox device). I'd like bundles to be more "batteries included", though.

Ok, so I think I'm cool with having controller.validateAndInstallBundle() invoking some device code so it can push run-queue things. I still need to think about where the promise should come from.

Description of the Design

Security Considerations

Someone who has access to the bundle device (or whatever provides the promises) could incur a storage burden by asking for a whole bunch of nonsense bundleIDs that will never get installed. We might fix this by having a single "some bundles have been installed" notifier, rather than tracking a separate thing per bundleID.

Test Plan

unit tests

@warner warner added enhancement New feature or request SwingSet package: SwingSet labels Feb 10, 2022
@warner warner self-assigned this Feb 10, 2022
@warner
Copy link
Member Author

warner commented Feb 10, 2022

#4523 would make it easier to add a companion vat. That would change the overall bundles API to:

  • E(vats.bundles).getBundlecap(bundleID) -> Promise<bundlecap>
  • E(vats.bundles).getNamedBundlecap(bundleName) -> Promise<bundlecap>
  • D(bundlecap).getBundleID() -> bundleID
  • D(bundlecap).getBundle() -> bundle

If we gave vats.vatAdmin access to vats.bundles, then E(vats.vatAdmin).createNamedVat(bundleName) could maybe stick around. (Currently it uses a funky endowment that I'd like to remove, and if so I'd remove createNamedVat and require callers to go through getNamedBundlecap first).

The storage burden is still an issue. And maybe we want two separate APIs: one "wait forever until bundle is installed", and a second that rejects the promise if the bundle isn't already installed. And/or a query API.

Internally, E(vats.bundles).initialize({ devices: bundles }) would give devices.bundles a reference to a private object that should be notified when a new bundle is installed. vats.bundles would use the same D(devices.bundles).getBundleCap(bundleID) as before, but the signature would change to -> bundleID | undefined instead of throwing an error when the bundle was not installed. devices.bundles would be given an endowment that allows it to register a callback with the kernel. kernel.installBundle() would invoke this callback (with bundleID) after the bundle was safely installed in the kernelKeeper.

@warner
Copy link
Member Author

warner commented Feb 13, 2022

I think I'm going to address this by having vatAdmin re-export the bundle functionality. This will get the same API described for vats.bundles above, but should allow Zoe to do its job with only access to vatAdminService, which will reduce the changes we need to make in external dapp repositories.

The downside is that anyone who calls createVatAdminService() will need to change their calls and provide devices.bundle in addition to the existing devices.vatAdmin. (The need for this could be removed with something like #4523).

warner added a commit that referenced this issue Feb 13, 2022
This changes `vatAdminService` to expose/re-export the `getBundlecap()` and
`getNamedBundlecap()` functionality from `devices.bundle`. Since vats can
return Promises, the new vatAdmin.getBundlecap lets you wait for the given
bundle to be installed, which should simplify some contract install flows.

As a result, `createVatAdminService` changes: you must connect it to
`devices.bundle`. This requires a change to the bootstrap function all
tests (and production uses of swingset) from:

```js
const vatAdminService = await E(vats.vatAdmin).createVatAdminService(
  devices.vatAdmin);
```

to:

```js
const vatAdminService = await E(vats.vatAdmin).createVatAdminService(
  devices.vatAdmin, devices.bundle);
```

This commit updates all swingset tests to call createVatAdminService the new
way. The next commit will update all other packages in the tree. External
dapps don't usually perform full-swingset tests, so they are unlikely to be
affected.

closes #4521
warner added a commit that referenced this issue Feb 13, 2022
The swingset fix for #4521 requires all callers of `createVatAdminService()`
to provide it with `devices.bundle` in addition to the existing
`devices.vatAdmin`. This occurs in the `bootstrap()` function, in both the
production configuration (`packages/vats/src/bootstrap.js`) and in
swingset-based unit tests in all packages.

This commit updates all agoric-sdk packages to do this.

refs #4521
warner added a commit that referenced this issue Feb 18, 2022
Simplify the user experience by removing `devices.bundle` and merging its
functionality into vat-admin.

* bootstrap() can go back to doing `vatAdminService =
E(vats.vatAdmin).createVatAdminService(devices.vatAdmin)` ,
instead of `createVatAdminService(devices.vatAdmin, devices.bundle)`
* you can get bundlecaps from `E(vatAdminService).getBundlecap` or
`.getNamedBundlecap`, you no longer need `D(devices.bundle)` for those
* `E(vatAdminService).waitForBundlecap(bundleID)` gives you a Promise that
fires when (and if) the bundle has been installed, so you can e.g. begin a
`zoe.install()` before the bundle is installed (closes #4521)

closes #4566
warner added a commit that referenced this issue Feb 18, 2022
Simplify the user experience by removing `devices.bundle` and merging its
functionality into vat-admin.

* bootstrap() can go back to doing `vatAdminService =
E(vats.vatAdmin).createVatAdminService(devices.vatAdmin)` ,
instead of `createVatAdminService(devices.vatAdmin, devices.bundle)`
* you can get bundlecaps from `E(vatAdminService).getBundlecap` or
`.getNamedBundlecap`, you no longer need `D(devices.bundle)` for those
* `E(vatAdminService).waitForBundlecap(bundleID)` gives you a Promise that
fires when (and if) the bundle has been installed, so you can e.g. begin a
`zoe.install()` before the bundle is installed (closes #4521)

closes #4566
turadg pushed a commit that referenced this issue Feb 21, 2022
Simplify the user experience by removing `devices.bundle` and merging its
functionality into vat-admin.

* bootstrap() can go back to doing `vatAdminService =
E(vats.vatAdmin).createVatAdminService(devices.vatAdmin)` ,
instead of `createVatAdminService(devices.vatAdmin, devices.bundle)`
* you can get bundlecaps from `E(vatAdminService).getBundlecap` or
`.getNamedBundlecap`, you no longer need `D(devices.bundle)` for those
* `E(vatAdminService).waitForBundlecap(bundleID)` gives you a Promise that
fires when (and if) the bundle has been installed, so you can e.g. begin a
`zoe.install()` before the bundle is installed (closes #4521)

closes #4566
warner added a commit that referenced this issue Feb 25, 2022
Simplify the user experience by removing `devices.bundle` and merging its
functionality into vat-admin. Use mid-capitalized "bundleCap" in the
API (e.g. `getNamedBundleCap` instead of `getNamedBundlecap`).

* bootstrap() can go back to doing `vatAdminService =
E(vats.vatAdmin).createVatAdminService(devices.vatAdmin)` ,
instead of `createVatAdminService(devices.vatAdmin, devices.bundle)`
* you can get bundlecaps from `E(vatAdminService).getBundleCap` or
`.getNamedBundleCap`, you no longer need `D(devices.bundle)` for those
* `E(vatAdminService).waitForBundleCap(bundleID)` gives you a Promise that
fires when (and if) the bundle has been installed, so you can e.g. begin a
`zoe.install()` before the bundle is installed (closes #4521)

This also introduces a better way to export types from swingset, defines a
VatAdminRootDeviceNode type for use by clients who think they need that, and
exports a few ancillary types to support it.

closes #4566
@Tartuffo Tartuffo added this to the Mainnet 1 milestone Mar 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request SwingSet package: SwingSet
Projects
None yet
2 participants