Skip to content

Commit

Permalink
Merge pull request #7966 from Agoric/6678-test-upgradeZoeZcf
Browse files Browse the repository at this point in the history
test: a test framework for verifying upgrade of Zoe and ZCF
  • Loading branch information
Chris-Hibbert authored and mhofman committed Aug 7, 2023
2 parents f15a209 + c3fbb55 commit fdb1b5d
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 20 deletions.
1 change: 1 addition & 0 deletions packages/vats/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"build:boot-viz-sim-gov": "node src/authorityViz.js --sim-chain --gov >docs/boot-sim-gov.dot && dot -Tsvg docs/boot-sim-gov.dot >docs/boot-sim-gov.dot.svg",
"build:restart-vats-proposal": "agoric run scripts/restart-vats.js",
"build:add-STARS-proposal": "agoric run scripts/add-STARS.js",
"build:zcf-proposal": "agoric run scripts/replace-zoe.js",
"prepack": "tsc --build jsconfig.build.json",
"postpack": "git clean -f '*.d.ts*'",
"test": "ava",
Expand Down
19 changes: 19 additions & 0 deletions packages/vats/scripts/replace-zoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { makeHelpers } from '@agoric/deploy-script-support';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */
export const defaultProposalBuilder = async ({ publishRef, install }) =>
harden({
sourceSpec: '../src/proposals/zcf-proposal.js',
getManifestCall: [
'getManifestForZoe',
{
zoeRef: publishRef(install('../src/vat-zoe.js')),
zcfRef: publishRef(install('../../zoe/src/contractFacet/vatRoot.js')),
},
],
});

export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);
await writeCoreProposal('replace-zcf', defaultProposalBuilder);
};
45 changes: 45 additions & 0 deletions packages/vats/src/proposals/zcf-proposal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { E } from '@endo/far';

/**
* @param {BootstrapPowers & {
* consume: {
* vatAdminSvc: VatAdminSve;
* vatStore: MapStore<string, CreateVatResults>;
* };
* }} powers
* @param {object} options
* @param {{ zoeRef: VatSourceRef; zcfRef: VatSourceRef }} options.options
*/
export const upgradeZcf = async (
{ consume: { vatAdminSvc, vatStore } },
options,
) => {
const { zoeRef, zcfRef } = options.options;

const zoeBundleCap = await E(vatAdminSvc).getBundleCap(zoeRef.bundleID);
console.log(`ZOE BUNDLE ID: `, zoeRef.bundleID);

const { adminNode, root: zoeRoot } = await E(vatStore).get('zoe');

await E(adminNode).upgrade(zoeBundleCap, {});

const zoeConfigFacet = await E(zoeRoot).getZoeConfigFacet();
await E(zoeConfigFacet).updateZcfBundleId(zcfRef.bundleID);
console.log(`ZCF BUNDLE ID: `, zcfRef.bundleID);
};

export const getManifestForZoe = (_powers, { zoeRef, zcfRef }) => ({
manifest: {
[upgradeZcf.name]: {
consume: {
vatAdminSvc: 'vatAdminSvc',
vatStore: 'vatStore',
},
produce: {},
},
},
options: {
zoeRef,
zcfRef,
},
});
89 changes: 88 additions & 1 deletion packages/vats/test/bootstrapTests/drivers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SECONDS_PER_MINUTE } from '@agoric/inter-protocol/src/proposals/econ-be
import { unmarshalFromVstorage } from '@agoric/internal/src/marshal.js';
import { slotToRemotable } from '@agoric/internal/src/storage-test-utils.js';
import { instanceNameFor } from '@agoric/inter-protocol/src/proposals/price-feed-proposal.js';

import { boardSlottingMarshaller } from '../../tools/board-utils.js';

/**
Expand Down Expand Up @@ -205,8 +206,10 @@ export const makePriceFeedDriver = async (
};
};

/** @typedef {Awaited<ReturnType<import('./supports.js').makeSwingsetTestKit>>} SwingsetTestKit */

/**
* @param {import('./supports.js').SwingsetTestKit} testKit
* @param {SwingsetTestKit} testKit
* @param {import('../../tools/board-utils.js').AgoricNamesRemotes} agoricNamesRemotes
* @param {Awaited<ReturnType<typeof makeWalletFactoryDriver>>} walletFactoryDriver
* @param {string[]} committeeAddresses
Expand Down Expand Up @@ -337,3 +340,87 @@ export const makeGovernanceDriver = async (
},
};
};

export const makeZoeDriver = async testKit => {
const { EV } = testKit.runUtils;
const zoe = await EV.vat('bootstrap').consumeItem('zoe');
const chainStorage = await EV.vat('bootstrap').consumeItem('chainStorage');
const storageNode = await EV(chainStorage).makeChildNode('prober-asid9a');
let creatorFacet;
let adminFacet;
let brand;
const sub = (a, v) => {
return { brand: a.brand, value: a.value - v };
};

return {
async instantiateProbeContract(probeContractBundle) {
const installation = await EV(zoe).install(probeContractBundle);
const startResults = await EV(zoe).startInstance(
installation,
undefined,
undefined,
{ storageNode },
'probe',
);
({ creatorFacet, adminFacet } = startResults);

const issuers = await EV(zoe).getIssuers(startResults.instance);
const brands = await EV(zoe).getBrands(startResults.instance);
brand = brands.Ducats;
return { creatorFacet, issuer: issuers.Ducats, brand };
},
async upgradeProbe(probeContractBundle) {
const fabricateBundleId = bundle => {
return `b1-${bundle.endoZipBase64Sha512}`;
};

await EV(adminFacet).upgradeContract(
fabricateBundleId(probeContractBundle),
);
},

verifyRealloc() {
return EV(creatorFacet).getAllocation();
},
async probeReallocation(value, payment) {
const stagingInv = await EV(creatorFacet).makeProbeStagingInvitation();

const stagingSeat = await EV(zoe).offer(
stagingInv,
{ give: { Ducats: value } },
{ Ducats: payment },
);
const helperPayments = await EV(stagingSeat).getPayouts();

const helperInv = await EV(creatorFacet).makeProbeHelperInvitation();
const helperSeat = await EV(zoe).offer(
helperInv,
{ give: { Ducats: sub(value, 1n) } },
{ Ducats: helperPayments.Ducats },
);
const internalPayments = await EV(helperSeat).getPayouts();

const internalInv = await EV(creatorFacet).makeProbeInternalInvitation();
const internalSeat = await EV(zoe).offer(
internalInv,
{ give: { Ducats: sub(value, 2n) } },
{ Ducats: internalPayments.Ducats },
);
const leftoverPayments = await EV(internalSeat).getPayouts();

return {
stagingResult: await EV(stagingSeat).getOfferResult(),
helperResult: await EV(helperSeat).getOfferResult(),
internalResult: await EV(internalSeat).getOfferResult(),
leftoverPayments,
};
},
async faucet() {
const faucetInv = await EV(creatorFacet).makeFaucetInvitation();
const seat = await EV(zoe).offer(faucetInv);

return EV(seat).getPayout('Ducats');
},
};
};
13 changes: 7 additions & 6 deletions packages/vats/test/bootstrapTests/supports.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
/* global process */
import * as fsAmbient from 'fs';

import { promises as fsAmbientPromises } from 'fs';
import { resolve as importMetaResolve } from 'import-meta-resolve';
import { basename } from 'path';
import { inspect } from 'util';
Expand Down Expand Up @@ -199,7 +200,7 @@ export const getNodeTestVaultsConfig = async (
config.defaultManagerType = 'local';
// speed up build (60s down to 10s in testing)
config.bundleCachePath = bundleDir;
await fsAmbient.promises.mkdir(bundleDir, { recursive: true });
await fsAmbientPromises.mkdir(bundleDir, { recursive: true });

if (config.coreProposals) {
// remove Pegasus because it relies on IBC to Golang that isn't running
Expand All @@ -209,7 +210,7 @@ export const getNodeTestVaultsConfig = async (
}

const testConfigPath = `${bundleDir}/${basename(specifier)}`;
await fsAmbient.promises.writeFile(
await fsAmbientPromises.writeFile(
testConfigPath,
JSON.stringify(config),
'utf-8',
Expand All @@ -222,7 +223,7 @@ export const getNodeTestVaultsConfig = async (
* @param {Pick<typeof import('node:child_process'), 'execFileSync'>} powers.childProcess
* @param {typeof import('node:fs/promises')} powers.fs
*/
const makeProposalExtractor = ({ childProcess, fs }) => {
export const makeProposalExtractor = ({ childProcess, fs }) => {
const getPkgPath = (pkg, fileName = '') =>
new URL(`../../../${pkg}/${fileName}`, import.meta.url).pathname;

Expand Down Expand Up @@ -309,6 +310,7 @@ const makeProposalExtractor = ({ childProcess, fs }) => {
};
return buildAndExtract;
};
harden(makeProposalExtractor);

/**
* Start a SwingSet kernel to be shared across all tests. By default Ava tests
Expand Down Expand Up @@ -434,7 +436,7 @@ export const makeSwingsetTestKit = async (

const buildProposal = makeProposalExtractor({
childProcess: childProcessAmbient,
fs: fsAmbient.promises,
fs: fsAmbientPromises,
});

console.timeEnd('makeSwingsetTestKit');
Expand Down Expand Up @@ -493,4 +495,3 @@ export const makeSwingsetTestKit = async (
timer,
};
};
/** @typedef {Awaited<ReturnType<typeof makeSwingsetTestKit>>} SwingsetTestKit */
39 changes: 26 additions & 13 deletions packages/vats/test/bootstrapTests/test-vats-restart.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
// @ts-check
/** @file Bootstrap test of restarting (almost) all vats */
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';

import processAmbient from 'child_process';
import { promises as fsAmbientPromises } from 'fs';

import { Fail } from '@agoric/assert';
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
import { makeAgoricNamesRemotesFromFakeStorage } from '../../tools/board-utils.js';
import { makeWalletFactoryDriver } from './drivers.js';
import { makeSwingsetTestKit } from './supports.js';
import { makeProposalExtractor, makeSwingsetTestKit } from './supports.js';

/**
* @type {import('ava').TestFn<
* Awaited<ReturnType<typeof makeTestContext>>
* >}
*/
const test = anyTest;
const { Fail } = assert;

/** @file Bootstrap test of restarting (almost) all vats */

// main/production config doesn't have initialPrice, upon which 'open vaults' depends
const PLATFORM_CONFIG = '@agoric/vats/decentral-itest-vaults-config.json';
/** @typedef {Awaited<ReturnType<typeof makeSwingsetTestKit>>} SwingsetTestKit */

// presently all these tests use one collateral manager
const collateralBrandKey = 'ATOM';

const makeTestContext = async t => {
export const makeTestContext = async t => {
console.time('DefaultTestContext');
/** @type {SwingsetTestKit} */
const swingsetTestKit = await makeSwingsetTestKit(t, 'bundles/vaults', {
configSpecifier: PLATFORM_CONFIG,
});
Expand Down Expand Up @@ -54,12 +52,27 @@ const makeTestContext = async t => {

console.timeEnd('DefaultTestContext');

const buildProposal = makeProposalExtractor({
childProcess: processAmbient,
fs: fsAmbientPromises,
});

return {
...swingsetTestKit,
agoricNamesRemotes,
walletFactoryDriver,
buildProposal,
};
};
/**
* @type {import('ava').TestFn<
* Awaited<ReturnType<typeof makeTestContext>>
* >}
*/
const test = anyTest;

// presently all these tests use one collateral manager
const collateralBrandKey = 'ATOM';

test.before(async t => {
t.context = await makeTestContext(t);
Expand Down
Loading

0 comments on commit fdb1b5d

Please sign in to comment.