From f4df63ae4a7afb70118dfe9224620bea300ed679 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 20 Jun 2023 10:27:30 -0700 Subject: [PATCH 01/34] chore(types): correct ManifestBundleRef --- .../test/upgrade-contract/propose-buggy-contract.js | 1 + .../upgrade-contract/propose-upgrade-contract.js | 1 + .../src/coreProposalBehavior.js | 12 +++++++----- packages/deploy-script-support/src/externalTypes.js | 9 ++++----- .../deploy-script-support/src/extract-proposal.js | 11 ++++++++++- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/agoric-cli/test/upgrade-contract/propose-buggy-contract.js b/packages/agoric-cli/test/upgrade-contract/propose-buggy-contract.js index 1e5829e6511..1420d080f7e 100644 --- a/packages/agoric-cli/test/upgrade-contract/propose-buggy-contract.js +++ b/packages/agoric-cli/test/upgrade-contract/propose-buggy-contract.js @@ -3,6 +3,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies 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: './init-proposal.js', diff --git a/packages/agoric-cli/test/upgrade-contract/propose-upgrade-contract.js b/packages/agoric-cli/test/upgrade-contract/propose-upgrade-contract.js index b149f7ef75b..60ad54bb46c 100644 --- a/packages/agoric-cli/test/upgrade-contract/propose-upgrade-contract.js +++ b/packages/agoric-cli/test/upgrade-contract/propose-upgrade-contract.js @@ -3,6 +3,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies 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: './upgrade-proposal.js', diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 477e8dddd7a..080a14bfbf2 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -24,12 +24,12 @@ export const permits = { * definitions. * * @param {object} opts - * @param {{ bundleName: string } | { bundleID: string }} opts.manifestBundleRef + * @param {import('./externalTypes.js').ManifestBundleRef} opts.manifestBundleRef * @param {[string, ...unknown[]]} opts.getManifestCall * @param {Record>} [opts.overrideManifest] * @param {typeof import('@endo/far').E} opts.E * @param {(...args: unknown[]) => void} [opts.log] - * @param {(ref: unknown) => Promise} [opts.restoreRef] + * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} [opts.restoreRef] * @returns {(vatPowers: unknown) => Promise} */ export const makeCoreProposalBehavior = ({ @@ -70,13 +70,15 @@ export const makeCoreProposalBehavior = ({ } = allPowers; const [exportedGetManifest, ...manifestArgs] = getManifestCall; + /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} */ const defaultRestoreRef = async ref => { // extract-proposal.js creates these records, and bundleName is // the name under which the bundle was installed into // config.bundles - const p = ref.bundleName - ? E(vatAdminSvc).getBundleIDByName(ref.bundleName) - : ref.bundleID; + const p = + 'bundleName' in ref + ? E(vatAdminSvc).getBundleIDByName(ref.bundleName) + : ref.bundleID; const bundleID = await p; const label = bundleID.slice(0, 8); return E(zoe).installBundleID(bundleID, label); diff --git a/packages/deploy-script-support/src/externalTypes.js b/packages/deploy-script-support/src/externalTypes.js index 35535dcf66a..442ea8bcce3 100644 --- a/packages/deploy-script-support/src/externalTypes.js +++ b/packages/deploy-script-support/src/externalTypes.js @@ -16,14 +16,13 @@ export {}; */ /** - * @typedef BundleHandle - * @property {string} [bundleName] + * @typedef {{ bundleName: string } | { bundleID: string} } ManifestBundleRef */ /** * @callback PublishBundleRef - * @param {ERef} bundle - * @returns {Promise} + * @param {ERef} bundle + * @returns {Promise} */ /** @@ -31,7 +30,7 @@ export {}; * @param {string} srcSpec * @param {string} bundlePath * @param {any} [opts] - * @returns {BundleHandle} + * @returns {ManifestBundleRef} */ /** diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index ea539b145b0..23550ef0133 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -135,11 +135,20 @@ export const extractCoreProposalBundles = async ( /** @type {import('./externalTypes.js').PublishBundleRef} */ const publishRef = async handleP => { const handle = await handleP; + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error -- https://github.com/Agoric/agoric-sdk/issues/4620 */ + // @ts-ignore xxx types bundleHandleToAbsolutePaths.has(handle) || Fail`${handle} not in installed bundles`; return handle; }; - const proposal = await ns[entrypoint]({ publishRef, install }, ...args); + const proposal = await ns[entrypoint]( + { + publishRef, + // @ts-expect-error not statically verified to return a full obj + install, + }, + ...args, + ); // Add the proposal bundle handles in sorted order. const bundleSpecEntries = [...thisProposalBundleHandles.keys()] From ad28858fe28b897ab61205ad7323af185ed67132 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 17 Jul 2023 15:01:50 -0400 Subject: [PATCH 02/34] refactor(agoric-cli): Improve git clone efficiency --- packages/agoric-cli/src/init.js | 3 ++- packages/cosmic-swingset/test/scenario2.js | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/agoric-cli/src/init.js b/packages/agoric-cli/src/init.js index a81283f8487..b901128b383 100644 --- a/packages/agoric-cli/src/init.js +++ b/packages/agoric-cli/src/init.js @@ -40,9 +40,10 @@ export default async function initMain(_progname, rawArgs, priv, opts) { dappBranch = ['-b', opts.dappBranch]; } + const shallow = ['--depth', '1', '--shallow-submodules']; const exitStatus = await pspawn( 'git', - ['clone', '--origin=upstream', dappURL, DIR, ...dappBranch], + ['clone', '--origin=upstream', ...shallow, dappURL, DIR, ...dappBranch], { stdio: 'inherit', }, diff --git a/packages/cosmic-swingset/test/scenario2.js b/packages/cosmic-swingset/test/scenario2.js index bc5656da90e..ce316044eda 100644 --- a/packages/cosmic-swingset/test/scenario2.js +++ b/packages/cosmic-swingset/test/scenario2.js @@ -6,9 +6,8 @@ const onlyStderr = ['ignore', 'ignore', 'inherit']; const noOutput = ['ignore', 'ignore', 'ignore']; // const noisyDebug = ['ignore', 'inherit', 'inherit']; -export const pspawn = - (bin, { spawn, cwd }) => - (args = [], opts = {}) => { +export const pspawn = (bin, { spawn, cwd }) => { + return (args = [], opts = {}) => { /** @type {import('child_process').ChildProcess} */ let child; const exit = new Promise((resolve, reject) => { @@ -16,7 +15,9 @@ export const pspawn = child = spawn(bin, args, { cwd, ...opts }); child.addListener('exit', code => { if (code !== 0) { - reject(Error(`exit ${code} from: ${bin} ${args}`)); + // TODO: Include ~3 lines from child.stderr or child.stdout if present. + // see https://nodejs.org/api/child_process.html#child_processspawncommand-args-options + reject(Error(`exit ${code} from command: ${bin} ${args}`)); return; } resolve(0); @@ -35,6 +36,7 @@ export const pspawn = // @ts-expect-error child is set in the Promise constructor return { kill, child, exit }; }; +}; /** * Shared state for tests using scenario2 chain in ../ From 5de1e93747146a4c9cd4e3d3d77a0f43033c72fb Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Fri, 28 Jul 2023 22:37:26 -0600 Subject: [PATCH 03/34] feat(deploy-script-support): generalize `extractCoreProposalBundles` --- .../src/extract-proposal.js | 104 ++++++++++-------- 1 file changed, 60 insertions(+), 44 deletions(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 408c223452f..6d2952a8155 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -40,6 +40,19 @@ const findModule = (initDir, srcSpec) => ? pathResolve(initDir, srcSpec) : req.resolve(srcSpec); +/** + * @param {{ bundleID?: string, bundleName?: string }} handle - mutated then hardened + * @param {string} sourceSpec - the specifier of a module to load + * @param {number} sequence - the sequence number of the proposal + * @param {string} piece - the piece of the proposal + * @returns {Promise<[string, any]>} + */ +const namedHandleToBundleSpec = async (handle, sourceSpec, sequence, piece) => { + handle.bundleName = `coreProposal${sequence}_${piece}`; + harden(handle); + return harden([handle.bundleName, { sourceSpec }]); +}; + /** * Format core proposals to be run at bootstrap: * SwingSet `bundles` configuration @@ -54,26 +67,28 @@ const findModule = (initDir, srcSpec) => * @param {ConfigProposal[]} coreProposals - governance * proposals to run at chain bootstrap for scenarios such as sim-chain. * @param {FilePath} [dirname] - * @param {typeof makeEnactCoreProposalsFromBundleRef} [makeEnactCoreProposals] - * @param {(i: number) => number} [getSequenceForProposal] + * @param {object} [opts] + * @param {typeof makeEnactCoreProposalsFromBundleRef} [opts.makeEnactCoreProposals] + * @param {(i: number) => number} [opts.getSequenceForProposal] + * @param {typeof namedHandleToBundleSpec} [opts.handleToBundleSpec] */ export const extractCoreProposalBundles = async ( coreProposals, dirname = '.', - makeEnactCoreProposals = makeEnactCoreProposalsFromBundleRef, - getSequenceForProposal, + opts, ) => { - if (!getSequenceForProposal) { - // Deterministic proposal numbers. - getSequenceForProposal = i => i; - } + const { + makeEnactCoreProposals = makeEnactCoreProposalsFromBundleRef, + getSequenceForProposal = i => i, + handleToBundleSpec = namedHandleToBundleSpec, + } = opts || {}; dirname = pathResolve(dirname); dirname = await fs.promises .stat(dirname) .then(stbuf => (stbuf.isDirectory() ? dirname : path.dirname(dirname))); - /** @type {Map<{ bundleName?: string }, { source: string, bundle?: string }>} */ + /** @type {Map<{ bundleID?: string, bundleName?: string }, { source: string, bundle?: string }>} */ const bundleHandleToAbsolutePaths = new Map(); const bundleToSource = new Map(); @@ -151,29 +166,30 @@ export const extractCoreProposalBundles = async ( ); // Add the proposal bundle handles in sorted order. - const bundleSpecEntries = [...thisProposalBundleHandles.keys()] - .map(handle => [handle, bundleHandleToAbsolutePaths.get(handle)]) - .sort(([_hnda, { source: a }], [_hndb, { source: b }]) => { - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - return 0; - }) - .map(([handle, absolutePaths], j) => { - // Transform the bundle handle identity into a bundleName reference. - handle.bundleName = `coreProposal${thisProposalSequence}_${j}`; - harden(handle); - - /** @type {[string, { sourceSpec: string }]} */ - const specEntry = [ - handle.bundleName, - { sourceSpec: absolutePaths.source }, - ]; - return specEntry; - }); + const bundleSpecEntries = await Promise.all( + [...thisProposalBundleHandles.keys()] + .map(handle => [handle, bundleHandleToAbsolutePaths.get(handle)]) + .sort(([_hnda, { source: a }], [_hndb, { source: b }]) => { + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + }) + .map(async ([handle, absolutePaths], j) => { + // Transform the bundle handle identity into a bundleName reference. + const specEntry = await handleToBundleSpec( + handle, + absolutePaths.source, + thisProposalSequence, + String(j), + ); + harden(handle); + return specEntry; + }), + ); // Now that we've assigned all the bundleNames and hardened the // handles, we can extract the behavior bundle. @@ -192,21 +208,21 @@ export const extractCoreProposalBundles = async ( exportedGetManifest ](harden({ restoreRef: () => null }), ...manifestArgs); - const behaviorBundleHandle = harden({ - bundleName: `coreProposal${thisProposalSequence}_behaviors`, - }); - const behaviorAbsolutePaths = harden({ - source: behaviorSource, - }); - bundleHandleToAbsolutePaths.set( + const behaviorBundleHandle = {}; + const specEntry = await handleToBundleSpec( behaviorBundleHandle, - behaviorAbsolutePaths, + behaviorSource, + thisProposalSequence, + 'behaviors', ); + bundleSpecEntries.unshift(specEntry); - bundleSpecEntries.unshift([ - behaviorBundleHandle.bundleName, - { sourceSpec: behaviorAbsolutePaths.source }, - ]); + bundleHandleToAbsolutePaths.set( + behaviorBundleHandle, + harden({ + source: behaviorSource, + }), + ); return harden({ ref: behaviorBundleHandle, From e0cb38323ba4d29cc8125a1262e5a8fe90de976d Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Fri, 4 Aug 2023 14:00:39 -0700 Subject: [PATCH 04/34] test: drop obsolete tests --- .../test/test-gov-collateral.js | 605 ------------------ 1 file changed, 605 deletions(-) delete mode 100644 packages/inter-protocol/test/test-gov-collateral.js diff --git a/packages/inter-protocol/test/test-gov-collateral.js b/packages/inter-protocol/test/test-gov-collateral.js deleted file mode 100644 index d476115fbba..00000000000 --- a/packages/inter-protocol/test/test-gov-collateral.js +++ /dev/null @@ -1,605 +0,0 @@ -/** @file currently disabled https://github.com/Agoric/agoric-sdk/issues/7175 */ -import { test as anyTest } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; -import process from 'process'; -import url from 'url'; -import path from 'path'; -import { E, Far } from '@endo/far'; -import { makePromiseKit } from '@endo/promise-kit'; -import bundleSource from '@endo/bundle-source'; -import { - addBankAssets, - makeAddressNameHubs, - makeOracleBrands, - makeBoard, - startPriceAuthorityRegistry, -} from '@agoric/vats/src/core/basic-behaviors.js'; -import centralSupplyBundle from '@agoric/vats/bundles/bundle-centralSupply.js'; -import { - bridgeCoreEval, - setupClientManager, -} from '@agoric/vats/src/core/chain-behaviors.js'; -import { extractCoreProposalBundles } from '@agoric/deploy-script-support/src/extract-proposal.js'; -import { makeCoreProposalBehavior } from '@agoric/deploy-script-support/src/coreProposalBehavior.js'; -import { makeNameHubKit } from '@agoric/vats/src/nameHub.js'; -import { AmountMath, makeIssuerKit } from '@agoric/ertp'; -import { Stable } from '@agoric/vats/src/tokens.js'; -import { provideBundleCache } from '@agoric/swingset-vat/tools/bundleTool.js'; -import { TimeMath } from '@agoric/time'; - -import { makeScalarBigMapStore } from '@agoric/vat-data'; -import { - setupBootstrap, - setUpZoeForTest, - mintRunPayment, - DENOM_UNIT as UNIT, -} from './supports.js'; -import { INVITATION_MAKERS_DESC } from '../src/econCommitteeCharter.js'; - -/** @template T @typedef {import('@endo/promise-kit').PromiseKit} PromiseKit */ - -const { Fail } = assert; -const dirname = url.fileURLToPath(new URL('.', import.meta.url)); - -/** @type {import('ava').TestFn>>} */ -const test = anyTest; - -const contractRoots = { - mintHolder: '../vats/src/mintHolder.js', - econCommitteeCharter: './src/econCommitteeCharter.js', -}; - -const coreProposals = { - addCollateral: '../scripts/add-collateral-core.js', - startRunPreview: '../scripts/init-core.js', - inviteCommittee: '../scripts/invite-committee-core.js', -}; - -const voterAddresses = { - Rowland: `agoric1qed57ae8k5cqr30u5mmd46jdxfr0juyggxv6ad`, - Bill: `agoric1xgw4cknedau6xhrlyn6c8e40d02mejee8gwnef`, - Dan: `agoric1yumvyl7f5nkalss7w59gs6n3jtqv5gmarudx55`, -}; - -// Nondeterministic, but the test shouldn't rely on this value. -let lastProposalSequence = 0; - -const makeTestContext = async () => { - const bundleCache = await provideBundleCache('bundles/', {}, s => import(s)); - const { zoe, feeMintAccessP, vatAdminSvc, vatAdminState } = - await setUpZoeForTest(); - assert(vatAdminState); - - const stableIssuer = await E(zoe).getFeeIssuer(); - const stableBrand = await E(stableIssuer).getBrand(); - - const install = (src, dest) => - bundleCache.load(src, dest).then(b => E(zoe).install(b)); - const installation = { - mintHolder: install(contractRoots.mintHolder, 'mintHolder'), - /** @type {Promise>} */ - centralSupply: E(zoe).install(centralSupplyBundle), - econCommitteeCharter: install( - contractRoots.econCommitteeCharter, - 'econCommitteeCharter', - ), - }; - - const bundleNameToAbsolutePaths = new Map(); - const bundlePathToInstallP = new Map(); - const restoreBundleName = bundleName => { - const absolutePaths = bundleNameToAbsolutePaths.get(bundleName); - absolutePaths || Fail`bundleName ${bundleName} not found`; - const { source, bundle } = absolutePaths; - const bundlePath = bundle || source.replace(/(\\|\/|:)/g, '_'); - if (!bundlePathToInstallP.has(bundlePath)) { - const match = path.basename(bundlePath).match(/^bundle-(.*)\.js$/); - const actualBundle = match ? match[1] : bundlePath; - bundlePathToInstallP.set(bundlePath, install(source, actualBundle)); - } - return bundlePathToInstallP.get(bundlePath); - }; - - const registerOne = async (bundleName, paths) => { - !bundleNameToAbsolutePaths.has(bundleName) || - Fail`bundleName ${bundleName} already registered`; - bundleNameToAbsolutePaths.set(bundleName, paths); - // use vatAdminState to install this bundle - let bundleP; - if (paths.bundle) { - bundleP = import(paths.bundle).then(ns => ns.default); - } else { - assert(paths.source); - bundleP = bundleSource(paths.source); - } - const bundle = await bundleP; - const bundleID = bundle.endoZipBase64Sha512; - assert(bundleID); - vatAdminState.installNamedBundle(bundleName, bundleID, bundle); - }; - - const registerBundleHandles = async bundleHandleMap => { - const allP = []; - for (const [{ bundleName }, paths] of bundleHandleMap.entries()) { - allP.push(registerOne(bundleName, paths)); - } - await Promise.all(allP); - }; - - return { - registerBundleHandles, - restoreBundleName, - cleanups: [], - zoe: await zoe, - feeMintAccess: await feeMintAccessP, - vatAdminSvc, - vatAdminState, - run: { issuer: stableIssuer, brand: stableBrand }, - installation, - }; -}; - -test.before(async t => { - t.context = await makeTestContext(); -}); - -/** - * @param {import('ava').ExecutionContext>>} t - * @param {{ env?: Record }} [io] - */ -const makeScenario = async (t, { env = process.env } = {}) => { - const rawSpace = await setupBootstrap(t); - const vatPowers = t.context.vatAdminState.getVatPowers(); - const space = { vatPowers, ...rawSpace }; - space.produce.vatAdminSvc.resolve(t.context.vatAdminSvc); - - const loadVat = name => { - const baggage = makeScalarBigMapStore('baggage'); - return import(`@agoric/vats/src/vat-${name}.js`).then(ns => - ns.buildRootObject({}, {}, baggage), - ); - }; - space.produce.loadVat.resolve(loadVat); - space.produce.loadCriticalVat.resolve(loadVat); - - const emptyRunPayment = async () => { - const { - issuer: { - consume: { [Stable.symbol]: stableIssuer }, - }, - brand: { - consume: { [Stable.symbol]: stableBrand }, - }, - } = space; - return E(E(stableIssuer).makeEmptyPurse()).withdraw( - AmountMath.make(await stableBrand, 0n), - ); - }; - - /** @type {PromiseKit<{ mint: ERef, issuer: ERef, brand: Brand}>} */ - const ibcKitP = makePromiseKit(); - - const startDevNet = async () => { - // If we don't have a proper bridge manager, we need it to be undefined. - space.produce.bridgeManager.resolve(undefined); - - /** @type {BankManager} */ - const bankManager = Far('mock BankManager', { - getAssetSubscription: () => assert.fail('not impl'), - getModuleAccountAddress: () => assert.fail('not impl'), - getRewardDistributorDepositFacet: () => - Far('depositFacet', { - receive: () => /** @type {any} */ (null), - }), - addAsset: async (denom, keyword, proposedName, kit) => { - t.log('addAsset', { denom, keyword, issuer: `${kit.issuer}` }); - t.truthy(kit.mint); - ibcKitP.resolve({ ...kit, mint: kit.mint || assert.fail() }); - }, - getBankForAddress: () => assert.fail('not impl'), - }); - space.produce.bankManager.resolve(bankManager); - - space.installation.produce.mintHolder.resolve( - t.context.installation.mintHolder, - ); - - space.produce.initialSupply.resolve(emptyRunPayment()); - - return Promise.all([ - // @ts-expect-error TODO: align types better - addBankAssets(space), - setupClientManager(space), - makeAddressNameHubs(space), - // @ts-expect-error TODO: align types better - makeBoard(space), - // @ts-expect-error TODO: align types better - makeOracleBrands(space), - // @ts-expect-error TODO: align types better - bridgeCoreEval(space), - // @ts-expect-error TODO: align types better - startPriceAuthorityRegistry(space), - ]); - }; - - const provisionMembers = async () => { - const { zoe } = space.consume; - const invitationIssuer = await E(zoe).getInvitationIssuer(); - const nameAdmin = await space.consume.namesByAddressAdmin; - const purses = new Map( - Object.values(voterAddresses).map(addr => { - const purse = E(invitationIssuer).makeEmptyPurse(); - return [addr, purse]; - }), - ); - Object.values(voterAddresses).forEach(addr => { - const { nameHub, nameAdmin: myAddressNameAdmin } = makeNameHubKit(); - const depositFacet = Far('depositFacet', { - receive: pmt => { - const purse = purses.get(addr); - assert(purse, addr); - return E(purse).deposit(pmt); - }, - }); - myAddressNameAdmin.update('depositFacet', depositFacet); - nameAdmin.update(addr, nameHub, myAddressNameAdmin); - }); - return purses; - }; - - /** @type {any} */ - const { restoreBundleName: produceRestoreBundleName } = space.produce; - produceRestoreBundleName.resolve(t.context.restoreBundleName); - const makeEnactCoreProposalsFromBundleHandle = - ({ makeCoreProposalArgs, E: cpE }) => - async allPowers => { - const { - consume: { restoreBundleName }, - } = allPowers; - const restoreRef = async ({ bundleName }) => { - return cpE(restoreBundleName)(bundleName); - }; - - await Promise.all( - makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => { - const subBehavior = makeCoreProposalBehavior({ - manifestBundleRef: ref, - getManifestCall: call, - overrideManifest, - E: cpE, - restoreRef, - }); - await subBehavior(allPowers); - }), - ); - }; - - /** - * @param {string[]} proposals - */ - const evalProposals = async proposals => { - const { code, bundleHandleToAbsolutePaths } = - await extractCoreProposalBundles( - proposals, - dirname, - makeEnactCoreProposalsFromBundleHandle, - () => (lastProposalSequence += 1), - ); - await t.context.registerBundleHandles(bundleHandleToAbsolutePaths); - - const coreEvalMessage = { - type: 'CORE_EVAL', - evals: [ - { - json_permits: 'true', - js_code: code, - }, - ], - }; - - /** @type {any} */ - const { coreEvalBridgeHandler } = space.consume; - await E(coreEvalBridgeHandler).fromBridge(coreEvalMessage); - }; - - const startRunPreview = async () => { - const { brand: atomBrand } = makeIssuerKit( - 'ATOM', - undefined, - harden({ decimalPlaces: 6 }), - ); - env.MIN_INITIAL_POOL_LIQUIDITY = '0'; - await Promise.all([ - E(E(space.consume.agoricNamesAdmin).lookupAdmin('oracleBrand')).update( - 'ATOM', - atomBrand, - ), - evalProposals([coreProposals.startRunPreview]), - ]); - }; - - const enactVaultAssetProposal = async () => { - env.INTERCHAIN_DENOM = 'ibc/abc123'; - await evalProposals([coreProposals.addCollateral]); - }; - - const enactInviteEconCommitteeProposal = async () => { - env.ECON_COMMITTEE_ADDRESSES = JSON.stringify(voterAddresses); - await evalProposals([coreProposals.inviteCommittee]); - }; - - /** - * @param {{ - * agoricNames: ERef, - * board: ERef, - * zoe: ERef, - * wallet: { - * purses: { - * ist: ERef, - * atom: ERef, - * }, - * }, - * }} home - */ - const makeBenefactor = home => { - const { - agoricNames, - zoe, - wallet: { purses }, - } = home; - - return Far('benefactor', { - depositInReserve: async (qty = 10_000n) => { - const atomBrand = await E(agoricNames).lookup('brand', 'ATOM'); - /** @type {ERef} */ - const reserveAPI = E(zoe).getPublicFacet( - E(agoricNames).lookup('instance', 'reserve'), - ); - - const proposal = harden({ - give: { Collateral: AmountMath.make(atomBrand, qty * UNIT) }, - }); - const atom10k = await E(purses.atom).withdraw(proposal.give.Collateral); - const seat = E(zoe).offer( - await E(reserveAPI).makeAddCollateralInvitation(), - proposal, - harden({ Collateral: atom10k }), - ); - return E(seat).getOfferResult(); - }, - }); - }; - - const { agoricNames, zoe, board } = space.consume; - const makeRunPurse = async value => { - /** @type {Promise>} */ - const issuerP = E(agoricNames).lookup('issuer', 'IST'); - const purseP = E(issuerP).makeEmptyPurse(); - return mintRunPayment(value, { - centralSupply: t.context.installation.centralSupply, - feeMintAccess: t.context.feeMintAccess, - zoe, - }).then(pmt => - E(purseP) - .deposit(pmt) - .then(_ => purseP), - ); - }; - const makeAtomPurse = async value => { - // when using benefactor.makePool: - // const { issuer, mint, brand } = await ibcKitP.promise; - const kits = await E(space.consume.contractKits).values(); - /** @type {{ creatorFacet: ERef> }} */ - // @ts-expect-error cast - const { creatorFacet: mint } = - [...kits].find(k => k.label === 'mintHolder') || Fail`no mintHolder`; - const issuer = E(mint).getIssuer(); - const purseP = E(issuer).makeEmptyPurse(); - const brand = await E(issuer).getBrand(); - const pmt = await E(mint).mintPayment(AmountMath.make(brand, value)); - await E(purseP).deposit(pmt); - return purseP; - }; - const purses = { - ist: makeRunPurse(10_000n * UNIT), - atom: makeAtomPurse(10_000n * UNIT), - }; - - return { - startDevNet, - provisionMembers, - startRunPreview, - enactVaultAssetProposal, - enactInviteEconCommitteeProposal, - benefactor: makeBenefactor({ agoricNames, board, zoe, wallet: { purses } }), - space, - }; -}; - -test.skip('Benefactor can add to reserve', async t => { - const s = await makeScenario(t); - await s.startDevNet(); - await s.provisionMembers(); - await s.startRunPreview(); - - await Promise.all([ - s.enactVaultAssetProposal(), - s.enactInviteEconCommitteeProposal(), - ]); - - const result = await s.benefactor.depositInReserve(4000n); - t.deepEqual(result, 'added Collateral to the Reserve'); -}); - -test.skip('voters get invitations', async t => { - const s = await makeScenario(t); - await s.startDevNet(); - const purses = await s.provisionMembers(); - await s.startRunPreview(); - - await Promise.all([ - s.enactVaultAssetProposal(), - s.enactInviteEconCommitteeProposal(), - ]); - - t.is(purses.size, 3); - await Promise.all( - [...purses].map(async ([_addr, purse]) => { - const amt = await E(purse).getCurrentAmount(); - const value = amt.value; - assert(Array.isArray(value)); - - const instanceInv = value.find( - ({ description }) => description === INVITATION_MAKERS_DESC, - ); - t.assert(instanceInv); - - const voterInv = value.find(({ description }) => - description.startsWith('Voter'), - ); - t.assert(voterInv); - t.not(instanceInv, voterInv); - }), - ); -}); - -test.skip('assets are in Vaults', async t => { - const s = await makeScenario(t); - await s.startDevNet(); - await s.provisionMembers(); - await s.startRunPreview(); - // await s.benefactor.makePool(2000n, 1000n); - - await Promise.all([ - s.enactVaultAssetProposal(), - s.enactInviteEconCommitteeProposal(), - ]); - - const { - consume: { zoe, agoricNames }, - instance: { consume: instanceP }, - } = s.space; - const brand = await E(agoricNames).lookup('brand', 'ATOM'); - const stableBrand = await E(agoricNames).lookup('brand', Stable.symbol); - - /** @type {ERef} */ - const vaultsAPI = instanceP.VaultFactory.then(i => E(zoe).getPublicFacet(i)); - - const params = await E(vaultsAPI).getGovernedParams({ - collateralBrand: brand, - }); - t.deepEqual(params.DebtLimit, { - type: 'amount', - // 1000 IST is the default debtLimitValue in add-collateral-core - value: { brand: stableBrand, value: 1_000n * UNIT }, - }); -}); - -test.skip('Committee can raise debt limit', async t => { - const s = await makeScenario(t); - await s.startDevNet(); - const invitationPurses = await s.provisionMembers(); - await s.startRunPreview(); - // await s.benefactor.makePool(2000n, 1000n); - - await Promise.all([ - s.enactVaultAssetProposal(), - s.enactInviteEconCommitteeProposal(), - ]); - - const { agoricNames } = s.space.consume; - const brand = await E(agoricNames).lookup('brand', 'ATOM'); - const stableBrand = await E(agoricNames).lookup('brand', Stable.symbol); - const vaultsInstance = await E(agoricNames).lookup( - 'instance', - 'VaultFactory', - ); - const economicCommittee = await E(agoricNames).lookup( - 'instance', - 'economicCommittee', - ); - - const { zoe } = s.space.consume; - t.log({ purses: invitationPurses }); - - const billsInvitationPurse = invitationPurses.get(voterAddresses.Bill); - assert(billsInvitationPurse); - - const invitationsAmt = await E(billsInvitationPurse).getCurrentAmount(); - t.log('amt.value', invitationsAmt.value); - - const charterInvDetail = /** @type {SetValue} */ (invitationsAmt.value).find( - ({ description }) => description === INVITATION_MAKERS_DESC, - ); - t.assert(charterInvDetail); - - const charterInv = await E(billsInvitationPurse).withdraw( - AmountMath.make(invitationsAmt.brand, harden([charterInvDetail])), - ); - const charterInvitationMakers = await E.get( - E(E(zoe).offer(charterInv)).getOfferResult(), - ).invitationMakers; - - const params = { DebtLimit: AmountMath.make(stableBrand, 100n) }; - - // We happen to know how the timer is implemented. - /** @type { ERef } */ - const timer = /** @type {any } */ (s.space.consume.chainTimerService); - - const now = await E(timer).getCurrentTimestamp(); - const deadline = TimeMath.addAbsRel(now, 3n); - const startVotingSeat = E(zoe).offer( - await E(charterInvitationMakers).VoteOnParamChange(), - undefined, - undefined, - { - params, - instance: vaultsInstance, - deadline, - path: { paramPath: { key: { collateralBrand: brand } } }, - }, - ); - await E(startVotingSeat).getOfferResult(); - await E(startVotingSeat).getPayouts(); - - /** @type {ERef} */ - const committeePublic = E(zoe).getPublicFacet(economicCommittee); - const questions = await E(committeePublic).getOpenQuestions(); - t.log({ questions }); - t.true(questions.length > 0, 'question is open'); - const question = E(committeePublic).getQuestion(questions[0]); - const { positions, questionHandle, counterInstance } = await E( - question, - ).getDetails(); - - await Promise.all( - [...invitationPurses.values()].map(async p => { - const amt2 = await E(p).getCurrentAmount(); - - const item = /** @type {SetValue} */ (amt2.value).find( - ({ description }) => description.startsWith('Voter'), - ); - const inv = await E(p).withdraw( - AmountMath.make(amt2.brand, harden([item])), - ); - t.log({ inv }); - const seat = await E(zoe).offer(inv); - t.log({ seat }); - const { voter } = await E(seat).getOfferResult(); - t.log({ voter }); - return E(voter).castBallotFor(questionHandle, [positions[0]]); - }), - ); - - await E(timer).tick(); - await E(timer).tick(); - await E(timer).tick(); - - const count = E(zoe).getPublicFacet(counterInstance); - const outcome = await E(count).getOutcome(); - t.deepEqual(outcome, { - changes: { DebtLimit: { brand: stableBrand, value: 100n } }, - }); -}); - -// https://github.com/endojs/endo/issues/647 -// test.todo('users can open vaults'); From 960de3ba0d031eeb3d78858559f7e770137c52c7 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Wed, 2 Aug 2023 20:04:38 -0600 Subject: [PATCH 05/34] fix(cosmic-swingset): only require vatconfig if uninitialized --- packages/cosmic-swingset/src/chain-main.js | 17 +++-- packages/cosmic-swingset/src/launch-chain.js | 72 ++++++++++++-------- packages/cosmic-swingset/src/sim-chain.js | 28 +++++--- 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/packages/cosmic-swingset/src/chain-main.js b/packages/cosmic-swingset/src/chain-main.js index 287b23a324d..305079d7118 100644 --- a/packages/cosmic-swingset/src/chain-main.js +++ b/packages/cosmic-swingset/src/chain-main.js @@ -359,12 +359,15 @@ export default async function main(progname, args, { env, homedir, agcc }) { const argv = { bootMsg, }; - const vatHref = await importMetaResolve( - env.CHAIN_BOOTSTRAP_VAT_CONFIG || - argv.bootMsg.params.bootstrap_vat_config, - import.meta.url, - ); - const vatconfig = new URL(vatHref).pathname; + const getVatConfig = async () => { + const vatHref = await importMetaResolve( + env.CHAIN_BOOTSTRAP_VAT_CONFIG || + argv.bootMsg.params.bootstrap_vat_config, + import.meta.url, + ); + const vatconfig = new URL(vatHref).pathname; + return vatconfig; + }; // Delay makeShutdown to override the golang interrupts const { registerShutdown } = makeShutdown(); @@ -463,7 +466,7 @@ export default async function main(progname, args, { env, homedir, agcc }) { clearChainSends, replayChainSends, bridgeOutbound: doOutboundBridge, - vatconfig, + vatconfig: getVatConfig, argv, env, verboseBlocks: true, diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index bc10c58c7cf..893aeafc62c 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -68,7 +68,7 @@ const getHostKey = path => `host.${path}`; * @param {Map<*, *>} mailboxStorage * @param {undefined | ((dstID: string, obj: any) => any)} bridgeOutbound * @param {SwingStoreKernelStorage} kernelStorage - * @param {string} vatconfig absolute path + * @param {string | (() => string | Promise)} vatconfig absolute path * @param {unknown} bootstrapArgs JSON-serializable data * @param {{}} env * @param {*} options @@ -83,42 +83,48 @@ export async function buildSwingset( { debugName = undefined, slogCallbacks, slogSender }, ) { const debugPrefix = debugName === undefined ? '' : `${debugName}:`; - let config = await loadSwingsetConfigFile(vatconfig); - if (config === null) { - config = loadBasedir(vatconfig); - } - const mbs = buildMailboxStateMap(mailboxStorage); - const timer = buildTimer(); - const mb = buildMailbox(mbs); - config.devices = { - mailbox: { - sourceSpec: mb.srcPath, - }, - timer: { - sourceSpec: timer.srcPath, - }, - }; + + const bridgeDevice = bridgeOutbound && buildBridge(bridgeOutbound); + const mailboxDevice = buildMailbox(mbs); + const timerDevice = buildTimer(); + const deviceEndowments = { - mailbox: { ...mb.endowments }, - timer: { ...timer.endowments }, + mailbox: { ...mailboxDevice.endowments }, + timer: { ...timerDevice.endowments }, }; - - let bridgeInbound; - if (bridgeOutbound) { - const bd = buildBridge(bridgeOutbound); - config.devices.bridge = { - sourceSpec: bd.srcPath, - }; - deviceEndowments.bridge = { ...bd.endowments }; - bridgeInbound = bd.deliverInbound; + if (bridgeDevice) { + deviceEndowments.bridge = { ...bridgeDevice.endowments }; } async function ensureSwingsetInitialized() { if (swingsetIsInitialized(kernelStorage)) { return; } - if (!config) throw Fail`config not yet set`; + + const configLocation = await (typeof vatconfig === 'function' + ? vatconfig() + : vatconfig); + let config = await loadSwingsetConfigFile(configLocation); + if (config === null) { + config = loadBasedir(configLocation); + } + + config.devices = { + mailbox: { + sourceSpec: mailboxDevice.srcPath, + }, + timer: { + sourceSpec: timerDevice.srcPath, + }, + }; + + if (bridgeDevice) { + config.devices.bridge = { + sourceSpec: bridgeDevice.srcPath, + }; + } + const { coreProposals, clearStorageSubtrees, @@ -135,7 +141,7 @@ export async function buildSwingset( if (coreProposals) { const { bundles, code } = await extractCoreProposalBundles( coreProposals, - vatconfig, // for path resolution + configLocation, // for path resolution ); swingsetConfig.bundles = { ...swingsetConfig.bundles, ...bundles }; @@ -162,6 +168,7 @@ export async function buildSwingset( debugPrefix, }); } + await ensureSwingsetInitialized(); const controller = await makeSwingsetController( kernelStorage, @@ -176,7 +183,12 @@ export async function buildSwingset( // We DON'T want to run the kernel yet, only when the application decides // (either on bootstrap block (0) or in endBlock). - return { controller, mb, bridgeInbound, timer }; + return { + controller, + mb: mailboxDevice, + bridgeInbound: bridgeDevice && bridgeDevice.deliverInbound, + timer: timerDevice, + }; } /** diff --git a/packages/cosmic-swingset/src/sim-chain.js b/packages/cosmic-swingset/src/sim-chain.js index 685c4674b37..78f113594a6 100644 --- a/packages/cosmic-swingset/src/sim-chain.js +++ b/packages/cosmic-swingset/src/sim-chain.js @@ -34,7 +34,9 @@ async function makeMapStorage(file) { const map = new Map(); map.commit = async () => { const obj = {}; - [...map.entries()].forEach(([k, v]) => (obj[k] = exportMailbox(v))); + for (const [k, v] of map.entries()) { + obj[k] = exportMailbox(v); + } const json = stringify(obj); await fs.promises.writeFile(file, json); }; @@ -43,8 +45,11 @@ async function makeMapStorage(file) { content = await fs.promises.readFile(file); return JSON.parse(content); })().then( - obj => - Object.entries(obj).forEach(([k, v]) => map.set(k, importMailbox(v))), + obj => { + for (const [k, v] of Object.entries(obj)) { + map.set(k, importMailbox(v)); + } + }, () => {}, ); @@ -70,12 +75,15 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { }, }; - const url = await importMetaResolve( - process.env.CHAIN_BOOTSTRAP_VAT_CONFIG || - argv.bootMsg.params.bootstrap_vat_config, - import.meta.url, - ); - const vatconfig = new URL(url).pathname; + const getVatConfig = async () => { + const url = await importMetaResolve( + process.env.CHAIN_BOOTSTRAP_VAT_CONFIG || + argv.bootMsg.params.bootstrap_vat_config, + import.meta.url, + ); + const vatconfig = new URL(url).pathname; + return vatconfig; + }; const stateDBdir = path.join(basedir, `fake-chain-${GCI}-state`); function replayChainSends() { Fail`Replay not implemented`; @@ -108,7 +116,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { mailboxStorage, clearChainSends, replayChainSends, - vatconfig, + vatconfig: getVatConfig, argv, debugName: GCI, metricsProvider, From e36966dd0d9164ced5d0b70acc88b773b639adb9 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Fri, 28 Jul 2023 22:45:06 -0600 Subject: [PATCH 06/34] feat(cosmic-swingset): implement `ENACTED_UPGRADE` blocking send --- packages/cosmic-swingset/package.json | 1 + packages/cosmic-swingset/src/helpers/json.js | 19 +++++ packages/cosmic-swingset/src/launch-chain.js | 81 +++++++++++++++++++- packages/internal/src/action-types.js | 1 + 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 packages/cosmic-swingset/src/helpers/json.js diff --git a/packages/cosmic-swingset/package.json b/packages/cosmic-swingset/package.json index 06f331abe86..0b01815be77 100644 --- a/packages/cosmic-swingset/package.json +++ b/packages/cosmic-swingset/package.json @@ -30,6 +30,7 @@ "@agoric/swing-store": "^0.9.2-u13.0", "@agoric/swingset-vat": "^0.32.3-u13.0", "@agoric/telemetry": "^0.6.3-u13.0", + "@endo/bundle-source": "2.5.2-upstream-rollup", "@endo/far": "0.2.18", "@endo/import-bundle": "0.3.4", "@endo/init": "0.5.56", diff --git a/packages/cosmic-swingset/src/helpers/json.js b/packages/cosmic-swingset/src/helpers/json.js new file mode 100644 index 00000000000..af6b991c171 --- /dev/null +++ b/packages/cosmic-swingset/src/helpers/json.js @@ -0,0 +1,19 @@ +// @ts-check + +/** + * Parses JSON and, if necessary, throws exceptions that include the location + * of the offending file. + * + * @param {string} source + * @param {string} location + */ +export const parseLocatedJson = (source, location) => { + try { + return JSON.parse(source); + } catch (error) { + if (error instanceof SyntaxError) { + throw SyntaxError(`Cannot parse JSON from ${location}, ${error}`); + } + throw error; + } +}; diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index 893aeafc62c..8cb2e24c75b 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -4,6 +4,8 @@ import anylogger from 'anylogger'; import { E } from '@endo/far'; +import bundleSource from '@endo/bundle-source'; + import { buildMailbox, buildMailboxStateMap, @@ -39,6 +41,7 @@ import { import { parseParams } from './params.js'; import { makeQueue } from './helpers/make-queue.js'; import { exportStorage } from './export-storage.js'; +import { parseLocatedJson } from './helpers/json.js'; const console = anylogger('launch-chain'); const blockManagerConsole = anylogger('block-manager'); @@ -399,10 +402,10 @@ export async function launch({ bridgeInbound(source, body); } - async function installBundle(bundleSource) { + async function installBundle(bundleJson) { let bundle; try { - bundle = JSON.parse(bundleSource); + bundle = JSON.parse(bundleJson); } catch (e) { blockManagerConsole.warn('INSTALL_BUNDLE warn:', e); return; @@ -746,7 +749,14 @@ export async function launch({ blockTime, upgradePlan, }); - // TODO: Process upgrade plan + // Process upgrade plan + const upgradedAction = { + type: ActionType.ENACTED_UPGRADE, + upgradePlan, + blockHeight, + blockTime, + }; + await doBlockingSend(upgradedAction); controller.writeSlogObject({ type: 'cosmic-swingset-upgrade-finish', blockHeight, @@ -757,6 +767,71 @@ export async function launch({ return true; } + case ActionType.ENACTED_UPGRADE: { + // Install and execute new core proposals. + const { + upgradePlan: { info: upgradeInfoJson = null } = {}, + blockHeight, + blockTime, + } = action; + const upgradePlanInfo = + upgradeInfoJson && + parseLocatedJson(upgradeInfoJson, 'ENACTED_UPGRADE upgradePlan.info'); + + // Handle the planned core proposals as just another action. + const { coreProposals = [] } = upgradePlanInfo || {}; + + if (!coreProposals.length) { + // Nothing to do. + return undefined; + } + + const { bundles, code: coreEvalCode } = + await extractCoreProposalBundles(coreProposals, vatconfig, { + handleToBundleSpec: async (handle, source, _sequence, _piece) => { + const bundle = await bundleSource(source); + const { endoZipBase64Sha512: hash } = bundle; + const bundleID = `b1-${hash}`; + handle.bundleID = bundleID; + harden(handle); + return harden([`${bundleID}: ${source}`, bundle]); + }, + }); + + for (const [meta, bundle] of Object.entries(bundles)) { + // eslint-disable-next-line no-await-in-loop + await controller + .validateAndInstallBundle(bundle) + .catch(e => Fail`Cannot validate and install ${meta}: ${e}`); + } + + // Now queue the code for evaluation. + // + // TODO: Once SwingSet sprouts some tools for preemption, we should use + // them to help the upgrade process finish promptly. + const coreEvalAction = { + type: ActionType.CORE_EVAL, + blockHeight, + blockTime, + evals: [ + { + json_permits: 'true', + js_code: coreEvalCode, + }, + ], + }; + highPriorityQueue.push({ + context: { + blockHeight, + txHash: 'x/upgrade', + msgIdx: 0, + }, + action: coreEvalAction, + }); + + return undefined; + } + case ActionType.COMMIT_BLOCK: { const { blockHeight, blockTime } = action; verboseBlocks && diff --git a/packages/internal/src/action-types.js b/packages/internal/src/action-types.js index a7dec994dff..869f87c901e 100644 --- a/packages/internal/src/action-types.js +++ b/packages/internal/src/action-types.js @@ -2,6 +2,7 @@ export const AG_COSMOS_INIT = 'AG_COSMOS_INIT'; export const SWING_STORE_EXPORT = 'SWING_STORE_EXPORT'; +export const ENACTED_UPGRADE = 'ENACTED_UPGRADE'; export const BEGIN_BLOCK = 'BEGIN_BLOCK'; export const CALCULATE_FEES_IN_BEANS = 'CALCULATE_FEES_IN_BEANS'; export const CORE_EVAL = 'CORE_EVAL'; From 41133e00aa9b82e2daf89cf5cff5ab72a6c4ea76 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Thu, 3 Aug 2023 20:43:00 -0600 Subject: [PATCH 07/34] fix(cosmic-swingset): only search for the `vatconfig` on init --- packages/cosmic-swingset/src/launch-chain.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index 8cb2e24c75b..e001d2f6e47 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -25,6 +25,7 @@ import { makeWithQueue } from '@agoric/internal/src/queue.js'; import * as ActionType from '@agoric/internal/src/action-types.js'; import { extractCoreProposalBundles } from '@agoric/deploy-script-support/src/extract-proposal.js'; +import { fileURLToPath } from 'url'; import { makeDefaultMeterProvider, @@ -71,7 +72,7 @@ const getHostKey = path => `host.${path}`; * @param {Map<*, *>} mailboxStorage * @param {undefined | ((dstID: string, obj: any) => any)} bridgeOutbound * @param {SwingStoreKernelStorage} kernelStorage - * @param {string | (() => string | Promise)} vatconfig absolute path + * @param {string | (() => string | Promise)} vatconfig absolute path or thunk * @param {unknown} bootstrapArgs JSON-serializable data * @param {{}} env * @param {*} options @@ -786,8 +787,10 @@ export async function launch({ return undefined; } + // Find scripts relative to our location. + const myFilename = fileURLToPath(import.meta.url); const { bundles, code: coreEvalCode } = - await extractCoreProposalBundles(coreProposals, vatconfig, { + await extractCoreProposalBundles(coreProposals, myFilename, { handleToBundleSpec: async (handle, source, _sequence, _piece) => { const bundle = await bundleSource(source); const { endoZipBase64Sha512: hash } = bundle; From 19725e5a132056a314d90975fffbb89053de8829 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 11 Aug 2023 12:40:01 -0400 Subject: [PATCH 08/34] feat: better diagnostic for bad proposal --- packages/deploy-script-support/src/extract-proposal.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 23550ef0133..408c223452f 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -184,6 +184,10 @@ export const extractCoreProposalBundles = async ( const behaviorSource = pathResolve(initDir, sourceSpec); const behaviors = await import(behaviorSource); const [exportedGetManifest, ...manifestArgs] = getManifestCall; + assert( + exportedGetManifest in behaviors, + `behavior ${behaviorSource} missing ${exportedGetManifest}`, + ); const { manifest: overrideManifest } = await behaviors[ exportedGetManifest ](harden({ restoreRef: () => null }), ...manifestArgs); From 452e6aded8ef387f214475c61d82b9ab564c2535 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Sat, 12 Aug 2023 11:23:01 -0400 Subject: [PATCH 09/34] chore(types): improve coverage --- .../src/externalTypes.js | 2 +- .../src/getBundlerMaker.js | 3 ++ .../src/writeCoreProposal.js | 41 ++++++++++++++++++- .../test/unitTests/test-getBundlerMaker.js | 2 + 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/deploy-script-support/src/externalTypes.js b/packages/deploy-script-support/src/externalTypes.js index 442ea8bcce3..5288582b099 100644 --- a/packages/deploy-script-support/src/externalTypes.js +++ b/packages/deploy-script-support/src/externalTypes.js @@ -30,7 +30,7 @@ export {}; * @param {string} srcSpec * @param {string} bundlePath * @param {any} [opts] - * @returns {ManifestBundleRef} + * @returns {Promise} */ /** diff --git a/packages/deploy-script-support/src/getBundlerMaker.js b/packages/deploy-script-support/src/getBundlerMaker.js index 375d7c331b7..5e419703ca6 100644 --- a/packages/deploy-script-support/src/getBundlerMaker.js +++ b/packages/deploy-script-support/src/getBundlerMaker.js @@ -13,6 +13,8 @@ import { E } from '@endo/far'; import url from 'url'; +/** @typedef {ReturnType['publicFacet']} BundleMaker */ + export const makeGetBundlerMaker = (homeP, { lookup, bundleSource }) => async ({ @@ -20,6 +22,7 @@ export const makeGetBundlerMaker = log = console.log, } = {}) => { const { board: optionalBoard, zoe, scratch } = await homeP; + /** @type {() => Promise} */ const lookupOrCreate = async () => { // Locate the bundler maker if any already exists at the given path. let bundlerMaker = await lookup(JSON.parse(BUNDLER_MAKER_LOOKUP)); diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 57e34e9fe05..144ef6bebff 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -7,6 +7,25 @@ import { createBundles } from '@agoric/internal/src/node/createBundles.js'; import { defangAndTrim, mergePermits, stringify } from './code-gen.js'; import { makeCoreProposalBehavior, permits } from './coreProposalBehavior.js'; +/** + * @callback WriteCoreProposal + * @param {string} filePrefix + * @param {import('./externalTypes.js').ProposalBuilder} proposalBuilder + * @returns {Promise} + */ + +/** + * + * @param {*} homeP + * @param {*} endowments + * @param {{ + * getBundlerMaker: () => Promise, + * getBundleSpec: (...args: *) => Promise, + * log?: typeof console.log, + * writeFile?: typeof fs.promises.writeFile + * }} io + * @returns {WriteCoreProposal} + */ export const makeWriteCoreProposal = ( homeP, endowments, @@ -50,8 +69,18 @@ export const makeWriteCoreProposal = ( }; }; - let mutex = Promise.resolve(); + let mutex = + /** @type {Promise} */ ( + Promise.resolve() + ); + /** @type {WriteCoreProposal} */ const writeCoreProposal = async (filePrefix, proposalBuilder) => { + /** + * + * @param {string} entrypoint + * @param {string} [bundlePath] + * @returns {Promise} + */ const getBundle = async (entrypoint, bundlePath) => { if (!bundlePath) { return bundleSource(pathResolve(entrypoint)); @@ -62,7 +91,14 @@ export const makeWriteCoreProposal = ( return ns.default; }; - // Install an entrypoint. + /** + * Install an entrypoint. + * + * @param {string} entrypoint + * @param {string} [bundlePath] + * @param [opts] + * @returns {Promise} + */ const install = async (entrypoint, bundlePath, opts) => { const bundle = getBundle(entrypoint, bundlePath); @@ -71,6 +107,7 @@ export const makeWriteCoreProposal = ( // console.log('installing', { filePrefix, entrypoint, bundlePath }); return getBundleSpec(bundle, getBundler, opts); }); + // @ts-expect-error xxx mutex type narrowing return mutex; }; diff --git a/packages/deploy-script-support/test/unitTests/test-getBundlerMaker.js b/packages/deploy-script-support/test/unitTests/test-getBundlerMaker.js index 53875a9fa7d..bea7a2cb5d4 100644 --- a/packages/deploy-script-support/test/unitTests/test-getBundlerMaker.js +++ b/packages/deploy-script-support/test/unitTests/test-getBundlerMaker.js @@ -15,10 +15,12 @@ test('getBundlerMaker - already made', async t => { const getBundlerMaker = makeGetBundlerMaker({}, { lookup }); const bundler = await getBundlerMaker({ log: t.log }); + // @ts-expect-error mock lookup result t.is(bundler, 'BUNDLER_MAKER_FOUND'); }); test('getBundlerMaker - not yet made', async t => { + /** @type {any} */ let bundlerMaker; const zoe = { install: async b => { From 5c3398428787de999c8cc20bbd1d8e4d0d85afbc Mon Sep 17 00:00:00 2001 From: Mathieu Hofman Date: Wed, 30 Aug 2023 00:03:59 +0000 Subject: [PATCH 10/34] refactor(cosmic-swingset): share runSwingset with bootstrap --- packages/cosmic-swingset/src/launch-chain.js | 182 ++++++++++--------- packages/cosmic-swingset/src/sim-chain.js | 1 + 2 files changed, 94 insertions(+), 89 deletions(-) diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index e001d2f6e47..ad0668a1a0f 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -198,7 +198,8 @@ export async function buildSwingset( /** * @typedef {import('@agoric/swingset-vat').RunPolicy & { * shouldRun(): boolean; - * remainingBeans(): bigint; + * remainingBeans(): bigint | undefined; + * totalBeans(): bigint; * }} ChainRunPolicy */ @@ -211,19 +212,24 @@ export async function buildSwingset( /** * @param {BeansPerUnit} beansPerUnit + * @param {boolean} [ignoreBlockLimit] * @returns {ChainRunPolicy} */ -function computronCounter({ - [BeansPerBlockComputeLimit]: blockComputeLimit, - [BeansPerVatCreation]: vatCreation, - [BeansPerXsnapComputron]: xsnapComputron, -}) { +function computronCounter( + { + [BeansPerBlockComputeLimit]: blockComputeLimit, + [BeansPerVatCreation]: vatCreation, + [BeansPerXsnapComputron]: xsnapComputron, + }, + ignoreBlockLimit = false, +) { assert.typeof(blockComputeLimit, 'bigint'); assert.typeof(vatCreation, 'bigint'); assert.typeof(xsnapComputron, 'bigint'); let totalBeans = 0n; - const shouldRun = () => totalBeans < blockComputeLimit; - const remainingBeans = () => blockComputeLimit - totalBeans; + const shouldRun = () => ignoreBlockLimit || totalBeans < blockComputeLimit; + const remainingBeans = () => + ignoreBlockLimit ? undefined : blockComputeLimit - totalBeans; const policy = harden({ vatCreated() { @@ -247,23 +253,17 @@ function computronCounter({ return shouldRun(); }, emptyCrank() { - return true; + return shouldRun(); }, shouldRun, remainingBeans, + totalBeans() { + return totalBeans; + }, }); return policy; } -function neverStop() { - return harden({ - vatCreated: () => true, - crankComplete: () => true, - crankFailed: () => true, - emptyCrank: () => true, - }); -} - export async function launch({ actionQueueStorage, highPriorityQueueStorage, @@ -353,14 +353,55 @@ export async function launch({ inboundQueueMetrics, }); - async function bootstrapBlock(_blockHeight, blockTime) { + /** + * @param {number} blockHeight + * @param {ChainRunPolicy} runPolicy + */ + function makeRunSwingset(blockHeight, runPolicy) { + let runNum = 0; + async function runSwingset() { + const startBeans = runPolicy.totalBeans(); + controller.writeSlogObject({ + type: 'cosmic-swingset-run-start', + blockHeight, + runNum, + startBeans, + remainingBeans: runPolicy.remainingBeans(), + }); + // TODO: crankScheduler does a schedulerBlockTimeHistogram thing + // that needs to be revisited, it used to be called once per + // block, now it's once per processed inbound queue item + await crankScheduler(runPolicy); + const finishBeans = runPolicy.totalBeans(); + controller.writeSlogObject({ + type: 'kernel-stats', + stats: controller.getStats(), + }); + controller.writeSlogObject({ + type: 'cosmic-swingset-run-finish', + blockHeight, + runNum, + startBeans, + finishBeans, + usedBeans: finishBeans - startBeans, + remainingBeans: runPolicy.remainingBeans(), + }); + runNum += 1; + return runPolicy.shouldRun(); + } + return runSwingset; + } + + async function bootstrapBlock(blockHeight, blockTime, params) { // We need to let bootstrap know of the chain time. The time of the first // block may be the genesis time, or the block time of the upgrade block. timer.poll(blockTime); // This is before the initial block, we need to finish processing the // entire bootstrap before opening for business. - const policy = neverStop(); - await crankScheduler(policy); + const runPolicy = computronCounter(params.beansPerUnit, true); + const runSwingset = makeRunSwingset(blockHeight, runPolicy); + + await runSwingset(); } async function saveChainState() { @@ -510,67 +551,39 @@ export async function launch({ return p; } - async function runKernel(runPolicy, blockHeight, blockTime) { - let runNum = 0; - async function runSwingset() { - const initialBeans = runPolicy.remainingBeans(); - controller.writeSlogObject({ - type: 'cosmic-swingset-run-start', - blockHeight, - runNum, - initialBeans, - }); - // TODO: crankScheduler does a schedulerBlockTimeHistogram thing - // that needs to be revisited, it used to be called once per - // block, now it's once per processed inbound queue item - await crankScheduler(runPolicy); - const remainingBeans = runPolicy.remainingBeans(); - controller.writeSlogObject({ - type: 'kernel-stats', - stats: controller.getStats(), - }); - controller.writeSlogObject({ - type: 'cosmic-swingset-run-finish', - blockHeight, - runNum, - remainingBeans, - usedBeans: initialBeans - remainingBeans, - }); - runNum += 1; - return runPolicy.shouldRun(); - } - - /** - * Process as much as we can from an inbound queue, which contains - * first the old actions not previously processed, followed by actions - * newly added, running the kernel to completion after each. - * - * @param {InboundQueue} inboundQueue - */ - async function processActions(inboundQueue) { - let keepGoing = true; - for (const { action, context } of inboundQueue.consumeAll()) { - const inboundNum = `${context.blockHeight}-${context.txHash}-${context.msgIdx}`; - inboundQueueMetrics.decStat(); - // eslint-disable-next-line no-await-in-loop - await performAction(action, inboundNum); - // eslint-disable-next-line no-await-in-loop - keepGoing = await runSwingset(); - if (!keepGoing) { - // any leftover actions will remain on the inbound queue for possible - // processing in the next block - break; - } + /** + * Process as much as we can from an inbound queue, which contains + * first the old actions not previously processed, followed by actions + * newly added, running the kernel to completion after each. + * + * @param {InboundQueue} inboundQueue + * @param {ReturnType} runSwingset + */ + async function processActions(inboundQueue, runSwingset) { + let keepGoing = true; + for (const { action, context } of inboundQueue.consumeAll()) { + const inboundNum = `${context.blockHeight}-${context.txHash}-${context.msgIdx}`; + inboundQueueMetrics.decStat(); + // eslint-disable-next-line no-await-in-loop + await performAction(action, inboundNum); + // eslint-disable-next-line no-await-in-loop + keepGoing = await runSwingset(); + if (!keepGoing) { + // any leftover actions will remain on the inbound queue for possible + // processing in the next block + break; } - return keepGoing; } + return keepGoing; + } + async function runKernel(runSwingset, blockHeight, blockTime) { // First, complete leftover work, if any let keepGoing = await runSwingset(); if (!keepGoing) return; // Then, process as much as we can from the priorityQueue. - keepGoing = await processActions(highPriorityQueue); + keepGoing = await processActions(highPriorityQueue, runSwingset); if (!keepGoing) return; // Then, update the timer device with the new external time, which might @@ -587,7 +600,7 @@ export async function launch({ if (!keepGoing) return; // Finally, process as much as we can from the actionQueue. - await processActions(actionQueue); + await processActions(actionQueue, runSwingset); } async function endBlock(blockHeight, blockTime, params) { @@ -603,8 +616,9 @@ export async function launch({ // make a runPolicy that will be shared across all cycles const runPolicy = computronCounter(params.beansPerUnit); + const runSwingset = makeRunSwingset(blockHeight, runPolicy); - await runKernel(runPolicy, blockHeight, blockTime); + await runKernel(runSwingset, blockHeight, blockTime); if (END_BLOCK_SPIN_MS) { // Introduce a busy-wait to artificially put load on the chain. @@ -708,34 +722,24 @@ export async function launch({ // ); switch (action.type) { case ActionType.AG_COSMOS_INIT: { - const { isBootstrap, upgradePlan, blockTime } = action; + const { isBootstrap, upgradePlan, blockTime, params } = action; // This only runs for the very first block on the chain. if (isBootstrap) { verboseBlocks && blockManagerConsole.info('block bootstrap'); (savedHeight === 0 && savedBeginHeight === 0) || Fail`Cannot run a bootstrap block at height ${savedHeight}`; + const bootstrapBlockParams = parseParams(params); const blockHeight = 0; - const runNum = 0; controller.writeSlogObject({ type: 'cosmic-swingset-bootstrap-block-start', blockTime, }); - controller.writeSlogObject({ - type: 'cosmic-swingset-run-start', - blockHeight, - runNum, - }); // Start a block transaction, but without changing state // for the upcoming begin block check saveBeginHeight(savedBeginHeight); await processAction(action.type, async () => - bootstrapBlock(blockHeight, blockTime), + bootstrapBlock(blockHeight, blockTime, bootstrapBlockParams), ); - controller.writeSlogObject({ - type: 'cosmic-swingset-run-finish', - blockHeight, - runNum, - }); controller.writeSlogObject({ type: 'cosmic-swingset-bootstrap-block-finish', blockTime, diff --git a/packages/cosmic-swingset/src/sim-chain.js b/packages/cosmic-swingset/src/sim-chain.js index 78f113594a6..4faf71a6142 100644 --- a/packages/cosmic-swingset/src/sim-chain.js +++ b/packages/cosmic-swingset/src/sim-chain.js @@ -216,6 +216,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { type: 'AG_COSMOS_INIT', blockTime: scaleBlockTime(Date.now()), isBootstrap: true, + params: DEFAULT_SIM_SWINGSET_PARAMS, }); blockHeight = initialHeight; }; From 1cf7c92ee422c794c1b706214a21d3c06a36fdf0 Mon Sep 17 00:00:00 2001 From: Mathieu Hofman Date: Thu, 31 Aug 2023 00:10:28 +0000 Subject: [PATCH 11/34] feat(cosmic-swingset): run upgrade actions to completion --- packages/cosmic-swingset/src/launch-chain.js | 85 +++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index ad0668a1a0f..56a4dfe95c0 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -40,7 +40,7 @@ import { BeansPerXsnapComputron, } from './sim-params.js'; import { parseParams } from './params.js'; -import { makeQueue } from './helpers/make-queue.js'; +import { makeQueue, makeQueueStorageMock } from './helpers/make-queue.js'; import { exportStorage } from './export-storage.js'; import { parseLocatedJson } from './helpers/json.js'; @@ -312,6 +312,14 @@ export async function launch({ const actionQueue = makeQueue(actionQueueStorage); /** @type {InboundQueue} */ const highPriorityQueue = makeQueue(highPriorityQueueStorage); + /** + * In memory queue holding actions that must be consumed entirely + * during the block. If it's not drained, we open the gates to + * hangover hell. + * + * @type {InboundQueue} + */ + const runThisBlock = makeQueue(makeQueueStorageMock().storage); // Not to be confused with the gas model, this meter is for OpenTelemetry. const metricMeter = metricsProvider.getMeter('ag-chain-cosmos'); @@ -582,6 +590,13 @@ export async function launch({ let keepGoing = await runSwingset(); if (!keepGoing) return; + // Then, if we have anything in the special runThisBlock queue, process + // it and do no further work. + if (runThisBlock.size()) { + await processActions(runThisBlock, runSwingset); + return; + } + // Then, process as much as we can from the priorityQueue. keepGoing = await processActions(highPriorityQueue, runSwingset); if (!keepGoing) return; @@ -611,11 +626,15 @@ export async function launch({ // First, record new actions (bridge/mailbox/etc events that cosmos // added up for delivery to swingset) into our inboundQueue metrics inboundQueueMetrics.updateLength( - actionQueue.size() + highPriorityQueue.size(), + actionQueue.size() + highPriorityQueue.size() + runThisBlock.size(), ); + // If we have work to complete this block, it needs to run to completion. + // It will also run to completion any work that swingset still had pending. + const neverStop = runThisBlock.size() > 0; + // make a runPolicy that will be shared across all cycles - const runPolicy = computronCounter(params.beansPerUnit); + const runPolicy = computronCounter(params.beansPerUnit, neverStop); const runSwingset = makeRunSwingset(blockHeight, runPolicy); await runKernel(runSwingset, blockHeight, blockTime); @@ -747,38 +766,36 @@ export async function launch({ } if (upgradePlan) { const blockHeight = upgradePlan.height; - if (blockNeedsExecution(blockHeight)) { - controller.writeSlogObject({ - type: 'cosmic-swingset-upgrade-start', - blockHeight, - blockTime, - upgradePlan, - }); - // Process upgrade plan - const upgradedAction = { - type: ActionType.ENACTED_UPGRADE, - upgradePlan, - blockHeight, - blockTime, - }; - await doBlockingSend(upgradedAction); - controller.writeSlogObject({ - type: 'cosmic-swingset-upgrade-finish', - blockHeight, - blockTime, - }); - } + + // Process upgrade plan + const upgradedAction = { + type: ActionType.ENACTED_UPGRADE, + upgradePlan, + blockHeight, + blockTime, + }; + await doBlockingSend(upgradedAction); } return true; } case ActionType.ENACTED_UPGRADE: { // Install and execute new core proposals. - const { - upgradePlan: { info: upgradeInfoJson = null } = {}, + const { upgradePlan, blockHeight, blockTime } = action; + + if (!blockNeedsExecution(blockHeight)) { + return undefined; + } + + controller.writeSlogObject({ + type: 'cosmic-swingset-upgrade-start', blockHeight, blockTime, - } = action; + upgradePlan, + }); + + const { info: upgradeInfoJson = null } = upgradePlan || {}; + const upgradePlanInfo = upgradeInfoJson && parseLocatedJson(upgradeInfoJson, 'ENACTED_UPGRADE upgradePlan.info'); @@ -813,9 +830,6 @@ export async function launch({ } // Now queue the code for evaluation. - // - // TODO: Once SwingSet sprouts some tools for preemption, we should use - // them to help the upgrade process finish promptly. const coreEvalAction = { type: ActionType.CORE_EVAL, blockHeight, @@ -827,7 +841,7 @@ export async function launch({ }, ], }; - highPriorityQueue.push({ + runThisBlock.push({ context: { blockHeight, txHash: 'x/upgrade', @@ -836,6 +850,12 @@ export async function launch({ action: coreEvalAction, }); + controller.writeSlogObject({ + type: 'cosmic-swingset-upgrade-finish', + blockHeight, + blockTime, + }); + return undefined; } @@ -849,6 +869,9 @@ export async function launch({ ); } + runThisBlock.size() === 0 || + Fail`We didn't process all "run this block" actions`; + controller.writeSlogObject({ type: 'cosmic-swingset-commit-block-start', blockHeight, From c373264d439659025150eda641680e0093e87530 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 13:03:06 -0500 Subject: [PATCH 12/34] chore(deploy-script-support): Rename variable for clarity --- packages/deploy-script-support/src/coreProposalBehavior.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 6d25bc913b3..a73528effbd 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -45,7 +45,7 @@ export const makeCoreProposalBehavior = ({ overrideManifest, E, log = console.info, - restoreRef: overrideRestoreRef, + restoreRef: customRestoreRef, }) => { const { entries, fromEntries } = Object; @@ -127,7 +127,7 @@ export const makeCoreProposalBehavior = ({ manifestGetterName, bundleExports: Object.keys(proposalNS), }); - const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); + const restoreRef = customRestoreRef || makeRestoreRef(vatAdminSvc, zoe); const { manifest, options: rawOptions, From 42960720ea8fbed2388b6bb8a6f9aa0ae6352167 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 13 Nov 2023 15:34:15 -0500 Subject: [PATCH 13/34] chore(deploy-script-support): Rename `allPowers` to clarify its limited scope --- .../src/coreProposalBehavior.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 080a14bfbf2..e9b99cbfa87 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -8,7 +8,8 @@ const t = 'makeCoreProposalBehavior'; * @typedef {*} BootstrapPowers */ -// These permits apply to `allPowers` in `behavior` below. +// These permits limit the powers passed to the `behavior` function returned by +// `makeCoreProposalBehavior`. export const permits = { consume: { agoricNamesAdmin: t, vatAdminSvc: t, zoe: t }, evaluateBundleCap: t, @@ -56,9 +57,9 @@ export const makeCoreProposalBehavior = ({ return fromEntries(ents); }; - /** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} allPowers */ - const behavior = async allPowers => { - // NOTE: If updating any of these names extracted from `allPowers`, you must + /** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers */ + const behavior = async powers => { + // NOTE: If updating any of these names extracted from `powers`, you must // change `permits` above to reflect their accessibility. const { consume: { vatAdminSvc, zoe, agoricNamesAdmin }, @@ -67,7 +68,7 @@ export const makeCoreProposalBehavior = ({ modules: { utils: { runModuleBehaviors }, }, - } = allPowers; + } = powers; const [exportedGetManifest, ...manifestArgs] = getManifestCall; /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} */ @@ -130,7 +131,7 @@ export const makeCoreProposalBehavior = ({ // Evaluate the manifest for our behaviors. return runModuleBehaviors({ - allPowers, + allPowers: powers, behaviors: manifestNS, manifest: overrideManifest || manifest, makeConfig: (name, _permit) => { @@ -146,7 +147,7 @@ export const makeCoreProposalBehavior = ({ export const makeEnactCoreProposalsFromBundleRef = ({ makeCoreProposalArgs, E }) => - async allPowers => { + async powers => { await Promise.all( makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => { const subBehavior = makeCoreProposalBehavior({ @@ -155,7 +156,7 @@ export const makeEnactCoreProposalsFromBundleRef = overrideManifest, E, }); - return subBehavior(allPowers); + return subBehavior(powers); }), ); }; From 7640bae3757849b7d4a40c3cc50ebb13fc00fb61 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 14:26:38 -0500 Subject: [PATCH 14/34] chore(deploy-script-support): Improve JSDoc annotation --- .../src/coreProposalBehavior.js | 39 ++++++++++++++----- .../src/writeCoreProposal.js | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index a73528effbd..bc28ad25aea 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -8,6 +8,12 @@ const t = 'makeCoreProposalBehavior'; * @typedef {*} BootstrapPowers */ +/** + * @typedef {import('./externalTypes.js').ManifestBundleRef} ManifestBundleRef + * @typedef {[methodName: string, ...args: unknown[]]} FlatMethargs + * @typedef {Record>} Manifest + */ + /** * These permits are expected to be the minimum powers required by the * `coreProposalBehavior` function returned from `makeCoreProposalBehavior`. @@ -30,13 +36,13 @@ export const permits = { * for catching bugs. Thus, this maker must not reference any other modules or * definitions. * - * @param {object} opts - * @param {import('./externalTypes.js').ManifestBundleRef} opts.manifestBundleRef - * @param {[methodName: string, ...args: unknown[]]} opts.getManifestCall - * @param {Record>} [opts.overrideManifest] - * @param {typeof import('@endo/far').E} opts.E - * @param {(...args: unknown[]) => void} [opts.log] - * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} [opts.restoreRef] + * @param {object} inputs + * @param {ManifestBundleRef} inputs.manifestBundleRef + * @param {FlatMethargs} inputs.getManifestCall + * @param {Manifest} [inputs.overrideManifest] + * @param {typeof import('@endo/far').E} inputs.E + * @param {(...args: unknown[]) => void} [inputs.log] + * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} [inputs.restoreRef] * @returns {(vatPowers: unknown) => Promise} */ export const makeCoreProposalBehavior = ({ @@ -167,9 +173,20 @@ export const makeCoreProposalBehavior = ({ return coreProposalBehavior; }; -export const makeEnactCoreProposalsFromBundleRef = - ({ makeCoreProposalArgs, E }) => - async powers => { +/** + * @param {object} inputs + * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, overrideManifest?: Manifest }>} inputs.makeCoreProposalArgs + * @param {typeof import('@endo/far').E} inputs.E + */ +export const makeEnactCoreProposalsFromBundleRef = ({ + makeCoreProposalArgs, + E, +}) => { + /** + * @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers + * @returns {Promise} + */ + const enactCoreProposals = async powers => { await Promise.all( makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => { const coreProposalBehavior = makeCoreProposalBehavior({ @@ -182,3 +199,5 @@ export const makeEnactCoreProposalsFromBundleRef = }), ); }; + return enactCoreProposals; +}; diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 8a489f47384..99c4ac51007 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -98,7 +98,7 @@ export const makeWriteCoreProposal = ( * * @param {string} entrypoint * @param {string} [bundlePath] - * @param [opts] + * @param {unknown} [opts] * @returns {Promise} */ const install = async (entrypoint, bundlePath, opts) => { From d59a45538624f5c50dbfab80fba7cc750a31c802 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 13 Nov 2023 15:45:46 -0500 Subject: [PATCH 15/34] chore(deploy-script-support): Move default restoreRef creation up a level --- .../src/coreProposalBehavior.js | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index e9b99cbfa87..19b8ff3331d 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -57,6 +57,23 @@ export const makeCoreProposalBehavior = ({ return fromEntries(ents); }; + const makeRestoreRef = (vatAdminSvc, zoe) => { + /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} */ + const defaultRestoreRef = async bundleRef => { + // extract-proposal.js creates these records, and bundleName is + // the 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 behavior = async powers => { // NOTE: If updating any of these names extracted from `powers`, you must @@ -71,21 +88,6 @@ export const makeCoreProposalBehavior = ({ } = powers; const [exportedGetManifest, ...manifestArgs] = getManifestCall; - /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} */ - const defaultRestoreRef = async ref => { - // extract-proposal.js creates these records, and bundleName is - // the name under which the bundle was installed into - // config.bundles - const p = - 'bundleName' in ref - ? E(vatAdminSvc).getBundleIDByName(ref.bundleName) - : ref.bundleID; - const bundleID = await p; - const label = bundleID.slice(0, 8); - return E(zoe).installBundleID(bundleID, label); - }; - const restoreRef = overrideRestoreRef || defaultRestoreRef; - // Get the on-chain installation containing the manifest and behaviors. console.info('evaluateBundleCap', { manifestBundleRef, @@ -102,10 +104,12 @@ export const makeCoreProposalBehavior = ({ const manifestNS = await evaluateBundleCap(bundleCap); + // Get the manifest and its metadata. console.error('execute', { exportedGetManifest, behaviors: Object.keys(manifestNS), }); + const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); const { manifest, options: rawOptions, From 03666ac8c91577c8e790138a60413544ef4d7e5c Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 14:28:45 -0500 Subject: [PATCH 16/34] chore(deploy-script-support): Fix package reference in comment --- packages/deploy-script-support/src/extract-proposal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 6d2952a8155..fd3d208da9e 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -248,7 +248,7 @@ export const extractCoreProposalBundles = async ( harden(makeCPArgs); const code = `\ -// This is generated by @agoric/cosmic-swingset/src/extract-proposal.js - DO NOT EDIT +// This is generated by @agoric/deploy-script-support/src/extract-proposal.js - DO NOT EDIT /* eslint-disable */ const makeCoreProposalArgs = harden(${stringify(makeCPArgs, true)}); From df36c5b420c2be8a8f674e59b633b6f15499f666 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 13 Nov 2023 15:54:52 -0500 Subject: [PATCH 17/34] chore(deploy-script-support): Clarify the [methodName, ...args] structure of getManifestCall --- .../src/coreProposalBehavior.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 19b8ff3331d..302f6bf079e 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -26,7 +26,7 @@ export const permits = { * * @param {object} opts * @param {import('./externalTypes.js').ManifestBundleRef} opts.manifestBundleRef - * @param {[string, ...unknown[]]} opts.getManifestCall + * @param {[methodName: string, ...args: unknown[]]} opts.getManifestCall * @param {Record>} [opts.overrideManifest] * @param {typeof import('@endo/far').E} opts.E * @param {(...args: unknown[]) => void} [opts.log] @@ -35,7 +35,7 @@ export const permits = { */ export const makeCoreProposalBehavior = ({ manifestBundleRef, - getManifestCall, + getManifestCall: [manifestGetterName, ...manifestGetterArgs], overrideManifest, E, log = console.info, @@ -86,12 +86,11 @@ export const makeCoreProposalBehavior = ({ utils: { runModuleBehaviors }, }, } = powers; - const [exportedGetManifest, ...manifestArgs] = getManifestCall; // Get the on-chain installation containing the manifest and behaviors. console.info('evaluateBundleCap', { manifestBundleRef, - exportedGetManifest, + exportedGetManifest: manifestGetterName, vatAdminSvc, }); let bcapP; @@ -106,7 +105,7 @@ export const makeCoreProposalBehavior = ({ // Get the manifest and its metadata. console.error('execute', { - exportedGetManifest, + exportedGetManifest: manifestGetterName, behaviors: Object.keys(manifestNS), }); const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); @@ -114,9 +113,9 @@ export const makeCoreProposalBehavior = ({ manifest, options: rawOptions, installations: rawInstallations, - } = await manifestNS[exportedGetManifest]( + } = await manifestNS[manifestGetterName]( harden({ restoreRef }), - ...manifestArgs, + ...manifestGetterArgs, ); // Await references in the options or installations. From c6c172b6936f885108e9a016e7500ee28443fb99 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 14:35:26 -0500 Subject: [PATCH 18/34] chore(deploy-script-support): For clarity, rename "override" paramaters to "custom" (the former can be read like a verb) --- .../src/coreProposalBehavior.js | 12 ++++++------ .../deploy-script-support/src/writeCoreProposal.js | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index bc28ad25aea..1d8e50241f5 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -39,19 +39,19 @@ export const permits = { * @param {object} inputs * @param {ManifestBundleRef} inputs.manifestBundleRef * @param {FlatMethargs} inputs.getManifestCall - * @param {Manifest} [inputs.overrideManifest] + * @param {Manifest} [inputs.customManifest] * @param {typeof import('@endo/far').E} inputs.E * @param {(...args: unknown[]) => void} [inputs.log] - * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} [inputs.restoreRef] + * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} [inputs.customRestoreRef] * @returns {(vatPowers: unknown) => Promise} */ export const makeCoreProposalBehavior = ({ manifestBundleRef, getManifestCall: [manifestGetterName, ...manifestGetterArgs], - overrideManifest, + customManifest, E, log = console.info, - restoreRef: customRestoreRef, + customRestoreRef, }) => { const { entries, fromEntries } = Object; @@ -162,7 +162,7 @@ export const makeCoreProposalBehavior = ({ // Remember that `powers` may be arbitrarily broad. allPowers: powers, behaviors: proposalNS, - manifest: overrideManifest || manifest, + manifest: customManifest || manifest, makeConfig: (name, _permit) => { log('coreProposal:', name); return { options }; @@ -192,7 +192,7 @@ export const makeEnactCoreProposalsFromBundleRef = ({ const coreProposalBehavior = makeCoreProposalBehavior({ manifestBundleRef: ref, getManifestCall: call, - overrideManifest, + customManifest: overrideManifest, E, }); return coreProposalBehavior(powers); diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 99c4ac51007..18a1b22c688 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -137,7 +137,7 @@ export const makeWriteCoreProposal = ( // console.log('created', { filePrefix, sourceSpec, getManifestCall }); // Extract the top-level permit. - const { permits: proposalPermit, manifest: overrideManifest } = + const { permits: proposalPermit, manifest: customManifest } = await mergeProposalPermit(proposal, permits); // Get an install @@ -150,10 +150,10 @@ export const makeWriteCoreProposal = ( const manifestBundleRef = ${stringify(manifestBundleRef)}; const getManifestCall = harden(${stringify(getManifestCall, true)}); -const overrideManifest = ${stringify(overrideManifest, true)}; +const customManifest = ${stringify(customManifest, true)}; // Make the behavior the completion value. -(${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, overrideManifest, E }); +(${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, customManifest, E }); `; const trimmed = defangAndTrim(code); From 0cb13359bd91e2e239f1cd8df7b10545b5aee87e Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 13 Nov 2023 15:58:24 -0500 Subject: [PATCH 19/34] chore(deploy-script-support): Enforce bundleRef shape --- .../deploy-script-support/src/coreProposalBehavior.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 302f6bf079e..9b0ac80212a 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -96,8 +96,16 @@ export const makeCoreProposalBehavior = ({ let bcapP; if ('bundleName' in manifestBundleRef) { bcapP = E(vatAdminSvc).getNamedBundleCap(manifestBundleRef.bundleName); - } else { + } 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; From 283e64940220ee658f815043d922402603c95ed0 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 14:39:32 -0500 Subject: [PATCH 20/34] =?UTF-8?q?chore(deploy-script-support):=20Complete?= =?UTF-8?q?=20the=20"override"=20=E2=86=92=20"custom"=20renaming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deploy-script-support/src/coreProposalBehavior.js | 6 +++--- packages/deploy-script-support/src/extract-proposal.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 1d8e50241f5..259090f98a1 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -175,7 +175,7 @@ export const makeCoreProposalBehavior = ({ /** * @param {object} inputs - * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, overrideManifest?: Manifest }>} inputs.makeCoreProposalArgs + * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, customManifest?: Manifest }>} inputs.makeCoreProposalArgs * @param {typeof import('@endo/far').E} inputs.E */ export const makeEnactCoreProposalsFromBundleRef = ({ @@ -188,11 +188,11 @@ export const makeEnactCoreProposalsFromBundleRef = ({ */ const enactCoreProposals = async powers => { await Promise.all( - makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => { + makeCoreProposalArgs.map(async ({ ref, call, customManifest }) => { const coreProposalBehavior = makeCoreProposalBehavior({ manifestBundleRef: ref, getManifestCall: call, - customManifest: overrideManifest, + customManifest, E, }); return coreProposalBehavior(powers); diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index fd3d208da9e..4cda7c3e4ac 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -204,7 +204,7 @@ export const extractCoreProposalBundles = async ( exportedGetManifest in behaviors, `behavior ${behaviorSource} missing ${exportedGetManifest}`, ); - const { manifest: overrideManifest } = await behaviors[ + const { manifest: customManifest } = await behaviors[ exportedGetManifest ](harden({ restoreRef: () => null }), ...manifestArgs); @@ -227,7 +227,7 @@ export const extractCoreProposalBundles = async ( return harden({ ref: behaviorBundleHandle, call: getManifestCall, - overrideManifest, + customManifest, bundleSpecs: bundleSpecEntries, }); }), @@ -240,10 +240,10 @@ export const extractCoreProposalBundles = async ( harden(bundles); // Extract the manifest references and calls. - const makeCPArgs = extracted.map(({ ref, call, overrideManifest }) => ({ + const makeCPArgs = extracted.map(({ ref, call, customManifest }) => ({ ref, call, - overrideManifest, + customManifest, })); harden(makeCPArgs); From b5e27d2ef4a371bbad8228c50cbc23359f839ce9 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 13 Nov 2023 16:00:01 -0500 Subject: [PATCH 21/34] chore(deploy-script-support): Rename `manifestNS` to clarify its nature --- .../src/coreProposalBehavior.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 9b0ac80212a..dcbaf28cd25 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -109,19 +109,19 @@ export const makeCoreProposalBehavior = ({ } const bundleCap = await bcapP; - const manifestNS = await evaluateBundleCap(bundleCap); + const installationNS = await evaluateBundleCap(bundleCap); // Get the manifest and its metadata. console.error('execute', { exportedGetManifest: manifestGetterName, - behaviors: Object.keys(manifestNS), + behaviors: Object.keys(installationNS), }); const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); const { manifest, options: rawOptions, installations: rawInstallations, - } = await manifestNS[manifestGetterName]( + } = await installationNS[manifestGetterName]( harden({ restoreRef }), ...manifestGetterArgs, ); @@ -131,7 +131,7 @@ export const makeCoreProposalBehavior = ({ [rawOptions, rawInstallations].map(shallowlyFulfilled), ); - // Publish the installations for behavior dependencies. + // Publish the installations for our dependencies. const installAdmin = E(agoricNamesAdmin).lookupAdmin('installation'); await Promise.all( entries(installations || {}).map(([key, value]) => { @@ -140,10 +140,10 @@ export const makeCoreProposalBehavior = ({ }), ); - // Evaluate the manifest for our behaviors. + // Evaluate the manifest. return runModuleBehaviors({ allPowers: powers, - behaviors: manifestNS, + behaviors: installationNS, manifest: overrideManifest || manifest, makeConfig: (name, _permit) => { log('coreProposal:', name); @@ -152,7 +152,6 @@ export const makeCoreProposalBehavior = ({ }); }; - // Make the behavior the completion value. return behavior; }; From 49672efbd98a675d503094bb0e3b0edc9db58613 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 15:02:36 -0500 Subject: [PATCH 22/34] chore(deploy-script-support): Clarify script completion value as pseudo-export --- packages/deploy-script-support/src/extract-proposal.js | 8 +++++--- packages/deploy-script-support/src/writeCoreProposal.js | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 4cda7c3e4ac..976c2a90871 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -253,9 +253,11 @@ export const extractCoreProposalBundles = async ( const makeCoreProposalArgs = harden(${stringify(makeCPArgs, true)}); -const makeCoreProposalBehavior = ${makeCoreProposalBehavior}; - -(${makeEnactCoreProposals})({ makeCoreProposalArgs, E }); +// Make an enactCoreProposals function and "export" it by way of script completion value. +(( + makeCoreProposalBehavior = ${makeCoreProposalBehavior}, + makeEnactCoreProposals = ${makeEnactCoreProposals}, +) => makeEnactCoreProposals({ makeCoreProposalArgs, E }))(); `; // console.debug('created bundles from proposals:', coreProposals, bundles); diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 18a1b22c688..3c75212a8a2 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -152,8 +152,9 @@ const manifestBundleRef = ${stringify(manifestBundleRef)}; const getManifestCall = harden(${stringify(getManifestCall, true)}); const customManifest = ${stringify(customManifest, true)}; -// Make the behavior the completion value. -(${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, customManifest, E }); +// Make a behavior function and "export" it by way of script completion value. +const behavior = (${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, customManifest, E }); +behavior; `; const trimmed = defangAndTrim(code); From 65a6d9df13cb5b6316b5a9e225655086ec543302 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 23 Nov 2023 11:07:50 -0500 Subject: [PATCH 23/34] chore(deploy-script-support): Improve comment --- packages/deploy-script-support/src/coreProposalBehavior.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index dcbaf28cd25..3c937c91977 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -61,7 +61,7 @@ export const makeCoreProposalBehavior = ({ /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise>} */ const defaultRestoreRef = async bundleRef => { // extract-proposal.js creates these records, and bundleName is - // the name under which the bundle was installed into + // the optional name under which the bundle was installed into // config.bundles const bundleIdP = 'bundleName' in bundleRef From 18902d2c5eade34dbe33dfcf1052b5d4dbf5bfc2 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 15:15:08 -0500 Subject: [PATCH 24/34] =?UTF-8?q?chore(deploy-script-support):=20Avoid=20"?= =?UTF-8?q?make=E2=80=A6"=20names=20for=20non-function=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deploy-script-support/src/coreProposalBehavior.js | 9 +++------ packages/deploy-script-support/src/extract-proposal.js | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 259090f98a1..f678563d568 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -175,20 +175,17 @@ export const makeCoreProposalBehavior = ({ /** * @param {object} inputs - * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, customManifest?: Manifest }>} inputs.makeCoreProposalArgs + * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, customManifest?: Manifest }>} inputs.metadataRecords * @param {typeof import('@endo/far').E} inputs.E */ -export const makeEnactCoreProposalsFromBundleRef = ({ - makeCoreProposalArgs, - E, -}) => { +export const makeEnactCoreProposalsFromBundleRef = ({ metadataRecords, E }) => { /** * @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers * @returns {Promise} */ const enactCoreProposals = async powers => { await Promise.all( - makeCoreProposalArgs.map(async ({ ref, call, customManifest }) => { + metadataRecords.map(async ({ ref, call, customManifest }) => { const coreProposalBehavior = makeCoreProposalBehavior({ manifestBundleRef: ref, getManifestCall: call, diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 976c2a90871..6820cbbba3c 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -240,24 +240,24 @@ export const extractCoreProposalBundles = async ( harden(bundles); // Extract the manifest references and calls. - const makeCPArgs = extracted.map(({ ref, call, customManifest }) => ({ + const metadataRecords = extracted.map(({ ref, call, customManifest }) => ({ ref, call, customManifest, })); - harden(makeCPArgs); + harden(metadataRecords); const code = `\ // This is generated by @agoric/deploy-script-support/src/extract-proposal.js - DO NOT EDIT /* eslint-disable */ -const makeCoreProposalArgs = harden(${stringify(makeCPArgs, true)}); +const metadataRecords = harden(${stringify(metadataRecords, true)}); // Make an enactCoreProposals function and "export" it by way of script completion value. (( makeCoreProposalBehavior = ${makeCoreProposalBehavior}, makeEnactCoreProposals = ${makeEnactCoreProposals}, -) => makeEnactCoreProposals({ makeCoreProposalArgs, E }))(); +) => makeEnactCoreProposals({ metadataRecords, E }))(); `; // console.debug('created bundles from proposals:', coreProposals, bundles); From 579c3f0940316d00dc4897b42bd2556b952ead37 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 23 Nov 2023 11:10:46 -0500 Subject: [PATCH 25/34] chore(deploy-script-support): Clean up logging --- .../deploy-script-support/src/coreProposalBehavior.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 3c937c91977..00c08e689c6 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -88,9 +88,9 @@ export const makeCoreProposalBehavior = ({ } = powers; // Get the on-chain installation containing the manifest and behaviors. - console.info('evaluateBundleCap', { + log('evaluateBundleCap', { manifestBundleRef, - exportedGetManifest: manifestGetterName, + manifestGetterName, vatAdminSvc, }); let bcapP; @@ -112,9 +112,9 @@ export const makeCoreProposalBehavior = ({ const installationNS = await evaluateBundleCap(bundleCap); // Get the manifest and its metadata. - console.error('execute', { - exportedGetManifest: manifestGetterName, - behaviors: Object.keys(installationNS), + log('execute', { + manifestGetterName, + bundleExports: Object.keys(installationNS), }); const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); const { From 04ed28ac253ab1732867db7be93938846f296d36 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 15:27:16 -0500 Subject: [PATCH 26/34] chore(deploy-script-support): Sync code patterns across files --- .../src/extract-proposal.js | 21 +++++++++---------- .../src/writeCoreProposal.js | 10 ++++----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 6820cbbba3c..dc6112a8db2 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -197,21 +197,20 @@ export const extractCoreProposalBundles = async ( harden(proposal), ); - const behaviorSource = pathResolve(initDir, sourceSpec); - const behaviors = await import(behaviorSource); - const [exportedGetManifest, ...manifestArgs] = getManifestCall; - assert( - exportedGetManifest in behaviors, - `behavior ${behaviorSource} missing ${exportedGetManifest}`, + const proposalSource = pathResolve(initDir, sourceSpec); + const proposalNS = await import(proposalSource); + const [manifestGetterName, ...manifestGetterArgs] = getManifestCall; + manifestGetterName in proposalNS || + Fail`proposal ${proposalSource} missing export ${manifestGetterName}`; + const { manifest: customManifest } = await proposalNS[manifestGetterName]( + harden({ restoreRef: () => null }), + ...manifestGetterArgs, ); - const { manifest: customManifest } = await behaviors[ - exportedGetManifest - ](harden({ restoreRef: () => null }), ...manifestArgs); const behaviorBundleHandle = {}; const specEntry = await handleToBundleSpec( behaviorBundleHandle, - behaviorSource, + proposalSource, thisProposalSequence, 'behaviors', ); @@ -220,7 +219,7 @@ export const extractCoreProposalBundles = async ( bundleHandleToAbsolutePaths.set( behaviorBundleHandle, harden({ - source: behaviorSource, + source: proposalSource, }), ); diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 3c75212a8a2..cee6cf47a91 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -51,15 +51,15 @@ export const makeWriteCoreProposal = ( const mergeProposalPermit = async (proposal, additionalPermits) => { const { sourceSpec, - getManifestCall: [exportedGetManifest, ...manifestArgs], + getManifestCall: [manifestGetterName, ...manifestGetterArgs], } = proposal; - const manifestNs = await import(pathResolve(sourceSpec)); + const proposalNS = await import(pathResolve(sourceSpec)); // We only care about the manifest, not any restoreRef calls. - const { manifest } = await manifestNs[exportedGetManifest]( - { restoreRef: x => `restoreRef:${x}` }, - ...manifestArgs, + const { manifest } = await proposalNS[manifestGetterName]( + harden({ restoreRef: x => `restoreRef:${x}` }), + ...manifestGetterArgs, ); const mergedPermits = mergePermits(manifest); From 8f890ab4f3314574cba4712cee64f59b47ece834 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 23 Nov 2023 11:28:11 -0500 Subject: [PATCH 27/34] chore(deploy-script-support): Comment on the scope of `powers` --- .../src/coreProposalBehavior.js | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 00c08e689c6..7cb743ba1c9 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -8,8 +8,14 @@ const t = 'makeCoreProposalBehavior'; * @typedef {*} BootstrapPowers */ -// These permits limit the powers passed to the `behavior` function returned by -// `makeCoreProposalBehavior`. +/** + * These permits are expected to be the minimum powers required by the + * `behavior` function returned from `makeCoreProposalBehavior`. + * They are merged with all of the manifest getter's permits to produce the + * total permits needed by the resulting core proposal (such as might be---and + * generally are---written into a *-permit.json file). + * @see {@link ./writeCoreProposal.js} + */ export const permits = { consume: { agoricNamesAdmin: t, vatAdminSvc: t, zoe: t }, evaluateBundleCap: t, @@ -76,8 +82,13 @@ export const makeCoreProposalBehavior = ({ /** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers */ const behavior = async powers => { - // NOTE: If updating any of these names extracted from `powers`, you must - // change `permits` above to reflect their accessibility. + // 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, @@ -142,6 +153,7 @@ export const makeCoreProposalBehavior = ({ // Evaluate the manifest. return runModuleBehaviors({ + // Remember that `powers` may be arbitrarily broad. allPowers: powers, behaviors: installationNS, manifest: overrideManifest || manifest, From b85acb261d8033efd9a2c56a426dddf22a0d8a8e Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 4 Jan 2024 15:45:56 -0500 Subject: [PATCH 28/34] chore(deploy-script-support): Update assert(cond, X`...`) calls to cond || Fail`...` --- .../deploy-script-support/src/extract-proposal.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index dc6112a8db2..5827c24a899 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -14,7 +14,7 @@ import { * @typedef {string | { module: string, entrypoint: string, args?: Array }} ConfigProposal */ -const { details: X, Fail } = assert; +const { Fail } = assert; const req = createRequire(import.meta.url); @@ -24,8 +24,8 @@ const req = createRequire(import.meta.url); * @typedef {string} FilePath */ const pathResolve = (...paths) => { - const fileName = paths.pop(); - assert(fileName, '>=1 paths required'); + const fileName = /** @type {string} */ (paths.pop()); + fileName || Fail`base name required`; try { return req.resolve(fileName, { paths, @@ -132,11 +132,8 @@ export const extractCoreProposalBundles = async ( absolutePaths.bundle = absoluteBundle; const oldSource = bundleToSource.get(absoluteBundle); if (oldSource) { - assert.equal( - oldSource, - absoluteSrc, - X`${bundlePath} already installed from ${oldSource}, now ${absoluteSrc}`, - ); + oldSource === absoluteSrc || + Fail`${bundlePath} already installed from ${oldSource}, now ${absoluteSrc}`; } else { bundleToSource.set(absoluteBundle, absoluteSrc); } From 78ed7a641bb59eaa7f1daedbdf833b2c99803c5b Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 27 Nov 2023 15:20:22 -0500 Subject: [PATCH 29/34] chore(deploy-script-support): Rename variables for clarity Per @michaelfig review --- .../src/coreProposalBehavior.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index 7cb743ba1c9..6d25bc913b3 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -10,7 +10,7 @@ const t = 'makeCoreProposalBehavior'; /** * These permits are expected to be the minimum powers required by the - * `behavior` function returned from `makeCoreProposalBehavior`. + * `coreProposalBehavior` function returned from `makeCoreProposalBehavior`. * They are merged with all of the manifest getter's permits to produce the * total permits needed by the resulting core proposal (such as might be---and * generally are---written into a *-permit.json file). @@ -81,7 +81,7 @@ export const makeCoreProposalBehavior = ({ }; /** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} powers */ - const behavior = async 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 @@ -120,19 +120,19 @@ export const makeCoreProposalBehavior = ({ } const bundleCap = await bcapP; - const installationNS = await evaluateBundleCap(bundleCap); + const proposalNS = await evaluateBundleCap(bundleCap); // Get the manifest and its metadata. log('execute', { manifestGetterName, - bundleExports: Object.keys(installationNS), + bundleExports: Object.keys(proposalNS), }); const restoreRef = overrideRestoreRef || makeRestoreRef(vatAdminSvc, zoe); const { manifest, options: rawOptions, installations: rawInstallations, - } = await installationNS[manifestGetterName]( + } = await proposalNS[manifestGetterName]( harden({ restoreRef }), ...manifestGetterArgs, ); @@ -155,7 +155,7 @@ export const makeCoreProposalBehavior = ({ return runModuleBehaviors({ // Remember that `powers` may be arbitrarily broad. allPowers: powers, - behaviors: installationNS, + behaviors: proposalNS, manifest: overrideManifest || manifest, makeConfig: (name, _permit) => { log('coreProposal:', name); @@ -164,7 +164,7 @@ export const makeCoreProposalBehavior = ({ }); }; - return behavior; + return coreProposalBehavior; }; export const makeEnactCoreProposalsFromBundleRef = @@ -172,13 +172,13 @@ export const makeEnactCoreProposalsFromBundleRef = async powers => { await Promise.all( makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => { - const subBehavior = makeCoreProposalBehavior({ + const coreProposalBehavior = makeCoreProposalBehavior({ manifestBundleRef: ref, getManifestCall: call, overrideManifest, E, }); - return subBehavior(powers); + return coreProposalBehavior(powers); }), ); }; From 7d56920d176f64bb05810b86933ce66b452c4593 Mon Sep 17 00:00:00 2001 From: Mathieu Hofman <86499+mhofman@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:40:20 -0300 Subject: [PATCH 30/34] feat(cosmic-swingset): add begin block check and transaction (#8432) * feat(cosmic-swingset): add being block check and transaction * fixup! feat(cosmic-swingset): add being block check and transaction --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/cosmic-swingset/src/launch-chain.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/cosmic-swingset/src/launch-chain.js b/packages/cosmic-swingset/src/launch-chain.js index 56a4dfe95c0..ec695710aa9 100644 --- a/packages/cosmic-swingset/src/launch-chain.js +++ b/packages/cosmic-swingset/src/launch-chain.js @@ -787,6 +787,10 @@ export async function launch({ return undefined; } + // Start a block transaction, but without changing state + // for the upcoming begin block check + saveBeginHeight(savedBeginHeight); + controller.writeSlogObject({ type: 'cosmic-swingset-upgrade-start', blockHeight, From 0d6dbbd50e99f9144e9ad5768bd1d8ee5a038616 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Tue, 9 Jan 2024 18:54:42 -0500 Subject: [PATCH 31/34] chore(deploy-script-support): Apply suggestions from code review --- packages/deploy-script-support/src/extract-proposal.js | 7 ++++++- packages/deploy-script-support/src/writeCoreProposal.js | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/deploy-script-support/src/extract-proposal.js b/packages/deploy-script-support/src/extract-proposal.js index 5827c24a899..1fb77e553a2 100644 --- a/packages/deploy-script-support/src/extract-proposal.js +++ b/packages/deploy-script-support/src/extract-proposal.js @@ -250,10 +250,15 @@ export const extractCoreProposalBundles = async ( const metadataRecords = harden(${stringify(metadataRecords, true)}); // Make an enactCoreProposals function and "export" it by way of script completion value. -(( +// It is constructed by an IIFE to ensure the absence of global bindings for +// makeCoreProposalBehavior and makeEnactCoreProposals (the latter referencing the former), +// which may not be necessary but preserves behavior pre-dating +// https://github.com/Agoric/agoric-sdk/pull/8712 . +const enactCoreProposals = (( makeCoreProposalBehavior = ${makeCoreProposalBehavior}, makeEnactCoreProposals = ${makeEnactCoreProposals}, ) => makeEnactCoreProposals({ metadataRecords, E }))(); +enactCoreProposals; `; // console.debug('created bundles from proposals:', coreProposals, bundles); diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index cee6cf47a91..fab7bd3bffe 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -153,6 +153,9 @@ const getManifestCall = harden(${stringify(getManifestCall, true)}); const customManifest = ${stringify(customManifest, true)}; // 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 = (${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, customManifest, E }); behavior; `; From 2a68ca148f637ca88c553b75834496ac6ebea841 Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Thu, 16 Nov 2023 20:31:52 -0800 Subject: [PATCH 32/34] feat(deploy-script-support): Write out bundle file names in machine readable file --- .../src/writeCoreProposal.js | 23 +++++++++++++++++-- packages/internal/src/node/createBundles.js | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index 144ef6bebff..8a489f47384 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -91,6 +91,8 @@ export const makeWriteCoreProposal = ( return ns.default; }; + const bundles = []; + /** * Install an entrypoint. * @@ -103,9 +105,14 @@ export const makeWriteCoreProposal = ( const bundle = getBundle(entrypoint, bundlePath); // Serialise the installations. - mutex = E.when(mutex, () => { + mutex = E.when(mutex, async () => { // console.log('installing', { filePrefix, entrypoint, bundlePath }); - return getBundleSpec(bundle, getBundler, opts); + const spec = await getBundleSpec(bundle, getBundler, opts); + bundles.push({ + entrypoint, + ...spec, + }); + return spec; }); // @ts-expect-error xxx mutex type narrowing return mutex; @@ -162,6 +169,18 @@ const overrideManifest = ${stringify(overrideManifest, true)}; log(`creating ${proposalJsFile}`); await writeFile(proposalJsFile, trimmed); + const plan = { + name: filePrefix, + script: proposalJsFile, + permit: proposalPermitJsonFile, + bundles, + }; + + await writeFile( + `${filePrefix}-plan.json`, + `${JSON.stringify(plan, null, 2)}\n`, + ); + log(`\ You can now run a governance submission command like: agd tx gov submit-proposal swingset-core-eval ${proposalPermitJsonFile} ${proposalJsFile} \\ diff --git a/packages/internal/src/node/createBundles.js b/packages/internal/src/node/createBundles.js index d17d1bb45ea..ecc7d505b73 100644 --- a/packages/internal/src/node/createBundles.js +++ b/packages/internal/src/node/createBundles.js @@ -23,7 +23,7 @@ export const createBundlesFromAbsolute = async sourceBundles => { } const bundle = match[1]; - const args = cacheToArgs.get(cache) || ['--to', cache]; + const args = cacheToArgs.get(cache) || ['--cache-js', cache]; args.push(srcPath, bundle); cacheToArgs.set(cache, args); } From 6a02bcc701e4b842e1c0a3d8518714c357da9b45 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Tue, 9 Jan 2024 18:58:32 -0500 Subject: [PATCH 33/34] chore(deploy-script-support): Lookup the agoricNames installation admin only when necessary --- .../src/coreProposalBehavior.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/deploy-script-support/src/coreProposalBehavior.js b/packages/deploy-script-support/src/coreProposalBehavior.js index f678563d568..02cf5a37843 100644 --- a/packages/deploy-script-support/src/coreProposalBehavior.js +++ b/packages/deploy-script-support/src/coreProposalBehavior.js @@ -149,13 +149,16 @@ export const makeCoreProposalBehavior = ({ ); // Publish the installations for our dependencies. - const installAdmin = E(agoricNamesAdmin).lookupAdmin('installation'); - await Promise.all( - entries(installations || {}).map(([key, value]) => { - produceInstallations[key].resolve(value); - return E(installAdmin).update(key, value); - }), - ); + 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({ From 8ae111d4958f4e32fbf93ca7a810922827d1b886 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 19 Jan 2024 09:16:45 -0800 Subject: [PATCH 34/34] chore(types): InstallEntrypoint --- .../src/endo-pieces-contract.js | 3 +++ packages/deploy-script-support/src/externalTypes.js | 12 ++++++------ .../deploy-script-support/src/getBundlerMaker.js | 1 + .../deploy-script-support/src/writeCoreProposal.js | 2 ++ .../test/unitTests/test-installInPieces.js | 1 + .../inter-protocol/scripts/add-collateral-core.js | 1 + packages/inter-protocol/scripts/init-core.js | 2 ++ packages/vats/scripts/build-game1-start.js | 1 - packages/vats/scripts/build-walletFactory-upgrade.js | 1 - packages/vats/scripts/set-core-proposal-env.js | 2 +- 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/deploy-script-support/src/endo-pieces-contract.js b/packages/deploy-script-support/src/endo-pieces-contract.js index 419b243c133..715000aa415 100644 --- a/packages/deploy-script-support/src/endo-pieces-contract.js +++ b/packages/deploy-script-support/src/endo-pieces-contract.js @@ -18,6 +18,9 @@ export const start = () => { }); }; + /** + * @param {{ zoe: ERef }} opts + */ const makeBundler = ({ zoe }) => { /** @type { Map} */ const nameToContent = new Map(); diff --git a/packages/deploy-script-support/src/externalTypes.js b/packages/deploy-script-support/src/externalTypes.js index 5288582b099..364149da559 100644 --- a/packages/deploy-script-support/src/externalTypes.js +++ b/packages/deploy-script-support/src/externalTypes.js @@ -16,7 +16,7 @@ export {}; */ /** - * @typedef {{ bundleName: string } | { bundleID: string} } ManifestBundleRef + * @typedef {{fileName?: string} & ({ bundleName: string } | { bundleID: string}) } ManifestBundleRef */ /** @@ -26,10 +26,10 @@ export {}; */ /** - * @callback InstallBundle + * @callback InstallEntrypoint * @param {string} srcSpec - * @param {string} bundlePath - * @param {any} [opts] + * @param {string} [bundlePath] + * @param {unknown} [opts] * @returns {Promise} */ @@ -37,8 +37,8 @@ export {}; * @callback ProposalBuilder * @param {{ * publishRef: PublishBundleRef, - * install: InstallBundle, - * wrapInstall?: (f: T) => T } + * install: InstallEntrypoint, + * wrapInstall?: (f: T) => T } * } powers * @param {...any} args * @returns {Promise} diff --git a/packages/deploy-script-support/src/getBundlerMaker.js b/packages/deploy-script-support/src/getBundlerMaker.js index 5e419703ca6..425b49471a9 100644 --- a/packages/deploy-script-support/src/getBundlerMaker.js +++ b/packages/deploy-script-support/src/getBundlerMaker.js @@ -14,6 +14,7 @@ import { E } from '@endo/far'; import url from 'url'; /** @typedef {ReturnType['publicFacet']} BundleMaker */ +/** @typedef {ReturnType} Bundler */ export const makeGetBundlerMaker = (homeP, { lookup, bundleSource }) => diff --git a/packages/deploy-script-support/src/writeCoreProposal.js b/packages/deploy-script-support/src/writeCoreProposal.js index fab7bd3bffe..768ba5dce0c 100644 --- a/packages/deploy-script-support/src/writeCoreProposal.js +++ b/packages/deploy-script-support/src/writeCoreProposal.js @@ -39,6 +39,7 @@ export const makeWriteCoreProposal = ( const { bundleSource, pathResolve } = endowments; let bundlerCache; + /** @returns {import('./getBundlerMaker.js').Bundler} */ const getBundler = () => { if (!bundlerCache) { bundlerCache = E(getBundlerMaker()).makeBundler({ @@ -120,6 +121,7 @@ export const makeWriteCoreProposal = ( // Await a reference then publish to the board. const cmds = []; + /** @param {Promise} refP */ const publishRef = async refP => { const { fileName, ...ref } = await refP; if (fileName) { diff --git a/packages/deploy-script-support/test/unitTests/test-installInPieces.js b/packages/deploy-script-support/test/unitTests/test-installInPieces.js index 35c98459763..08181ce0689 100644 --- a/packages/deploy-script-support/test/unitTests/test-installInPieces.js +++ b/packages/deploy-script-support/test/unitTests/test-installInPieces.js @@ -27,6 +27,7 @@ test('installInPieces', async t => { }, }; + // @ts-expect-error fake Zoe const bundler = E(publicFacet).makeBundler({ zoe }); const installation = await installInPieces(endoPieces, bundler, { diff --git a/packages/inter-protocol/scripts/add-collateral-core.js b/packages/inter-protocol/scripts/add-collateral-core.js index bad11ee1c15..94e2425075b 100644 --- a/packages/inter-protocol/scripts/add-collateral-core.js +++ b/packages/inter-protocol/scripts/add-collateral-core.js @@ -107,6 +107,7 @@ export default async (homeP, endowments) => { await writeCoreProposal('gov-add-collateral', defaultProposalBuilder); await writeCoreProposal('gov-start-psm', opts => + // @ts-expect-error XXX makeInstallCache types psmProposalBuilder({ ...opts, wrapInstall: tool.wrapInstall }), ); }; diff --git a/packages/inter-protocol/scripts/init-core.js b/packages/inter-protocol/scripts/init-core.js index 332ec3d7030..7bf6c282b49 100644 --- a/packages/inter-protocol/scripts/init-core.js +++ b/packages/inter-protocol/scripts/init-core.js @@ -188,9 +188,11 @@ export default async (homeP, endowments) => { }); await Promise.all([ writeCoreProposal('gov-econ-committee', opts => + // @ts-expect-error XXX makeInstallCache types committeeProposalBuilder({ ...opts, wrapInstall: tool.wrapInstall }), ), writeCoreProposal('gov-amm-vaults-etc', opts => + // @ts-expect-error XXX makeInstallCache types mainProposalBuilder({ ...opts, wrapInstall: tool.wrapInstall }), ), ]); diff --git a/packages/vats/scripts/build-game1-start.js b/packages/vats/scripts/build-game1-start.js index fbc64399d01..6b0dfb10917 100644 --- a/packages/vats/scripts/build-game1-start.js +++ b/packages/vats/scripts/build-game1-start.js @@ -27,7 +27,6 @@ export const game1ProposalBuilder = async ({ publishRef, install }) => { }); }; -/** @type {DeployScriptFunction} */ export default async (homeP, endowments) => { const { writeCoreProposal } = await makeHelpers(homeP, endowments); await writeCoreProposal('start-game1', game1ProposalBuilder); diff --git a/packages/vats/scripts/build-walletFactory-upgrade.js b/packages/vats/scripts/build-walletFactory-upgrade.js index c7cfcdcd93d..ca8d566c744 100644 --- a/packages/vats/scripts/build-walletFactory-upgrade.js +++ b/packages/vats/scripts/build-walletFactory-upgrade.js @@ -28,7 +28,6 @@ export const defaultProposalBuilder = async ({ publishRef, install }) => { }); }; -/** @type {DeployScriptFunction} */ export default async (homeP, endowments) => { const { writeCoreProposal } = await makeHelpers(homeP, endowments); await writeCoreProposal('upgrade-walletFactory', defaultProposalBuilder); diff --git a/packages/vats/scripts/set-core-proposal-env.js b/packages/vats/scripts/set-core-proposal-env.js index 5a8f800e4ed..45725cd233a 100755 --- a/packages/vats/scripts/set-core-proposal-env.js +++ b/packages/vats/scripts/set-core-proposal-env.js @@ -10,7 +10,7 @@ if (!spec) { } const vatConfigFile = require.resolve(spec); -const configJson = fs.readFileSync(vatConfigFile); +const configJson = fs.readFileSync(vatConfigFile, 'utf-8'); const config = JSON.parse(configJson); const envs = new Map();