-
Notifications
You must be signed in to change notification settings - Fork 215
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cosmic-swingset): introduce GovernorExecutor #10725
refs: #10725 Initial set of changes to get auctioneer governors terminated.
- Loading branch information
1 parent
f223be1
commit 5c0ac62
Showing
3 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
packages/builders/scripts/vats/upgrade-governor-instance.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/** | ||
* @file Upgrade price-feed governor instances such as emerynet v664. | ||
* Functions as both an off-chain builder and an on-chain core-eval. | ||
*/ | ||
|
||
/// <reference types="@agoric/vats/src/core/types-ambient"/> | ||
|
||
import { E } from '@endo/far'; | ||
|
||
const SELF = '@agoric/builders/scripts/vats/terminate-governor-instance.js'; | ||
const USAGE = `Usage: agoric run /path/to/terminate-governor-instance.js \\ | ||
<$governorInstanceHandleBoardID:$instanceKitLabel>...`; | ||
|
||
const repr = val => | ||
typeof val === 'string' || (typeof val === 'object' && val !== null) | ||
? JSON.stringify(val) | ||
: String(val); | ||
const defaultMakeError = (strings, ...subs) => | ||
Error( | ||
strings.map((s, i) => `${i === 0 ? '' : repr(subs[i - 1])}${s}`).join(''), | ||
); | ||
const makeUsageError = (strings, ...subs) => { | ||
const err = defaultMakeError(strings, ...subs); | ||
console.error(err.message); | ||
console.error(USAGE); | ||
return err; | ||
}; | ||
|
||
const rtarget = /^(?<boardID>board[0-9]+):(?<instanceKitLabel>.+)$/; | ||
/** | ||
* @param {string[]} args | ||
* @param {(strings: TemplateStringsArray | string[], ...subs: unknown[]) => Error} [makeError] | ||
* @returns {Array<{boardID: string, instanceKitLabel: string}>} | ||
*/ | ||
const parseTargets = (args = [], makeError = defaultMakeError) => { | ||
if (!Array.isArray(args)) throw makeError`invalid targets: ${args}`; | ||
/** @type {Array<{boardID: string, instanceKitLabel: string}>} */ | ||
const targets = []; | ||
const badTargets = []; | ||
for (const arg of args) { | ||
const m = typeof arg === 'string' && arg.match(rtarget); | ||
if (!m) { | ||
badTargets.push(arg); | ||
} else { | ||
// @ts-expect-error cast | ||
targets.push(m.groups); | ||
} | ||
} | ||
if (badTargets.length !== 0) { | ||
throw makeError`malformed target(s): ${badTargets}`; | ||
} else if (targets.length === 0) { | ||
throw makeError`no target(s)`; | ||
} | ||
return targets; | ||
}; | ||
|
||
/** | ||
* @param {BootstrapPowers} powers | ||
* @param {{ options: { governorExecutorBundle: any, targetSpecifiers: string[] } }} config | ||
*/ | ||
export const upgradeGovernors = async ( | ||
{ consume: { board, governedContractKits } }, | ||
{ options: { governorExecutorBundle, targetSpecifiers } }, | ||
) => { | ||
const { Fail, quote: q } = assert; | ||
const targets = parseTargets(targetSpecifiers, Fail); | ||
const doneP = Promise.allSettled( | ||
targets.map(async ({ boardID, instanceKitLabel }) => { | ||
const logLabel = [boardID, instanceKitLabel]; | ||
const contractInstanceHandle = await E(board).getValue(boardID); | ||
const instanceKit = await E(governedContractKits).get( | ||
// @ts-expect-error TS2345 Property '[tag]' is missing | ||
contractInstanceHandle, | ||
); | ||
console.log( | ||
`${q(logLabel)} alleged governor contract instance kit`, | ||
instanceKit, | ||
); | ||
const { label, governorAdminFacet, adminFacet } = instanceKit; | ||
label === instanceKitLabel || | ||
Fail`${q(logLabel)} unexpected instanceKit label, got ${label} but wanted ${q(instanceKitLabel)}`; | ||
(adminFacet && adminFacet !== governorAdminFacet) || | ||
Fail`${q(logLabel)} instanceKit adminFacet should have been present and different from governorAdminFacet but was ${adminFacet}`; | ||
const reason = harden(Error(`core-eval terminating ${label} governor`)); | ||
await E(governorAdminFacet).upgradeContract(governorExecutorBundle, undefined); | ||
console.log(`${q(logLabel)} terminated governor`); | ||
}), | ||
); | ||
const results = await doneP; | ||
const problems = targets.flatMap(({ boardID, instanceKitLabel }, i) => { | ||
if (results[i].status === 'fulfilled') return []; | ||
return [[boardID, instanceKitLabel, results[i].reason]]; | ||
}); | ||
if (problems.length !== 0) { | ||
console.error('governor termination(s) failed', problems); | ||
Fail`governor termination(s) failed: ${problems}`; | ||
} | ||
}; | ||
harden(upgradeGovernors); | ||
|
||
/* | ||
export const getManifest = (_powers, targetSpecifiers) => { | ||
parseTargets(targetSpecifiers); | ||
return { | ||
manifest: { | ||
[upgradeGovernors.name]: { | ||
consume: { board: true, governedContractKits: true }, | ||
}, | ||
}, | ||
// Provide `terminateGovernors` a second argument like | ||
// `{ options: { targetSpecifiers } }`. | ||
options: { targetSpecifiers }, | ||
}; | ||
}; | ||
*/ | ||
|
||
const uG = 'upgradeGovernors'; | ||
/** | ||
* Return the manifest, installations, and options for upgrading Vaults. | ||
* | ||
* @param {object} utils | ||
* @param {any} utils.restoreRef | ||
* @param {any} vaultUpgradeOptions | ||
*/ | ||
export const getManifest = async ( | ||
{ restoreRef }, | ||
{ bundleRef, targetSpecifiers }, | ||
) => { | ||
return { | ||
manifest: { | ||
[upgradeGovernors.name]: { | ||
consume: { | ||
board: uG, | ||
zoe: uG, | ||
governedContractKits: uG, | ||
}, | ||
}, | ||
}, | ||
installations: { governorExecutor: restoreRef(bundleRef) }, // do we need installations ??? | ||
options: { governorExecutorBundle: bundleRef, targetSpecifiers }, | ||
}; | ||
}; | ||
|
||
/* @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ | ||
/* | ||
export const defaultProposalBuilder = async (_utils, targetSpecifiers) => { | ||
parseTargets(targetSpecifiers); | ||
return harden({ | ||
sourceSpec: SELF, | ||
getManifestCall: ['getManifest', targetSpecifiers], | ||
}); | ||
};*/ | ||
|
||
/* @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ | ||
/* | ||
export default async (homeP, endowments) => { | ||
const { scriptArgs } = endowments; | ||
parseTargets(scriptArgs, makeUsageError); | ||
const dspModule = await import('@agoric/deploy-script-support'); | ||
const { makeHelpers } = dspModule; | ||
const { writeCoreEval } = await makeHelpers(homeP, endowments); | ||
await writeCoreEval(upgradeGovernors.name, utils => | ||
defaultProposalBuilder(utils, scriptArgs), | ||
); | ||
}; | ||
*/ | ||
// import { makeHelpers } from '@agoric/deploy-script-support'; | ||
|
||
/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ | ||
export const defaultProposalBuilder = async ({ publishRef, install }, targetSpecifiers) => { | ||
parseTargets(targetSpecifiers); | ||
return harden({ | ||
sourceSpec: SELF, | ||
getManifestCall: [ | ||
getManifest.name, | ||
{ | ||
bundleRef: publishRef( | ||
install( | ||
'@agoric/governance/bundles/contractGovernorExecutor.js', | ||
), | ||
), | ||
targetSpecifiers, | ||
}, | ||
], | ||
}); | ||
} | ||
|
||
/* @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ | ||
/* | ||
export default async (homeP, endowments) => { | ||
const { writeCoreEval } = await makeHelpers(homeP, endowments); | ||
await writeCoreEval('upgrade-governor-instance', defaultProposalBuilder); | ||
}; | ||
*/ | ||
|
||
/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ | ||
export default async (homeP, endowments) => { | ||
const { scriptArgs } = endowments; | ||
parseTargets(scriptArgs, makeUsageError); | ||
const dspModule = await import('@agoric/deploy-script-support'); | ||
const { makeHelpers } = dspModule; | ||
const { writeCoreEval } = await makeHelpers(homeP, endowments); | ||
await writeCoreEval(upgradeGovernors.name, utils => | ||
defaultProposalBuilder(utils, scriptArgs), | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { E } from '@endo/eventual-send'; | ||
import { makeTracer } from '@agoric/internal'; | ||
|
||
const trace = makeTracer('CGExec', false); | ||
|
||
/** @type {ContractMeta} */ | ||
export const meta = { | ||
upgradability: 'canUpgrade', | ||
}; | ||
harden(meta); | ||
|
||
/** | ||
* Start an instance of a governor, governing a "governed" contract specified in terms. | ||
* | ||
* @param {ZCF<{}>} zcf | ||
* @param {{}} _privateArgs | ||
* @param {import('@agoric/vat-data').Baggage} baggage | ||
*/ | ||
export const start = async (zcf, _privateArgs, baggage) => { | ||
trace('start'); | ||
const contractInstanceAdminFacet = baggage.get('creatorFacet'); | ||
const terminationData = harden(Error(`termination of contract by executor governor`)); | ||
await E(contractInstanceAdminFacet).terminateContract(terminationData); | ||
zcf.shutdown(`self-termination of executor governor`); | ||
}; | ||
harden(start); |