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

add zoe.installBundleID(bundleID) #4563

Closed
warner opened this issue Feb 16, 2022 · 2 comments · Fixed by #4598
Closed

add zoe.installBundleID(bundleID) #4563

warner opened this issue Feb 16, 2022 · 2 comments · Fixed by #4598
Assignees
Labels
enhancement New feature or request Zoe package: Zoe

Comments

@warner
Copy link
Member

warner commented Feb 16, 2022

What is the Problem Being Solved?

As part of the path towards contract/vat upgrade, I need Zoe to treat contract source code as bundlecap handles, not (large) bundle objects. With #4372 we have the kernel support, but we need to change the way Zoe manages the "installations" table, as well as change the API.

Zoe distinguishes an "installation" (akin to a class) from an "instance". Each installation has a single contract code bundle. Each instance of that installation has its own vat. The vat is launched with the ZCF bundle, and then Zoe tells ZCF to evaluate the contract bundle.

The current API is: E(zoe).install(bundle). I want to change that to E(zoe).install(bundleID), where bundleID is a string that includes a hash of the bundle contents. Zoe uses vatAdminService to look up this ID and retrieve a bundlecap, and then stores just a bundlecap. When Zoe tells ZCF which contract to use, it sends the bundlecap. ZCF is responsible for retrieving the actual source code (using bundle = D(bundlecap).getBundle()) so it can do the importBundle(). By leaving the contract's identity as a bundlecap until the last possible moment, we can reduce the size of messages, and give us some wiggle room to get Endo more involved in the process (eventually importBundle(bundlecap) should be a service provided by the vat environment, and overlap somehow with JS's native dynamic import expression).

For that to work, you must install the bundle first, by talking to the kernel. That means the host application needs to be involved. For the chain, that will require a new cosmos transaction type (#4396), which calls controller.validateAndInstallBundle. The contract deployment process must change: the deploy script needs a way to sign and send this transaction first, learn the bundleID, then send the ID to E(zoe).install instead of the bundle.

I'm currently expecting that this will need a flag day, which is always horrible. If we were ok with E(zoe).install(bundleOrID), we could avoid it, but that will complicate the necessary Zoe changes.

Unit test code must be changed too. In looking at the Zoe unit tests, a common pattern is:

  const fakeVatAdminSvc = makeFakeVatAdmin(setJig).admin;
  const { zoeService: zoe } = makeZoeKit(fakeVatAdminSvc);
  const bundle = await bundleSource(contractRoot);
  const installation = await E(zoe).install(bundle);

that changes to:

  const { admin: fakeVatAdminSvc, vatAdminState } = makeFakeVatAdmin(setJig);
  const { zoeService: zoe } = makeZoeKit(fakeVatAdminSvc);
  const bundle = await bundleSource(contractRoot);
  vatAdminState.installBundle('b1-zcftester', bundle);
  const installation = await E(zoe).install('b1-atomicswap');

(the Bundle ID is normally b1- followed by a SHA512 hash of the bundle's compartment map, but the fake vatAdminService allows any string, so we use a made-up ID for the contracts used in the test)

Description of the Design

Security Considerations

Test Plan

@warner warner added enhancement New feature or request Zoe package: Zoe deployment Chain deployment mechanism (e.g. testnet) Zoe Contract Contracts within Zoe Dapp & UI Support AMM contract-upgrade labels Feb 16, 2022
@warner warner self-assigned this Feb 16, 2022
@warner warner changed the title zoe.install(bundlecap), not bundle, change deploy script zoe.install(bundleID), not bundle, change deploy scripts, tests Feb 16, 2022
@warner
Copy link
Member Author

warner commented Feb 16, 2022

Ok, to avoid the flag day, I'll split this into two pieces. This ticket is about changing E(zoe).install(bundle) into E(zoe).install(bundleOrID). Which means:

  • if install() receives an ID, it uses vatAdminService to turn it into a bundlecap (which doesn't resolve until the matching bundle is installed into the kernel from the outside)
  • the Zoe installations table holds { Bundlecap | Bundle }
  • when Zoe sends the contract to ZCF, it will do E(zcf).evaluateContract(bundleOrBundlecap)
    • ZCF will do bundle = D(bundlecap).getBundle() if necessary
  • the Zoe unit tests will all change to use bundleID, but I'll leave at least one case that uses a bundle directly

Once that lands, we'll start the process of converting dapps to install their bundles first and send an ID. When that process is complete, we'll remove the alternatives and the remaining Zoe API will be E(zoe).install(bundleID).

@warner warner changed the title zoe.install(bundleID), not bundle, change deploy scripts, tests zoe.install(bundleOrID) Feb 16, 2022
@warner warner removed Dapp & UI Support contract-upgrade Zoe Contract Contracts within Zoe deployment Chain deployment mechanism (e.g. testnet) AMM labels Feb 16, 2022
warner added a commit that referenced this issue Feb 16, 2022
Previously, `E(zoe).install()` accepted a source bundle. Now it accepts
either a source bundle, or a "bundle ID". The ID is a hash-based identifier
string that refers to a bundle installed into the kernel via
`controller.validateAndInstallBundle()`, and is retrievable from
vatAdminService. Zoe exchanges the ID for a bundlecap, and retains the
bundlecap for future use (including passing to the new ZCF vat, which
converts it into a source bundle for evaluation at the last possible moment).

The kernel install step can happen either before or after `E(zoe).install`,
because the id-to-bundlecap conversion waits until the kernel install is
complete.

This begins the process of making Zoe work exclusively with (small)
bundlecaps, and not (large) source bundles. The next step is to modify all
unit tests and external callers (including deploy scripts, #4564) to
kernel-install their bundle and use a bundleID for the Zoe install()
invocation. After that is complete, #4565 will remove support for full
bundles, and `E(zoe).install(bundleID)` will be the only choice.

closes #4563
@warner warner changed the title zoe.install(bundleOrID) zoe.installBundleID(bundleID) Feb 17, 2022
@warner
Copy link
Member Author

warner commented Feb 17, 2022

@erights and others have talked me into using a parallel public API, rather than a union type within the existing API. That means choosing a new name. I'll start with E(zoe).installBundleID(bundleID).

(New names are always frustrating, especially for a crew like ours that puts so much energy into getting the names right the first time around, which leaves less room for improvement. install is great, anything else is somewhat worse, but the parallel-API path means that at the end of the day we'll have retired/deleted install and only use something somewhat worse. If we had an extra couple of months, we could then engage in a second round of changes and pivot back to the perfect name but with the new behavior, but that's not realistic. Often it's more satisfying to wait for a drastic architectural change that requires abandoning the old perfect name anyways.)

So here's the public API changes I'll be making:

  • retain E(zoe).install(bundle) for now
  • add E(zoe).installBundleID(bundleID)
  • Installations used to have .getBundle() (and @dckc found external documentation on it: https://agoric.com/documentation/getting-started/intro-zoe.html#inspecting-an-invitation). I'll be removing that; installations will be empty objects.
  • add E(zoe).getBundleIDFromInstallation(installation), which both validates that installation is legit, and returns the bundle ID. It will throw for installations made from a bundle

Internally:

  • E(zcf).evaluateContract() might use bundleOrBundleID, or I might add a parallel method, or I might rename the original and add a parallel method
  • installationStorage.js will hold two weakmaps (really makeWeakStore, to prepare for virtualization/durabilization), mapping installations to bundles or bundlecaps/bundleIDs

warner added a commit that referenced this issue Feb 18, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with vatAdminService, either before or
after `installBundleID` (zoe will wait forever for the bundle to be
installed).

Zoe `Installation` objects no longer have any methods on them (the previous
`getBundle` would only work for bundle-based installations). A new
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it only works for
bundleID-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 18, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with vatAdminService, either before or
after `installBundleID` (zoe will wait forever for the bundle to be
installed).

Zoe `Installation` objects no longer have any methods on them (the previous
`getBundle` would only work for bundle-based installations). A new
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it only works for
bundleID-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 18, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 18, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 18, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 19, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundlecap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
@warner warner changed the title zoe.installBundleID(bundleID) add zoe.installBundleID(bundleID) Feb 19, 2022
warner added a commit that referenced this issue Feb 23, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 23, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 23, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
warner added a commit that referenced this issue Feb 25, 2022
To transition Zoe from full contract bundles to bundlecaps, this adds a new
install API. `E(zoe).install(bundle)` is unchanged, but the new preferred
approach is `E(zoe).installBundleID(bundleID)`. This requires the
corresponding bundle to be installed with the swingset kernel's
vatAdminService, either before or after `installBundleID()` (zoe will wait
forever for the bundle to be installed).

Zoe `Installation` objects retain their `getBundle()` method to accomodate
dapp tests that have not switched to the new approach, but it throws an error
if used on a new bundleID-based installation. A new method named
`E(zoe).getBundleIDFromInstallation(allegedInstallation)` can be used to both
validate the installation and get back the bundleID, but it throws on the old
bundle-based installations.

Internally, the installationStorage.unwrapInstallation now returns either `{
bundle, installation }` or `{ bundleCap, bundleID, installation }`. ZCF's
`evaluateContract()` method accepts either a bundlecap or a full bundle.

closes #4563
@mergify mergify bot closed this as completed in #4598 Feb 25, 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 Zoe package: Zoe
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant