diff --git a/a3p-integration/README.md b/a3p-integration/README.md index 7c30ea352a2f..664746a9c381 100644 --- a/a3p-integration/README.md +++ b/a3p-integration/README.md @@ -38,9 +38,18 @@ yarn test --debug -m "proposal-name" ## Package layering -Proposals are packages under the `/a3p-integration/proposals` folder, and are separate from each other, from the `a3p-integration` test environment, and from the enclosing `agoric-sdk` repository. They run inside the docker image, and cannot access SDK code. The are lower case, and executed in lexical order. - -In the release branches, the end-to-end `a3p-integration` test usually only has a single proposal package named `a:upgrade-NN`, which performs a chain software upgrade proposal to the corresponding upgrade plan. In the `master` branch, there may also be core-eval proposal packages, either before or after the chain software upgrade proposal. +Proposals are packages under the `/a3p-integration/proposals` folder, and are +separate from each other, from the `a3p-integration` test environment, and from +the enclosing `agoric-sdk` repository. They run inside the docker image, and +cannot access SDK code. Their names must be lower case, and they are executed in +lexical order. + +In the release branches, the end-to-end `a3p-integration` test usually only has +a single proposal package named `a:upgrade-NN`, which performs a chain software +upgrade proposal to the corresponding upgrade plan. In the `master` branch, the +next release's changes are staged in `a:upgrade-next`. There may also be +core-eval proposal packages, either before or after the chain software upgrade +proposal. The details of a proposal package are configured through the `agoricProposal` field of its `package.json`. @@ -52,15 +61,20 @@ For a chain software upgrade proposal, the `type` is `"Software Upgrade Proposal - `sdkImageTag` is the docker image tag to use that contains the upgraded chain software. It has a value of `unreleased`, which is the tag for the image that is built from the enclosing `agoric-sdk` repository. - `planName` is the "upgrade name" included in the proposal which must match the value in the upgraded chain software. In the `master` branch its value is `UNRELEASED_UPGRADE`. In the release branches, it's `agoric-upgrade-NN`. -- `upgradeInfo` contains other details passed to the governance proposal. In particular, the info can have a `coreProposal` field which instruct the chain software to run other core proposals besides the one already configured in the chain software's upgrade handler (see `CoreProposalSteps` in `/golang/cosmos/app/app.go`). This field is likely not relevant for release branches. +- `upgradeInfo` contains other details passed to the governance proposal. In + particular, it can have a `coreProposals` field which instructs the chain + software to run other core proposals in addition to the one configured in the + chain software's upgrade handler (see `CoreProposalSteps` in + `/golang/cosmos/app/app.go`). This field is likely not relevant for release + branches. For an example, see `a:upgrade-next` in master. ### Core-eval proposal -The `type` of a core-eval proposal is `"/agoric.swingset.CoreEvalProposal"`, and content is submitted from a `submission` subfolder. +The `type` of a core-eval proposal is `"/agoric.swingset.CoreEvalProposal"`, and content is submitted from a subfolder whose name defaults to `submission`. -If the proposal is planned to be executed after the chain software upgrade, and the source of the proposal is in `agoric-sdk`, it's recommended to not check-in the `submission` content in source control and instead generate it automatically when testing. Since proposals cannot access SDK code, a script can be used to generate the `submission` content. Until there is [native support for build scripts in the `synthetic-chain` tool](https://github.com/Agoric/agoric-3-proposals/issues/87), `a3p-integration`'s `build:submissions` step invokes `/script/generate-a3p-submission.sh` in `agoric-sdk` before starting the upgrade test. +If the proposal is planned to be executed after the chain software upgrade, and the source of the proposal is in `agoric-sdk`, it's recommended to not check-in the `submission` content in source control and instead generate it automatically when testing. Since proposals cannot access SDK code, a script can be used to generate the `submission` content. Until there is [native support for build scripts in the `synthetic-chain` tool](https://github.com/Agoric/agoric-3-proposals/issues/87), `a3p-integration`'s `build:submissions` step invokes `/script/generate-a3p-submissions.sh` in `agoric-sdk` before starting the upgrade test. For core eval proposals executing before the chain software upgrade, the `submission` should be checked in, since bundles built from newer software may not be compatible with older chains. @@ -99,11 +113,109 @@ make -C ../packages/deployment docker-build-sdk Some core-eval proposals `submission` content are generated from the `agoric-sdk` code, and must be rebuilt every time there is a change. The -`scripts/generate-a3p-submission.sh` script contains commands to generate the +`scripts/generate-a3p-submissions.sh` script contains commands to generate the core-eval content and move it to the expected proposal package's submission directory. It is executed as part of `a3p-integration`'s `build:submissions` step. -Each proposal that requires such a build step should add an `sdk-generate` property -in its `agoricProposal` config. +Each proposal that requires such a build step should add an entry to the +`sdk-generate` array in the `agoricProposal` section of `package.json`. + +Submissions that don't need to pass in options or generate references to source +bundles can be written directly in a `foo-submission` subdirectory of the +proposal. These would incude a .js or .tjs file, accompanied by a similarly-named +-permit.json file that can contain just `true`, or a complete permission manifest. +The submission should return the script, which can take BootstrapPowers as a +parameter. + +If the submission does require a bundle reference, or other options to be +provided, it should be written as two parts. The proposal usually goes in +`.../vats/proposals`, and the script in `.../builders/scripts/vats`. + +### Proposal + +The proposal is called with `(powers, options)` available. The manifest +detailing the powers that will be used is usually in the same file, and +conventionally named `getManifestForFoo`. The manifest needs to have a unique +name, since it will be referenced by name from the script. The usual format is +```js +export const foo = async ( + { + consume: { + ... + }, + brands: { + ... + } + }, + options, +) => { + // do the things using powers and options +}; + +export const getManifestForFoo = (powers, options) => { + manifest: { + [foo.name]: { + consume: { + ... + }, + options, +)}; +``` + +### Script + +The script describes how to build the core proposal for `a3p-integration`. For +`agoric-3-proposals` and uploading to the chain, the script is named in +`CoreProposalSteps` in `app.go`, and its `defaultProposalBuilder` is invoked +directly. The submission directories in a3p-integration are generated by the +`generate-a3p-submissions.sh` script, which reads instructions from +`agoricProposal.sdk-generate` in `package.json`. That field contains a list of +strings, each of which describes a single submission. If there is only one +submission, it can use the default directory name `submission` by specifying +only the name of the script file in `builders/scripts/vars`: +```json +"sdk-generate": ["test-localchain"], +``` +If there are multiple submissions, each entry has to specify the script name and +a distinct directory name. +```json +"sdk-generate": [ + "probe-zcf-bundle probe-submission", + "updatePriceFeeds priceFeed-submission", + "add-auction newAuction-submission" +], +``` + +Script files should export `defaultProposalBuilder` and a `default` function +that invokes `writeCoreProposal` one or more times to generate sets of files +describing the proposal. + +```js +export const defaultProposalBuilder = ({ publishRef, install }) => { + return harden({ + sourceSpec: '@agoric/vats/src/proposals/foo.js', + getManifestCall: [ + 'getManifestForFoo', + { + fooRef: publishRef(install('@agoric/...')), + ...otherParams, + }, + ], + }); +}; +` +export default async (homeP, endowments) => { + const { writeCoreProposal } = await makeHelpers(homeP, endowments); + await writeCoreProposal('proposalName', defaultProposalBuilder); +}; +``` + +The first element of `getManifestCall` is interpreted as the name of a proposal. +`fooRef` (i.e. `publishRef(install())`) is built from sources under +`../packages`, and passed as a `bundleRef`, which contains a `bundleID` suitable +for passing to Zoe or `vatAdminService`. + +The second element of `getManifestCall` produces the `options` argument passed +to the proposal. (`foo` in the example above).`` ## Building synthetic-chain images