Skip to content

Commit

Permalink
test: a3p test of zcfBundleCap
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris-Hibbert committed Feb 23, 2024
1 parent 446c1ab commit 219f9c2
Show file tree
Hide file tree
Showing 19 changed files with 2,729 additions and 9 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = {
'./packages/*/tsconfig.json',
'./packages/*/tsconfig.json',
'./packages/wallet/*/tsconfig.json',
'./a3p-integration/proposals/*/tsconfig.json',
'./tsconfig.json',
],
tsconfigRootDir: __dirname,
Expand Down
4 changes: 2 additions & 2 deletions a3p-integration/proposals/a:upgrade-next/post.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ test(`Ensure Network Vat was installed`, async t => {
test(`Smart Wallet vat was upgraded`, async t => {
const incarnation = await getIncarnation('walletFactory');

t.is(incarnation, 2);
t.true(incarnation >= 2);
});

test(`Zoe vat was upgraded`, async t => {
const incarnation = await getIncarnation('zoe');

t.is(incarnation, 1);
t.true(incarnation >= 1);
});

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"consume": {
"contractKits": true,
"governedContractKits": true,
"instancePrivateArgs": true,
"loadCriticalVat": true,
"psmKit": true,
"vatStore": true,
"zoe": "zoe",
"provisioning": "provisioning",
"vaultFactoryKit": true,
"agoricNamesAdmin": "makeCoreProposalBehavior",
"vatAdminSvc": "makeCoreProposalBehavior"
},
"produce": {},
"evaluateBundleCap": "makeCoreProposalBehavior",
"installation": {
"produce": "makeCoreProposalBehavior"
},
"modules": {
"utils": {
"runModuleBehaviors": "makeCoreProposalBehavior"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "probeZcfBundle",
"script": "probeZcfBundle.js",
"permit": "probeZcfBundle-permit.json",
"bundles": [
{
"entrypoint": "@agoric/zoe/src/contractFacet/vatRoot.js",
"bundleID": "b1-2f05ded2716a4413ce52fd3f0cd51b1985d33ebeeb08c61c3a85dd4b0c04a9b65ba99c21e7f48f59cdd69261885c57502602723ffef6238451b4ca92765e9dd1",
"fileName": "/Users/turadg/.agoric/cache/b1-2f05ded2716a4413ce52fd3f0cd51b1985d33ebeeb08c61c3a85dd4b0c04a9b65ba99c21e7f48f59cdd69261885c57502602723ffef6238451b4ca92765e9dd1.json"
},
{
"entrypoint": "@agoric/vats/src/proposals/probeZcfBundle.js",
"bundleID": "b1-0d8591fd292497a2b9ad303ffbd64b7c4ad690ac229fe7772e87cbd88897a8eacc23d1c52214e8b15053aa2275ea44186504a67d2f2e11347edeb10dd42c15a9",
"fileName": "/Users/turadg/.agoric/cache/b1-0d8591fd292497a2b9ad303ffbd64b7c4ad690ac229fe7772e87cbd88897a8eacc23d1c52214e8b15053aa2275ea44186504a67d2f2e11347edeb10dd42c15a9.json"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// This is generated by writeCoreProposal; please edit!
/* eslint-disable */

const manifestBundleRef = {bundleID:"b1-0d8591fd292497a2b9ad303ffbd64b7c4ad690ac229fe7772e87cbd88897a8eacc23d1c52214e8b15053aa2275ea44186504a67d2f2e11347edeb10dd42c15a9"};
const getManifestCall = harden([
"getManifestForProbeZcfBundleCap",
{
zcfRef: {
bundleID: "b1-2f05ded2716a4413ce52fd3f0cd51b1985d33ebeeb08c61c3a85dd4b0c04a9b65ba99c21e7f48f59cdd69261885c57502602723ffef6238451b4ca92765e9dd1",
},
},
]);
const customManifest = {
restartVats: {
consume: {
contractKits: true,
governedContractKits: true,
instancePrivateArgs: true,
loadCriticalVat: true,
provisioning: "provisioning",
psmKit: true,
vatStore: true,
vaultFactoryKit: true,
zoe: "zoe",
},
produce: {},
},
};

// Make a behavior function and "export" it by way of script completion value.
// It is constructed by an anonymous invocation to ensure the absence of a global binding
// for makeCoreProposalBehavior, which may not be necessary but preserves behavior pre-dating
// https://github.com/Agoric/agoric-sdk/pull/8712 .
const behavior = (({
manifestBundleRef,
getManifestCall: [manifestGetterName, ...manifestGetterArgs],
customManifest,
E,
log = console.info,
customRestoreRef,
}) => {
const { entries, fromEntries } = Object;

/**
* Given an object whose properties may be promise-valued, return a promise
* for an analogous object in which each such value has been replaced with its
* fulfillment.
* This is a non-recursive form of endo `deeplyFulfilled`.
*
* @template T
* @param {{[K in keyof T]: (T[K] | Promise<T[K]>)}} obj
* @returns {Promise<T>}
*/
const shallowlyFulfilled = async obj => {
if (!obj) {
return obj;
}
const awaitedEntries = await Promise.all(
entries(obj).map(async ([key, valueP]) => {
const value = await valueP;
return [key, value];
}),
);
return fromEntries(awaitedEntries);
};

const makeRestoreRef = (vatAdminSvc, zoe) => {
/** @type {(ref: import\('./externalTypes.js').ManifestBundleRef) => Promise<Installation<unknown>>} */
const defaultRestoreRef = async bundleRef => {
// extract-proposal.js creates these records, and bundleName is
// the optional name under which the bundle was installed into
// config.bundles
const bundleIdP =
'bundleName' in bundleRef
? E(vatAdminSvc).getBundleIDByName(bundleRef.bundleName)
: bundleRef.bundleID;
const bundleID = await bundleIdP;
const label = bundleID.slice(0, 8);
return E(zoe).installBundleID(bundleID, label);
};
return defaultRestoreRef;
};

/** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers */
const coreProposalBehavior = async powers => {
// NOTE: `powers` is expected to match or be a superset of the above `permits` export,
// which should therefore be kept in sync with this deconstruction code.
// HOWEVER, do note that this function is invoked with at least the *union* of powers
// required by individual moduleBehaviors declared by the manifest getter, which is
// necessary so it can use `runModuleBehaviors` to provide the appropriate subset to
// each one (see ./writeCoreProposal.js).
// Handle `powers` with the requisite care.
const {
consume: { vatAdminSvc, zoe, agoricNamesAdmin },
evaluateBundleCap,
installation: { produce: produceInstallations },
modules: {
utils: { runModuleBehaviors },
},
} = powers;

// Get the on-chain installation containing the manifest and behaviors.
log('evaluateBundleCap', {
manifestBundleRef,
manifestGetterName,
vatAdminSvc,
});
let bcapP;
if ('bundleName' in manifestBundleRef) {
bcapP = E(vatAdminSvc).getNamedBundleCap(manifestBundleRef.bundleName);
} else if ('bundleID' in manifestBundleRef) {
bcapP = E(vatAdminSvc).getBundleCap(manifestBundleRef.bundleID);
} else {
const keys = Reflect.ownKeys(manifestBundleRef).map(key =>
typeof key === 'string' ? JSON.stringify(key) : String(key),
);
const keysStr = `[${keys.join(', ')}]`;
throw Error(
`bundleRef must have own bundleName or bundleID, missing in ${keysStr}`,
);
}
const bundleCap = await bcapP;

const proposalNS = await evaluateBundleCap(bundleCap);

// Get the manifest and its metadata.
log('execute', {
manifestGetterName,
bundleExports: Object.keys(proposalNS),
});
const restoreRef = customRestoreRef || makeRestoreRef(vatAdminSvc, zoe);
const {
manifest,
options: rawOptions,
installations: rawInstallations,
} = await proposalNS[manifestGetterName](
harden({ restoreRef }),
...manifestGetterArgs,
);

// Await promises in the returned options and installations records.
const [options, installations] = await Promise.all(
[rawOptions, rawInstallations].map(shallowlyFulfilled),
);

// Publish the installations for our dependencies.
const installationEntries = entries(installations || {});
if (installationEntries.length > 0) {
const installAdmin = E(agoricNamesAdmin).lookupAdmin('installation');
await Promise.all(
installationEntries.map(([key, value]) => {
produceInstallations[key].resolve(value);
return E(installAdmin).update(key, value);
}),
);
}

// Evaluate the manifest.
return runModuleBehaviors({
// Remember that `powers` may be arbitrarily broad.
allPowers: powers,
behaviors: proposalNS,
manifest: customManifest || manifest,
makeConfig: (name, _permit) => {
log('coreProposal:', name);
return { options };
},
});
};

return coreProposalBehavior;
})({ manifestBundleRef, getManifestCall, customManifest, E });
behavior;
33 changes: 33 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/probeZcfBundleCap.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable @jessie.js/safe-await-separator */

import test from 'ava';

import {
evalBundles,
getIncarnation,
getVatDetails,
} from '@agoric/synthetic-chain';

const SUBMISSION_DIR = 'probe-submission';

test('upgrade Zoe to verify ZcfBundleCap endures', async t => {
t.assert((await getIncarnation('zoe')) === 1, 'zoe incarnation must be one');

// Before the test, the Wallet Factory should be using the legacy ZCF
const detailsBefore = await getVatDetails('walletFactory');
t.true(detailsBefore.incarnation >= 2, 'wf incarnation must be >= 2');

await evalBundles(SUBMISSION_DIR);

const detailsAfter = await getVatDetails('walletFactory');
t.true(detailsAfter.incarnation >= 3, 'wf incarnation after must be >= 3');

// The test restarts the WalletFactory, so it'll use the recently assigned
// ZCF bundle. It then restarts Zoe, so it'll revert to whichever ZCF bundle
// made it to persistent store. We then restart the Wallet Factory and see if
// it's gone back to the ZCF that Zoe initially knew about. If we could get the
// ZCF bundleID here from the probe, we'd explicitly check for that. Instead,
// we have to be content that it did indeed use the newly assigned bundle in
// manual tests.
t.not(detailsAfter.bundleID, detailsBefore.bundleID);
});
1 change: 1 addition & 0 deletions a3p-integration/proposals/c:probeZcfBundleCap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/submission
1 change: 1 addition & 0 deletions a3p-integration/proposals/c:probeZcfBundleCap/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
13 changes: 13 additions & 0 deletions a3p-integration/proposals/c:probeZcfBundleCap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"agoricProposal": {
"type": "/agoric.swingset.CoreEvalProposal",
"source": "submission"
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/synthetic-chain": "^0.0.6-4",
"ava": "^5.3.1"
},
"packageManager": "[email protected]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { execFileSync } from 'node:child_process';

import test from 'ava';

import {
makeAgd,
getIncarnation,
voteLatestProposalAndWait,
} from '@agoric/synthetic-chain';

const SUBMISSION_DIR = 'invite-submission';

const staticConfig = {
deposit: '10000000ubld', // 10 BLD
installer: 'gov1', // as in: agd keys show gov1
proposer: 'validator',
collateralPrice: 6, // conservatively low price. TODO: look up
swingstorePath: '~/.agoric/data/agoric/swingstore.sqlite',
};

/** Provide access to the outside world via context. */
const makeContext = async () => {
const config = {
chainId: 'agoriclocal',
...staticConfig,
};

const agd = makeAgd({ execFileSync }).withOpts({
keyringBackend: 'test',
});

return { agd, config };
};

test('upgrade Zoe to verify ZcfBundleCap endures', async t => {
const { agd, config } = await makeContext();
const { chainId, deposit, proposer } = config;
const from = agd.lookup(proposer);

t.assert((await getIncarnation('zoe')) === 1, 'zoe incarnation must be one');

await agd.tx(
[
'gov',
'submit-proposal',
'swingset-core-eval',
`${SUBMISSION_DIR}/probeZcf-permit.json`,
`${SUBMISSION_DIR}/probeZcf.js`,
'--title=probeZcf',
'--description="set ZcfBundleCap and restart zoe to ensure it endures"',
`--deposit=${deposit}`,
'--gas=auto',
'--gas-adjustment=1.2',
'--keyring-backend=test',
],
{ from, chainId, yes: true },
);
await voteLatestProposalAndWait();

const incarnation = await getIncarnation('foo');
t.is(incarnation, 1);
});
3 changes: 3 additions & 0 deletions a3p-integration/proposals/c:probeZcfBundleCap/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

echo TODO test of restart-vats
Loading

0 comments on commit 219f9c2

Please sign in to comment.