@agoric/deploy-script-support 0.9.7-pismo-dev-0d5327f.0 → 0.10.1-dev-bf4b59f.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.10.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/deploy-script-support@0.9.4...@agoric/deploy-script-support@0.10.0) (2023-05-19)
7
+
8
+
9
+ ### Features
10
+
11
+ * **core-proposals:** use bundle hash for label ([2eec093](https://github.com/Agoric/agoric-sdk/commit/2eec0939bd87bfcc48634ab75e2ba830cdb321e3))
12
+ * **deploy-script-support:** Publish bundles to chain if possible ([e8209da](https://github.com/Agoric/agoric-sdk/commit/e8209daec69fc6fd60f5d865cf29271eb106a995))
13
+ * **deploy-script-support:** reenable for `agoric run init-core.js` without `ag-solo` ([2b2bc96](https://github.com/Agoric/agoric-sdk/commit/2b2bc96780b00d9c964dba6e6c5de36acd4a83c6))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **deploy-script-support:** avoid pulling in notifiers ([#7522](https://github.com/Agoric/agoric-sdk/issues/7522)) ([c73675d](https://github.com/Agoric/agoric-sdk/commit/c73675dad025b6600f0eafe9f8e768086e50b626))
19
+ * **deploy-script-support:** update permits for `vatAdminSvc` ([73fef25](https://github.com/Agoric/agoric-sdk/commit/73fef256ab9abda1bda7e0619e8eee08c19f8883))
20
+ * avoid using top-level `require` ([57ca2db](https://github.com/Agoric/agoric-sdk/commit/57ca2dbfbadb373f97d43b2fb4e90302c9149976))
21
+ * change manifestInstallRef to manifestBundleRef ([4b87694](https://github.com/Agoric/agoric-sdk/commit/4b8769494eec1ce6bb5beda295389e8b982a9f37))
22
+ * remove unused overridded restoreRef, fix default version ([7f1cd48](https://github.com/Agoric/agoric-sdk/commit/7f1cd488e2aa7f89473b2187016f7f0dcbc989e8))
23
+ * rename makeEnactCoreProposalsFromBundleName to ..BundleRef ([7403f06](https://github.com/Agoric/agoric-sdk/commit/7403f06f58f0f50ecd154ad076a0a82317f3018b))
24
+ * replace unsafe then with E.when ([#6684](https://github.com/Agoric/agoric-sdk/issues/6684)) ([d7a749e](https://github.com/Agoric/agoric-sdk/commit/d7a749eec4ddec9ba39bbc65434f03ec113cae7c))
25
+ * replace zoe.install with zoe.installBundleID ([8a91b1b](https://github.com/Agoric/agoric-sdk/commit/8a91b1b06bf1a62c08156e595cf46f5194f73337)), closes [#6826](https://github.com/Agoric/agoric-sdk/issues/6826)
26
+ * **deploy-script-support:** Use versioned bundleSource ([41af48e](https://github.com/Agoric/agoric-sdk/commit/41af48e0d44e0615a53d5e3fe9f019895a58f96d))
27
+
28
+
29
+
6
30
  ### [0.9.6](https://github.com/Agoric/agoric-sdk/compare/@agoric/deploy-script-support@0.9.5...@agoric/deploy-script-support@0.9.6) (2023-02-17)
7
31
 
8
32
  **Note:** Version bump only for package @agoric/deploy-script-support
package/exported.js CHANGED
@@ -1,4 +1,3 @@
1
1
  import '@endo/bundle-source/exported.js';
2
- import '@agoric/vats/exported.js';
3
2
 
4
3
  import './src/externalTypes.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/deploy-script-support",
3
- "version": "0.9.7-pismo-dev-0d5327f.0+0d5327f",
3
+ "version": "0.10.1-dev-bf4b59f.0+bf4b59f",
4
4
  "description": "Helpers and other support for writing deploy scripts",
5
5
  "type": "module",
6
6
  "main": "src/helpers.js",
@@ -13,7 +13,7 @@
13
13
  "test:xs": "exit 0",
14
14
  "lint-fix": "yarn lint:eslint --fix",
15
15
  "lint:eslint": "eslint .",
16
- "lint:types": "tsc --maxNodeModuleJsDepth 5 -p jsconfig.json",
16
+ "lint:types": "tsc -p jsconfig.json",
17
17
  "lint": "run-s --continue-on-error lint:*"
18
18
  },
19
19
  "repository": {
@@ -34,25 +34,26 @@
34
34
  },
35
35
  "homepage": "https://github.com/Agoric/agoric-sdk#readme",
36
36
  "dependencies": {
37
- "@agoric/assert": "0.5.2-pismo-dev-0d5327f.0+0d5327f",
38
- "@agoric/ertp": "0.15.6-pismo-dev-0d5327f.0+0d5327f",
39
- "@agoric/import-manager": "0.3.9-pismo-dev-0d5327f.0+0d5327f",
40
- "@agoric/nat": "^4.1.0",
41
- "@agoric/notifier": "0.5.2-pismo-dev-0d5327f.0+0d5327f",
42
- "@agoric/store": "0.8.6-pismo-dev-0d5327f.0+0d5327f",
43
- "@agoric/vats": "0.13.3-pismo-dev-0d5327f.0+0d5327f",
44
- "@agoric/zoe": "0.25.6-pismo-dev-0d5327f.0+0d5327f",
45
- "@endo/base64": "^0.2.27",
46
- "@endo/bundle-source": "^2.3.1",
47
- "@endo/far": "^0.2.11",
48
- "@endo/marshal": "^0.7.5",
49
- "@endo/promise-kit": "^0.2.49",
50
- "@endo/zip": "^0.2.27"
37
+ "@agoric/assert": "0.6.1-dev-bf4b59f.0+bf4b59f",
38
+ "@agoric/ertp": "0.16.1-dev-bf4b59f.0+bf4b59f",
39
+ "@agoric/import-manager": "0.3.10-dev-bf4b59f.0+bf4b59f",
40
+ "@agoric/internal": "0.3.1-dev-bf4b59f.0+bf4b59f",
41
+ "@agoric/notifier": "0.6.1-dev-bf4b59f.0+bf4b59f",
42
+ "@agoric/store": "0.9.1-dev-bf4b59f.0+bf4b59f",
43
+ "@agoric/zoe": "0.26.1-dev-bf4b59f.0+bf4b59f",
44
+ "@endo/base64": "^0.2.31",
45
+ "@endo/bundle-source": "^2.5.1",
46
+ "@endo/far": "^0.2.18",
47
+ "@endo/marshal": "^0.8.5",
48
+ "@endo/nat": "^4.1.27",
49
+ "@endo/promise-kit": "^0.2.56",
50
+ "@endo/zip": "^0.2.31"
51
51
  },
52
52
  "devDependencies": {
53
- "@agoric/swingset-vat": "0.31.1-pismo-dev-0d5327f.0+0d5327f",
54
- "ava": "^4.3.1",
55
- "import-meta-resolve": "^1.1.1"
53
+ "@agoric/vats": "0.14.1-dev-bf4b59f.0+bf4b59f",
54
+ "@endo/init": "^0.5.56",
55
+ "ava": "^5.2.0",
56
+ "import-meta-resolve": "^2.2.1"
56
57
  },
57
58
  "files": [
58
59
  "src",
@@ -67,5 +68,5 @@
67
68
  "publishConfig": {
68
69
  "access": "public"
69
70
  },
70
- "gitHead": "0d5327f87310cf523834853b0546d0e217f37009"
71
+ "gitHead": "bf4b59f2128aca73d786429c6ef4a7c9cdfb6700"
71
72
  }
@@ -1,12 +1,14 @@
1
1
  // @ts-check
2
- import { assert, details as X } from '@agoric/assert';
2
+ import { Fail } from '@agoric/assert';
3
3
  import { E } from '@endo/far';
4
4
 
5
- /** @type {AssertOfferResult} */
5
+ /**
6
+ * @param {ERef<UserSeat>} seat
7
+ * @param {string} expectedOfferResult
8
+ * @returns {Promise<void>}
9
+ */
6
10
  export const assertOfferResult = async (seat, expectedOfferResult) => {
7
11
  const actualOfferResult = await E(seat).getOfferResult();
8
12
  actualOfferResult === expectedOfferResult ||
9
- assert.fail(
10
- X`offerResult (${actualOfferResult}) did not equal expected: ${expectedOfferResult}`,
11
- );
13
+ Fail`offerResult (${actualOfferResult}) did not equal expected: ${expectedOfferResult}`;
12
14
  };
@@ -0,0 +1,32 @@
1
+ const { Fail } = assert;
2
+
3
+ /**
4
+ * @param {string} cacheDir
5
+ * @param {{ now: typeof Date.now, fs: import('fs').promises, pathResolve: typeof import('path').resolve }} param1
6
+ */
7
+ export const makeCacheAndGetBundleSpec =
8
+ (cacheDir, { now, fs, pathResolve }) =>
9
+ async bundleP => {
10
+ const bundle = await bundleP;
11
+ const { endoZipBase64Sha512: hash } = bundle;
12
+
13
+ typeof hash === 'string' || Fail`bundle hash ${hash} must be a string`;
14
+ const bundleID = `b1-${hash}`;
15
+ const cacheFile = pathResolve(cacheDir, `${bundleID}.json`);
16
+
17
+ await fs.mkdir(cacheDir, { recursive: true });
18
+ try {
19
+ await fs.stat(cacheFile);
20
+ } catch (e) {
21
+ if (e.code !== 'ENOENT') {
22
+ throw e;
23
+ }
24
+ // FIXME: We could take a hard dependency on `tmp` here, but is it worth it?
25
+ const tmpFile = `${cacheFile}.${now()}`;
26
+ await fs.writeFile(tmpFile, JSON.stringify(bundle, null, 2), {
27
+ flag: 'wx',
28
+ });
29
+ await fs.rename(tmpFile, cacheFile);
30
+ }
31
+ return harden({ bundleID, fileName: cacheFile });
32
+ };
package/src/code-gen.js CHANGED
@@ -1,8 +1,5 @@
1
1
  // @ts-check
2
- import { makeMarshal } from '@endo/marshal';
3
- import { decodeToJustin } from '@endo/marshal/src/marshal-justin.js';
4
-
5
- export { deeplyFulfilled } from '@endo/marshal';
2
+ import { makeMarshal, decodeToJustin } from '@endo/marshal';
6
3
 
7
4
  const { keys, values, fromEntries } = Object;
8
5
 
@@ -1,8 +1,17 @@
1
+ // @ts-check
1
2
  const t = 'makeCoreProposalBehavior';
2
3
 
4
+ /**
5
+ * TODO import these from @agoric/vats when the types are better managed
6
+ *
7
+ * @typedef {*} ChainBootstrapSpace
8
+ * @typedef {*} BootstrapPowers
9
+ */
10
+
11
+ // These permits apply to `allPowers` in `behavior` below.
3
12
  export const permits = {
4
- consume: { board: t, agoricNamesAdmin: t },
5
- evaluateInstallation: t,
13
+ consume: { agoricNamesAdmin: t, vatAdminSvc: t, zoe: t },
14
+ evaluateBundleCap: t,
6
15
  installation: { produce: t },
7
16
  modules: { utils: { runModuleBehaviors: t } },
8
17
  };
@@ -15,7 +24,7 @@ export const permits = {
15
24
  * definitions.
16
25
  *
17
26
  * @param {object} opts
18
- * @param {string} opts.manifestInstallRef
27
+ * @param {{ bundleName: string } | { bundleID: string }} opts.manifestBundleRef
19
28
  * @param {[string, ...unknown[]]} opts.getManifestCall
20
29
  * @param {Record<string, Record<string, unknown>>} [opts.overrideManifest]
21
30
  * @param {typeof import('@endo/far').E} opts.E
@@ -24,7 +33,7 @@ export const permits = {
24
33
  * @returns {(vatPowers: unknown) => Promise<unknown>}
25
34
  */
26
35
  export const makeCoreProposalBehavior = ({
27
- manifestInstallRef,
36
+ manifestBundleRef,
28
37
  getManifestCall,
29
38
  overrideManifest,
30
39
  E,
@@ -47,10 +56,13 @@ export const makeCoreProposalBehavior = ({
47
56
  return fromEntries(ents);
48
57
  };
49
58
 
59
+ /** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} allPowers */
50
60
  const behavior = async allPowers => {
61
+ // NOTE: If updating any of these names extracted from `allPowers`, you must
62
+ // change `permits` above to reflect their accessibility.
51
63
  const {
52
- consume: { board, agoricNamesAdmin },
53
- evaluateInstallation,
64
+ consume: { vatAdminSvc, zoe, agoricNamesAdmin },
65
+ evaluateBundleCap,
54
66
  installation: { produce: produceInstallations },
55
67
  modules: {
56
68
  utils: { runModuleBehaviors },
@@ -58,25 +70,44 @@ export const makeCoreProposalBehavior = ({
58
70
  } = allPowers;
59
71
  const [exportedGetManifest, ...manifestArgs] = getManifestCall;
60
72
 
61
- const restoreRef = overrideRestoreRef || (x => E(board).getValue(x));
73
+ const defaultRestoreRef = async ref => {
74
+ // extract-proposal.js creates these records, and bundleName is
75
+ // the name under which the bundle was installed into
76
+ // config.bundles
77
+ const p = ref.bundleName
78
+ ? E(vatAdminSvc).getBundleIDByName(ref.bundleName)
79
+ : ref.bundleID;
80
+ const bundleID = await p;
81
+ const label = bundleID.slice(0, 8);
82
+ return E(zoe).installBundleID(bundleID, label);
83
+ };
84
+ const restoreRef = overrideRestoreRef || defaultRestoreRef;
62
85
 
63
86
  // Get the on-chain installation containing the manifest and behaviors.
64
- console.info('restoreRef, evaluateInstallation', {
65
- manifestInstallRef,
87
+ console.info('evaluateBundleCap', {
88
+ manifestBundleRef,
66
89
  exportedGetManifest,
90
+ vatAdminSvc,
67
91
  });
68
- const manifestInstallation = await restoreRef(manifestInstallRef);
69
- const behaviors = await evaluateInstallation(manifestInstallation);
92
+ let bcapP;
93
+ if ('bundleName' in manifestBundleRef) {
94
+ bcapP = E(vatAdminSvc).getNamedBundleCap(manifestBundleRef.bundleName);
95
+ } else {
96
+ bcapP = E(vatAdminSvc).getBundleCap(manifestBundleRef.bundleID);
97
+ }
98
+ const bundleCap = await bcapP;
99
+
100
+ const manifestNS = await evaluateBundleCap(bundleCap);
70
101
 
71
102
  console.error('execute', {
72
103
  exportedGetManifest,
73
- behaviors: Object.keys(behaviors),
104
+ behaviors: Object.keys(manifestNS),
74
105
  });
75
106
  const {
76
107
  manifest,
77
108
  options: rawOptions,
78
109
  installations: rawInstallations,
79
- } = await behaviors[exportedGetManifest](
110
+ } = await manifestNS[exportedGetManifest](
80
111
  harden({ restoreRef }),
81
112
  ...manifestArgs,
82
113
  );
@@ -98,7 +129,7 @@ export const makeCoreProposalBehavior = ({
98
129
  // Evaluate the manifest for our behaviors.
99
130
  return runModuleBehaviors({
100
131
  allPowers,
101
- behaviors,
132
+ behaviors: manifestNS,
102
133
  manifest: overrideManifest || manifest,
103
134
  makeConfig: (name, _permit) => {
104
135
  log('coreProposal:', name);
@@ -111,30 +142,16 @@ export const makeCoreProposalBehavior = ({
111
142
  return behavior;
112
143
  };
113
144
 
114
- export const makeEnactCoreProposalsFromBundleCap =
145
+ export const makeEnactCoreProposalsFromBundleRef =
115
146
  ({ makeCoreProposalArgs, E }) =>
116
147
  async allPowers => {
117
- const {
118
- vatPowers: { D },
119
- devices: { vatAdmin },
120
- consume: { zoe },
121
- } = allPowers;
122
- const restoreRef = async ref => {
123
- const { bundleID } = ref;
124
- const bundleCap = D(vatAdmin).getNamedBundleCap(bundleID);
125
- const bundle = D(bundleCap).getBundle();
126
- const install = await E(zoe).install(bundle);
127
- return install;
128
- };
129
-
130
148
  await Promise.all(
131
149
  makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => {
132
150
  const subBehavior = makeCoreProposalBehavior({
133
- manifestInstallRef: ref,
151
+ manifestBundleRef: ref,
134
152
  getManifestCall: call,
135
153
  overrideManifest,
136
154
  E,
137
- restoreRef,
138
155
  });
139
156
  return subBehavior(allPowers);
140
157
  }),
@@ -1,13 +1,14 @@
1
1
  // @ts-check
2
-
3
2
  import { E } from '@endo/far';
4
3
 
5
4
  /**
6
5
  * @param {ERef<Purse>} zoeInvitationPurse
7
- * @returns {DepositInvitation}
8
6
  */
9
7
  export const makeDepositInvitation = zoeInvitationPurse => {
10
- /** @type {DepositInvitation} */
8
+ /**
9
+ * @param {ERef<Invitation>} invitationP
10
+ * @returns {Promise<InvitationDetails>}
11
+ */
11
12
  const depositInvitation = async invitationP => {
12
13
  const invitation = await invitationP;
13
14
  // Deposit returns the amount deposited
@@ -3,7 +3,7 @@ import { E, Far } from '@endo/far';
3
3
  import { encodeBase64, decodeBase64 } from '@endo/base64';
4
4
  import { ZipWriter } from '@endo/zip';
5
5
 
6
- const { details: X, quote: q } = assert;
6
+ const { Fail, quote: q } = assert;
7
7
 
8
8
  export const start = () => {
9
9
  /** @type { Map<string, [string, Uint8Array]>} */
@@ -45,7 +45,9 @@ export const start = () => {
45
45
  */
46
46
  addByRef: (name, hash) => {
47
47
  const entry = hashToEntry.get(hash);
48
- assert(entry, X`hash not found: ${q(hash)}`);
48
+ if (!entry) {
49
+ throw Fail`hash not found: ${q(hash)}`;
50
+ }
49
51
  const [_n, content] = entry;
50
52
  nameToContent.set(name, [hash, content]);
51
53
  },
@@ -1,66 +1,46 @@
1
- /**
2
- * @callback InstallSaveAndPublish
3
- * @param {string} resolvedPath
4
- * @param {Petname} contractPetname
5
- * @returns {{ installation: Installation, id: string}}
6
- */
7
-
8
- /**
9
- * @typedef {object} StartInstanceResultWithDetailsNoInvitation
10
- * @property {any} creatorFacet
11
- * @property {any} publicFacet
12
- * @property {Instance} instance
13
- * @property {InvitationDetails} creatorInvitationDetails
14
- * @property {AdminFacet} adminFacet
15
- */
16
-
17
- /**
18
- * @typedef {object} OfferHelperConfig
19
- * @property {ERef<Invitation>=} invitation
20
- * @property {Partial<InvitationDetails>=} partialInvitationDetails
21
- * @property {Proposal} proposal
22
- * @property {Record<Keyword, Petname>} paymentsWithPursePetnames
23
- * @property {Record<Keyword, Petname>} payoutPursePetnames
24
- */
1
+ // @ts-check
2
+ export {};
25
3
 
4
+ // TODO move this type somewhere better
26
5
  /**
27
- * @callback OfferHelper
28
- * @param {OfferHelperConfig} config
29
- * @returns {{seat: Promise<UserSeat>, deposited:
30
- * Promise<Array<Promise<Amount>>>, invitationDetails:
31
- * InvitationDetails}}
6
+ * @typedef {string | string[]} Petname A petname can either be a plain string
7
+ * or a path for which the first element is a petname for the origin, and the
8
+ * rest of the elements are a snapshot of the names that were first given by that
9
+ * origin. We are migrating away from using plain strings, for consistency.
32
10
  */
33
11
 
34
12
  /**
35
- * @callback FindInvitationAmount
36
- * @param {Record<string, any>} invitationDetailsCriteria
37
- * @returns {Amount} invitationAmount
13
+ * @typedef ProposalResult
14
+ * @property {string} sourceSpec
15
+ * @property {[exportedGetManifest: string, ...manifestArgs: any[]]} getManifestCall
38
16
  */
39
17
 
40
18
  /**
41
- * @callback DepositInvitation
42
- * @param {ERef<Invitation>} invitationP
43
- * @returns {InvitationDetails}
19
+ * @typedef BundleHandle
20
+ * @property {string} [bundleName]
44
21
  */
45
22
 
46
23
  /**
47
- * @callback SaveIssuerHelper
48
- * @param {ERef<Issuer>} issuer
49
- * @param {Petname} brandPetname
50
- * @param {Petname} pursePetname
51
- * @returns {Promise<Petname>}
24
+ * @callback PublishBundleRef
25
+ * @param {ERef<BundleHandle>} bundle
26
+ * @returns {Promise<BundleHandle>}
52
27
  */
53
28
 
54
29
  /**
55
- * @callback AssertOfferResult
56
- * @param {ERef<UserSeat>} seat
57
- * @param {string} expectedOfferResult
58
- * @returns {Promise<void>}
30
+ * @callback InstallBundle
31
+ * @param {string} srcSpec
32
+ * @param {string} bundlePath
33
+ * @param {any} [opts]
34
+ * @returns {BundleHandle}
59
35
  */
60
36
 
61
37
  /**
62
- * @typedef {string | string[]} Petname A petname can either be a plain string
63
- * or a path for which the first element is a petname for the origin, and the
64
- * rest of the elements are a snapshot of the names that were first given by that
65
- * origin. We are migrating away from using plain strings, for consistency.
38
+ * @callback ProposalBuilder
39
+ * @param {{
40
+ * publishRef: PublishBundleRef,
41
+ * install: InstallBundle,
42
+ * wrapInstall?: <T>(f: T) => T }
43
+ * } powers
44
+ * @param {...any} args
45
+ * @returns {Promise<ProposalResult>}
66
46
  */
@@ -1,17 +1,22 @@
1
1
  // @ts-check
2
+ import { deeplyFulfilledObject } from '@agoric/internal';
2
3
  import fs from 'fs';
3
4
  import { createRequire } from 'module';
4
5
  import path from 'path';
5
6
 
6
- import { deeplyFulfilled, defangAndTrim, stringify } from './code-gen.js';
7
+ import { defangAndTrim, stringify } from './code-gen.js';
7
8
  import {
8
9
  makeCoreProposalBehavior,
9
- makeEnactCoreProposalsFromBundleCap,
10
+ makeEnactCoreProposalsFromBundleRef,
10
11
  } from './coreProposalBehavior.js';
11
12
 
12
- const { details: X } = assert;
13
+ /**
14
+ * @typedef {string | { module: string, entrypoint: string, args?: Array<unknown> }} ConfigProposal
15
+ */
16
+
17
+ const { details: X, Fail } = assert;
13
18
 
14
- const require = createRequire(import.meta.url);
19
+ const req = createRequire(import.meta.url);
15
20
 
16
21
  /**
17
22
  * @param {(ModuleSpecifier | FilePath)[]} paths
@@ -22,7 +27,7 @@ const pathResolve = (...paths) => {
22
27
  const fileName = paths.pop();
23
28
  assert(fileName, '>=1 paths required');
24
29
  try {
25
- return require.resolve(fileName, {
30
+ return req.resolve(fileName, {
26
31
  paths,
27
32
  });
28
33
  } catch (e) {
@@ -41,16 +46,16 @@ const pathResolve = (...paths) => {
41
46
  * but for sim-chain and such, they can be declared statically in
42
47
  * the chain configuration, in which case they are run at bootstrap.
43
48
  *
44
- * @param {(ModuleSpecifier | FilePath)[]} coreProposals - governance
49
+ * @param {ConfigProposal[]} coreProposals - governance
45
50
  * proposals to run at chain bootstrap for scenarios such as sim-chain.
46
51
  * @param {FilePath} [dirname]
47
- * @param {typeof makeEnactCoreProposalsFromBundleCap} [makeEnactCoreProposals]
52
+ * @param {typeof makeEnactCoreProposalsFromBundleRef} [makeEnactCoreProposals]
48
53
  * @param {(i: number) => number} [getSequenceForProposal]
49
54
  */
50
55
  export const extractCoreProposalBundles = async (
51
56
  coreProposals,
52
57
  dirname = '.',
53
- makeEnactCoreProposals = makeEnactCoreProposalsFromBundleCap,
58
+ makeEnactCoreProposals = makeEnactCoreProposalsFromBundleRef,
54
59
  getSequenceForProposal,
55
60
  ) => {
56
61
  if (!getSequenceForProposal) {
@@ -63,7 +68,7 @@ export const extractCoreProposalBundles = async (
63
68
  .stat(dirname)
64
69
  .then(stbuf => (stbuf.isDirectory() ? dirname : path.dirname(dirname)));
65
70
 
66
- /** @type {Map<{ bundleID?: string }, { source: string, bundle?: string }>} */
71
+ /** @type {Map<{ bundleName?: string }, { source: string, bundle?: string }>} */
67
72
  const bundleHandleToAbsolutePaths = new Map();
68
73
 
69
74
  const bundleToSource = new Map();
@@ -85,23 +90,18 @@ export const extractCoreProposalBundles = async (
85
90
  ({ module, entrypoint, args = [] } = coreProposal);
86
91
  }
87
92
 
88
- assert.typeof(
89
- module,
90
- 'string',
91
- X`coreProposal module ${module} must be string`,
92
- );
93
- assert.typeof(
94
- entrypoint,
95
- 'string',
96
- X`coreProposal entrypoint ${entrypoint} must be string`,
97
- );
98
- assert(Array.isArray(args), X`coreProposal args ${args} must be array`);
93
+ typeof module === 'string' ||
94
+ Fail`coreProposal module ${module} must be string`;
95
+ typeof entrypoint === 'string' ||
96
+ Fail`coreProposal entrypoint ${entrypoint} must be string`;
97
+ Array.isArray(args) || Fail`coreProposal args ${args} must be array`;
99
98
 
100
99
  const thisProposalBundleHandles = new Set();
101
100
  assert(getSequenceForProposal);
102
101
  const thisProposalSequence = getSequenceForProposal(i);
103
102
  const initPath = pathResolve(dirname, module);
104
103
  const initDir = path.dirname(initPath);
104
+ /** @type {Record<string, import('./externalTypes.js').ProposalBuilder>} */
105
105
  const ns = await import(initPath);
106
106
  const install = (srcSpec, bundlePath) => {
107
107
  const absoluteSrc = pathResolve(initDir, srcSpec);
@@ -121,16 +121,17 @@ export const extractCoreProposalBundles = async (
121
121
  bundleToSource.set(absoluteBundle, absoluteSrc);
122
122
  }
123
123
  }
124
- // Don't harden the bundleHandle since we need to set the bundleID on
124
+ // Don't harden the bundleHandle since we need to set the bundleName on
125
125
  // its unique identity later.
126
126
  thisProposalBundleHandles.add(bundleHandle);
127
127
  bundleHandleToAbsolutePaths.set(bundleHandle, harden(absolutePaths));
128
128
  return bundleHandle;
129
129
  };
130
+ /** @type {import('./externalTypes.js').PublishBundleRef} */
130
131
  const publishRef = async handleP => {
131
132
  const handle = await handleP;
132
133
  bundleHandleToAbsolutePaths.has(handle) ||
133
- assert.fail(X`${handle} not in installed bundles`);
134
+ Fail`${handle} not in installed bundles`;
134
135
  return handle;
135
136
  };
136
137
  const proposal = await ns[entrypoint]({ publishRef, install }, ...args);
@@ -148,21 +149,21 @@ export const extractCoreProposalBundles = async (
148
149
  return 0;
149
150
  })
150
151
  .map(([handle, absolutePaths], j) => {
151
- // Transform the bundle handle identity into a bundleID reference.
152
- handle.bundleID = `coreProposal${thisProposalSequence}_${j}`;
152
+ // Transform the bundle handle identity into a bundleName reference.
153
+ handle.bundleName = `coreProposal${thisProposalSequence}_${j}`;
153
154
  harden(handle);
154
155
 
155
156
  /** @type {[string, { sourceSpec: string }]} */
156
157
  const specEntry = [
157
- handle.bundleID,
158
+ handle.bundleName,
158
159
  { sourceSpec: absolutePaths.source },
159
160
  ];
160
161
  return specEntry;
161
162
  });
162
163
 
163
- // Now that we've assigned all the bundleIDs and hardened the handles, we
164
- // can extract the behavior bundle.
165
- const { sourceSpec, getManifestCall } = await deeplyFulfilled(
164
+ // Now that we've assigned all the bundleNames and hardened the
165
+ // handles, we can extract the behavior bundle.
166
+ const { sourceSpec, getManifestCall } = await deeplyFulfilledObject(
166
167
  harden(proposal),
167
168
  );
168
169
 
@@ -174,7 +175,7 @@ export const extractCoreProposalBundles = async (
174
175
  ](harden({ restoreRef: () => null }), ...manifestArgs);
175
176
 
176
177
  const behaviorBundleHandle = harden({
177
- bundleID: `coreProposal${thisProposalSequence}_behaviors`,
178
+ bundleName: `coreProposal${thisProposalSequence}_behaviors`,
178
179
  });
179
180
  const behaviorAbsolutePaths = harden({
180
181
  source: behaviorSource,
@@ -185,7 +186,7 @@ export const extractCoreProposalBundles = async (
185
186
  );
186
187
 
187
188
  bundleSpecEntries.unshift([
188
- behaviorBundleHandle.bundleID,
189
+ behaviorBundleHandle.bundleName,
189
190
  { sourceSpec: behaviorAbsolutePaths.source },
190
191
  ]);
191
192
 
@@ -14,11 +14,12 @@ import { E } from '@endo/far';
14
14
  import url from 'url';
15
15
 
16
16
  export const makeGetBundlerMaker =
17
- ({ board: optionalBoard, zoe, scratch }, { lookup, bundleSource }) =>
17
+ (homeP, { lookup, bundleSource }) =>
18
18
  async ({
19
19
  BUNDLER_MAKER_LOOKUP = JSON.stringify(['scratch', 'bundlerMaker']),
20
20
  log = console.log,
21
21
  } = {}) => {
22
+ const { board: optionalBoard, zoe, scratch } = await homeP;
22
23
  const lookupOrCreate = async () => {
23
24
  // Locate the bundler maker if any already exists at the given path.
24
25
  let bundlerMaker = await lookup(JSON.parse(BUNDLER_MAKER_LOOKUP));
package/src/helpers.js CHANGED
@@ -1,10 +1,15 @@
1
1
  // @ts-check
2
2
  import '@agoric/zoe/exported.js';
3
3
  import { E } from '@endo/far';
4
+ import bundleSource from '@endo/bundle-source';
5
+
6
+ import fs from 'fs/promises';
7
+ import os from 'os';
4
8
 
5
9
  import { makeInstall } from './install.js';
6
10
  import { makeOfferAndFindInvitationAmount } from './offer.js';
7
11
  import { makeStartInstance } from './startInstance.js';
12
+ import { makeCacheAndGetBundleSpec } from './cachedBundleSpec.js';
8
13
  import { makeDepositInvitation } from './depositInvitation.js';
9
14
  import { makeSaveIssuer } from './saveIssuer.js';
10
15
  import { makeGetBundlerMaker } from './getBundlerMaker.js';
@@ -12,68 +17,131 @@ import { assertOfferResult } from './assertOfferResult.js';
12
17
  import { installInPieces } from './installInPieces.js';
13
18
  import { makeWriteCoreProposal } from './writeCoreProposal.js';
14
19
 
15
- export * from './createBundles.js';
20
+ export * from '@agoric/internal/src/node/createBundles.js';
16
21
 
17
22
  // These are also hard-coded in lib-wallet.js.
18
23
  // TODO: Add methods to the wallet to access these without hard-coding
19
24
  // on this end.
20
25
  const ZOE_INVITE_PURSE_PETNAME = 'Default Zoe invite purse';
21
26
 
22
- export const makeHelpers = async (homePromise, endowments) => {
23
- const { zoe, wallet, scratch, board } = E.get(homePromise);
24
-
25
- const { bundleSource, lookup } = endowments;
26
-
27
- const walletAdmin = E(wallet).getAdminFacet();
28
- const installationManager = E(walletAdmin).getInstallationManager();
29
- const instanceManager = E(walletAdmin).getInstanceManager();
30
- const issuerManager = E(walletAdmin).getIssuerManager();
31
-
32
- // TODO: Rather than using one purse with a hard-coded petname, find
33
- // a better solution.
34
- const zoeInvitationPurse = E(walletAdmin).getPurse(ZOE_INVITE_PURSE_PETNAME);
35
-
36
- // Create the methods
37
-
38
- const install = makeInstall(bundleSource, zoe, installationManager, board);
39
-
40
- const startInstance = makeStartInstance(
41
- issuerManager,
42
- instanceManager,
43
- zoe,
44
- zoeInvitationPurse,
45
- );
46
-
47
- const { offer, findInvitationAmount } = makeOfferAndFindInvitationAmount(
48
- walletAdmin,
49
- zoe,
50
- zoeInvitationPurse,
27
+ /**
28
+ * @template {Record<PropertyKey, any>} T
29
+ *
30
+ * Lazily populate the returned object's properties from the properties of a
31
+ * source object. Each `sourceObject` property value is sampled at most once.
32
+ *
33
+ * @param {T} sourceObject
34
+ * @returns {T}
35
+ */
36
+ const makeLazyObject = sourceObject => {
37
+ const lazyObject = new Proxy(
38
+ {},
39
+ {
40
+ get(t, key) {
41
+ if (!(key in t)) {
42
+ if (key in sourceObject) {
43
+ t[key] = sourceObject[key];
44
+ }
45
+ }
46
+ return t[key];
47
+ },
48
+ },
51
49
  );
50
+ return /** @type {T} */ (lazyObject);
51
+ };
52
52
 
53
- const saveIssuer = makeSaveIssuer(walletAdmin, issuerManager);
54
-
55
- const depositInvitation = makeDepositInvitation(zoeInvitationPurse);
56
-
57
- const getBundlerMaker = makeGetBundlerMaker(
58
- { board, scratch, zoe },
59
- { bundleSource, lookup },
60
- );
53
+ export const makeHelpers = async (homePromise, endowments) => {
54
+ // Endowments provided via `agoric run` or `agoric deploy`.
55
+ const {
56
+ now,
57
+ lookup,
58
+ publishBundle,
59
+ pathResolve,
60
+ cacheDir = pathResolve(os.homedir(), '.agoric/cache'),
61
+ } = endowments;
62
+
63
+ // Internal-to-this-function lazy dependencies.
64
+ const deps = makeLazyObject({
65
+ get cacheAndGetBundleSpec() {
66
+ return makeCacheAndGetBundleSpec(cacheDir, {
67
+ now,
68
+ fs,
69
+ pathResolve,
70
+ });
71
+ },
72
+ get home() {
73
+ return E.get(homePromise);
74
+ },
75
+ get installationManager() {
76
+ return E(deps.walletAdmin).getInstallationManager();
77
+ },
78
+ get instanceManager() {
79
+ return E(deps.walletAdmin).getInstanceManager();
80
+ },
81
+ get issuerManager() {
82
+ return E(deps.walletAdmin).getIssuerManager();
83
+ },
84
+ get offerAndFind() {
85
+ return makeOfferAndFindInvitationAmount(
86
+ deps.walletAdmin,
87
+ deps.home.zoe,
88
+ deps.zoeInvitationPurse,
89
+ );
90
+ },
91
+ get walletAdmin() {
92
+ return E(deps.home.wallet).getAdminFacet();
93
+ },
94
+ get zoeInvitationPurse() {
95
+ // TODO: Rather than using one purse with a hard-coded petname, find
96
+ // a better solution.
97
+ return E(deps.walletAdmin).getPurse(ZOE_INVITE_PURSE_PETNAME);
98
+ },
99
+ });
61
100
 
62
- const writeCoreProposal = makeWriteCoreProposal(homePromise, endowments, {
101
+ // The memo returned to our callers.
102
+ const helpers = makeLazyObject({
103
+ assertOfferResult,
104
+ get depositInvitation() {
105
+ return makeDepositInvitation(deps.zoeInvitationPurse);
106
+ },
107
+ get findInvitationAmount() {
108
+ return deps.offerAndFind.findInvitationAmount;
109
+ },
110
+ get install() {
111
+ return makeInstall(
112
+ bundleSource,
113
+ deps.home.zoe,
114
+ deps.installationManager,
115
+ deps.home.board,
116
+ publishBundle,
117
+ pathResolve,
118
+ );
119
+ },
63
120
  installInPieces,
64
- getBundlerMaker,
121
+ get offer() {
122
+ return deps.offerAndFind.offer;
123
+ },
124
+ get saveIssuer() {
125
+ return makeSaveIssuer(deps.walletAdmin, deps.issuerManager);
126
+ },
127
+ get startInstance() {
128
+ return makeStartInstance(
129
+ deps.issuerManager,
130
+ deps.instanceManager,
131
+ deps.home.zoe,
132
+ deps.zoeInvitationPurse,
133
+ );
134
+ },
135
+ get getBundlerMaker() {
136
+ return makeGetBundlerMaker(homePromise, { bundleSource, lookup });
137
+ },
138
+ get writeCoreProposal() {
139
+ return makeWriteCoreProposal(homePromise, endowments, {
140
+ getBundleSpec: deps.cacheAndGetBundleSpec,
141
+ getBundlerMaker: helpers.getBundlerMaker,
142
+ });
143
+ },
65
144
  });
66
145
 
67
- return {
68
- install,
69
- startInstance,
70
- offer,
71
- findInvitationAmount,
72
- installInPieces,
73
- getBundlerMaker,
74
- saveIssuer,
75
- depositInvitation,
76
- assertOfferResult,
77
- writeCoreProposal,
78
- };
146
+ return helpers;
79
147
  };
package/src/install.js CHANGED
@@ -1,31 +1,72 @@
1
1
  // @ts-check
2
-
3
2
  import './externalTypes.js';
4
3
 
5
4
  import { E } from '@endo/far';
6
5
 
6
+ /** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
7
+
8
+ /**
9
+ * @callback BundleSource
10
+ * @param {string} startFilename - the filepath to start the bundling from
11
+ * @param {ModuleFormat | BundleOptions} [moduleFormat]
12
+ * @param {object} [powers]
13
+ * @param {ReadFn} [powers.read]
14
+ * @param {CanonicalFn} [powers.canonical]
15
+ */
16
+
7
17
  // XXX board is Board but specifying that leads to type errors with imports which aren't worth fixing right now
8
18
  /**
9
19
  * @param {BundleSource} bundleSource
10
20
  * @param {ERef<ZoeService>} zoe
11
21
  * @param {ERef<import('./startInstance.js').InstallationManager>} installationManager
12
22
  * @param {ERef<any>} board
13
- * @returns {InstallSaveAndPublish}
23
+ * @param {(bundle: any) => any} [publishBundle]
24
+ * @param {(path: string) => string} [pathResolve]
14
25
  */
15
- export const makeInstall = (bundleSource, zoe, installationManager, board) => {
16
- /** @type {InstallSaveAndPublish} */
17
- const install = async (resolvedPath, contractPetname) => {
18
- console.log(`- Installing Contract Name: ${contractPetname}`);
26
+ export const makeInstall = (
27
+ bundleSource,
28
+ zoe,
29
+ installationManager,
30
+ board,
31
+ publishBundle,
32
+ pathResolve,
33
+ ) => {
34
+ /**
35
+ * @param {string} contractPath
36
+ * @param {Petname} contractPetname
37
+ * @returns {Promise<{ installation: Installation, id: string}>}
38
+ */
39
+ const install = async (contractPath, contractPetname) => {
40
+ const resolvedPath = pathResolve ? pathResolve(contractPath) : contractPath;
19
41
 
20
42
  const bundle = await bundleSource(resolvedPath);
21
- const installation = await E(zoe).install(bundle);
22
-
43
+ console.log(`- Publishing Contract Name: ${contractPetname}`);
44
+ const hashedBundle = await (publishBundle ? publishBundle(bundle) : bundle);
45
+ console.log(`- Installing Contract Name: ${contractPetname}`);
46
+ const installation = await E(zoe).install(hashedBundle);
47
+ console.log(
48
+ `- Adding contract to installation manager: ${contractPetname}`,
49
+ );
23
50
  await E(installationManager).add(contractPetname, installation);
24
51
 
25
- console.log(`- Installed Contract Name: ${contractPetname}`);
26
-
52
+ // Let's share this installation with other people, so that
53
+ // they can run our contract code by making a contract
54
+ // instance (see the api deploy script in this repo to see an
55
+ // example of how to use the installation to make a new contract
56
+ // instance.)
57
+ // To share the installation, we're going to put it in the
58
+ // board. The board is a shared, on-chain object that maps
59
+ // strings to objects.
27
60
  const id = await E(board).getId(installation);
28
- return { installation, id };
61
+
62
+ console.log('- SUCCESS! contract code installed on Zoe');
63
+ console.log(`-- Contract Name: ${contractPetname}`);
64
+ console.log(`-- Installation Board Id: ${id}`);
65
+
66
+ return {
67
+ installation,
68
+ id,
69
+ };
29
70
  };
30
71
  return install;
31
72
  };
@@ -12,9 +12,12 @@ const computeSha512 = bytes => {
12
12
 
13
13
  export const installInPieces = async (
14
14
  bundle,
15
- bundler,
15
+ bundlerOrGetter,
16
16
  { maxBytesInFlight = 800_000, log = console.log, persist = false } = {},
17
17
  ) => {
18
+ const bundler =
19
+ typeof bundlerOrGetter === 'function' ? bundlerOrGetter() : bundlerOrGetter;
20
+
18
21
  // It would be nice to detect evaluation errors early like this:
19
22
  // await importBundle(bundle, { endowments });
20
23
  // but importBundle only works inside SwingSet; checking here
package/src/offer.js CHANGED
@@ -1,22 +1,35 @@
1
1
  // @ts-check
2
-
3
2
  import { E } from '@endo/far';
4
3
  import { assert } from '@agoric/assert';
5
- import { AmountMath } from '@agoric/ertp';
4
+ // Avoid pulling in too many dependencies like notifiers
5
+ import { AmountMath } from '@agoric/ertp/src/amountMath.js';
6
+
7
+ /** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
8
+
9
+ /**
10
+ * @typedef {object} OfferHelperConfig
11
+ * @property {ERef<Invitation>} [invitation]
12
+ * @property {Partial<InvitationDetails>} [partialInvitationDetails]
13
+ * @property {Proposal} proposal
14
+ * @property {Record<Keyword, Petname>} paymentsWithPursePetnames
15
+ * @property {Record<Keyword, Petname>} payoutPursePetnames
16
+ */
6
17
 
7
18
  /**
8
19
  * @param {ERef<any>} walletAdmin - an internal type of the
9
20
  * wallet, not defined here
10
21
  * @param {ERef<ZoeService>} zoe
11
22
  * @param {ERef<Purse>} zoeInvitationPurse
12
- * @returns {{ offer: OfferHelper, findInvitationAmount: FindInvitationAmount }}
13
23
  */
14
24
  export const makeOfferAndFindInvitationAmount = (
15
25
  walletAdmin,
16
26
  zoe,
17
27
  zoeInvitationPurse,
18
28
  ) => {
19
- /** @type {FindInvitationAmount} */
29
+ /**
30
+ * @param {Record<string, any>} invitationDetailsCriteria
31
+ * @returns {Promise<Amount>} invitationAmount
32
+ */
20
33
  const findInvitationAmount = async invitationDetailsCriteria => {
21
34
  const invitationAmount = await E(zoeInvitationPurse).getCurrentAmount();
22
35
 
@@ -79,16 +92,18 @@ export const makeOfferAndFindInvitationAmount = (
79
92
  const allDepositedP = Promise.all(
80
93
  Object.entries(paymentsP).map(([keyword, paymentP]) => {
81
94
  const depositInPurse = makeDepositInPurse(keyword);
82
- return paymentP.then(depositInPurse);
95
+ return E.when(paymentP, depositInPurse);
83
96
  }),
84
97
  );
85
98
  return allDepositedP;
86
99
  };
87
100
  const paymentsPP = E(seat).getPayouts();
88
- return paymentsPP.then(handlePayments);
101
+ return E.when(paymentsPP, handlePayments);
89
102
  };
90
103
 
91
- /** @type {OfferHelper} */
104
+ /**
105
+ * @param {OfferHelperConfig} config
106
+ */
92
107
  const offer = async config => {
93
108
  const {
94
109
  invitation,
package/src/saveIssuer.js CHANGED
@@ -1,15 +1,20 @@
1
1
  // @ts-check
2
-
3
2
  import { E } from '@endo/far';
4
3
 
4
+ /** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
5
+
5
6
  /**
6
7
  * @param {ERef<any>} walletAdmin - an internal type of the
7
8
  * wallet, not defined here
8
9
  * @param {ERef<import('./startInstance').IssuerManager>} issuerManager
9
- * @returns {SaveIssuerHelper}
10
10
  */
11
11
  export const makeSaveIssuer = (walletAdmin, issuerManager) => {
12
- /** @type {SaveIssuerHelper} */
12
+ /**
13
+ * @param {ERef<Issuer>} issuerP
14
+ * @param {Petname} brandPetname
15
+ * @param {Petname} pursePetname
16
+ * @returns {Promise<Petname>}
17
+ */
13
18
  const saveIssuer = async (issuerP, brandPetname, pursePetname) => {
14
19
  console.log(`-- Installing issuer for: ${brandPetname}`);
15
20
 
@@ -1,8 +1,9 @@
1
1
  // @ts-check
2
-
3
2
  import { assert } from '@agoric/assert';
4
3
  import { E, passStyleOf } from '@endo/far';
5
4
 
5
+ /** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
6
+
6
7
  /**
7
8
  * @template T
8
9
  * @typedef {object} PetnameManager
@@ -1,34 +1,29 @@
1
1
  // @ts-check
2
2
  import fs from 'fs';
3
3
  import { E } from '@endo/far';
4
+ import { deeplyFulfilled } from '@endo/marshal';
4
5
 
5
- import {
6
- deeplyFulfilled,
7
- defangAndTrim,
8
- mergePermits,
9
- stringify,
10
- } from './code-gen.js';
6
+ import { createBundles } from '@agoric/internal/src/node/createBundles.js';
7
+ import { defangAndTrim, mergePermits, stringify } from './code-gen.js';
11
8
  import { makeCoreProposalBehavior, permits } from './coreProposalBehavior.js';
12
- import { createBundles } from './createBundles.js';
13
9
 
14
10
  export const makeWriteCoreProposal = (
15
11
  homeP,
16
12
  endowments,
17
13
  {
18
14
  getBundlerMaker,
19
- installInPieces,
15
+ getBundleSpec,
20
16
  log = console.log,
21
17
  writeFile = fs.promises.writeFile,
22
18
  },
23
19
  ) => {
24
- const { board, zoe } = E.get(homeP);
25
20
  const { bundleSource, pathResolve } = endowments;
26
21
 
27
22
  let bundlerCache;
28
23
  const getBundler = () => {
29
24
  if (!bundlerCache) {
30
25
  bundlerCache = E(getBundlerMaker()).makeBundler({
31
- zoe,
26
+ zoe: E.get(homeP).zoe,
32
27
  });
33
28
  }
34
29
  return bundlerCache;
@@ -57,33 +52,37 @@ export const makeWriteCoreProposal = (
57
52
 
58
53
  let mutex = Promise.resolve();
59
54
  const writeCoreProposal = async (filePrefix, proposalBuilder) => {
55
+ const getBundle = async (entrypoint, bundlePath) => {
56
+ if (!bundlePath) {
57
+ return bundleSource(pathResolve(entrypoint));
58
+ }
59
+ const bundleCache = pathResolve(bundlePath);
60
+ await createBundles([[pathResolve(entrypoint), bundleCache]]);
61
+ const ns = await import(bundleCache);
62
+ return ns.default;
63
+ };
64
+
60
65
  // Install an entrypoint.
61
66
  const install = async (entrypoint, bundlePath, opts) => {
62
- const bundler = getBundler();
63
- let bundle;
64
- if (bundlePath) {
65
- const bundleCache = pathResolve(bundlePath);
66
- await createBundles([[pathResolve(entrypoint), bundleCache]]);
67
- const ns = await import(bundleCache);
68
- bundle = ns.default;
69
- } else {
70
- bundle = await bundleSource(pathResolve(entrypoint));
71
- }
67
+ const bundle = getBundle(entrypoint, bundlePath);
72
68
 
73
69
  // Serialise the installations.
74
- mutex = mutex.then(() => {
75
- console.log('installing', { filePrefix, entrypoint, bundlePath });
76
-
77
- return installInPieces(bundle, bundler, opts);
70
+ mutex = E.when(mutex, () => {
71
+ // console.log('installing', { filePrefix, entrypoint, bundlePath });
72
+ return getBundleSpec(bundle, getBundler, opts);
78
73
  });
79
74
  return mutex;
80
75
  };
81
76
 
82
77
  // Await a reference then publish to the board.
78
+ const cmds = [];
83
79
  const publishRef = async refP => {
84
- const ref = await refP;
85
- console.log('published', { filePrefix, ref });
86
- return E(board).getId(ref);
80
+ const { fileName, ...ref } = await refP;
81
+ if (fileName) {
82
+ cmds.push(`agd tx swingset install-bundle @${fileName}`);
83
+ }
84
+
85
+ return harden(ref);
87
86
  };
88
87
 
89
88
  // Create the proposal structure.
@@ -91,25 +90,26 @@ export const makeWriteCoreProposal = (
91
90
  harden(proposalBuilder({ publishRef, install })),
92
91
  );
93
92
  const { sourceSpec, getManifestCall } = proposal;
94
- console.log('created', { filePrefix, sourceSpec, getManifestCall });
93
+ // console.log('created', { filePrefix, sourceSpec, getManifestCall });
95
94
 
96
95
  // Extract the top-level permit.
97
96
  const { permits: proposalPermit, manifest: overrideManifest } =
98
97
  await mergeProposalPermit(proposal, permits);
99
98
 
100
99
  // Get an install
101
- const manifestInstallRef = await publishRef(install(sourceSpec));
102
- console.log('writing', { filePrefix, manifestInstallRef, sourceSpec });
100
+ const manifestBundleRef = await publishRef(install(sourceSpec));
101
+
102
+ // console.log('writing', { filePrefix, manifestBundleRef, sourceSpec });
103
103
  const code = `\
104
104
  // This is generated by writeCoreProposal; please edit!
105
105
  /* eslint-disable */
106
106
 
107
- const manifestInstallRef = ${stringify(manifestInstallRef)};
107
+ const manifestBundleRef = ${stringify(manifestBundleRef)};
108
108
  const getManifestCall = harden(${stringify(getManifestCall, true)});
109
109
  const overrideManifest = ${stringify(overrideManifest, true)};
110
110
 
111
111
  // Make the behavior the completion value.
112
- (${makeCoreProposalBehavior})({ manifestInstallRef, getManifestCall, overrideManifest, E });
112
+ (${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, overrideManifest, E });
113
113
  `;
114
114
 
115
115
  const trimmed = defangAndTrim(code);
@@ -130,6 +130,8 @@ You can now run a governance submission command like:
130
130
  agd tx gov submit-proposal swingset-core-eval ${proposalPermitJsonFile} ${proposalJsFile} \\
131
131
  --title="Enable <something>" --description="Evaluate ${proposalJsFile}" --deposit=1000000ubld \\
132
132
  --gas=auto --gas-adjustment=1.2
133
+ Remember to install bundles before submitting the proposal:
134
+ ${cmds.join('\n ')}
133
135
  `);
134
136
  };
135
137
 
@@ -1,79 +0,0 @@
1
- import path from 'path';
2
- import { spawnSync } from 'child_process';
3
- import { createRequire } from 'module';
4
-
5
- const BUNDLE_SOURCE_PROGRAM = 'bundle-source';
6
- const require = createRequire(import.meta.url);
7
-
8
- export const createBundlesFromAbsolute = async sourceBundles => {
9
- const prog = require.resolve(`.bin/${BUNDLE_SOURCE_PROGRAM}`);
10
-
11
- const cacheToArgs = new Map();
12
- for (const [srcPath, bundlePath] of sourceBundles) {
13
- const cache = path.dirname(bundlePath);
14
- const base = path.basename(bundlePath);
15
-
16
- const match = base.match(/^bundle-(.*)\.js$/);
17
- assert(match, `${bundlePath} is not 'DIR/bundle-NAME.js'`);
18
- const bundle = match[1];
19
-
20
- const args = cacheToArgs.get(cache) || ['--to', cache];
21
- args.push(srcPath, bundle);
22
- cacheToArgs.set(cache, args);
23
- }
24
-
25
- for (const args of cacheToArgs.values()) {
26
- console.log(BUNDLE_SOURCE_PROGRAM, ...args);
27
- const { status } = spawnSync(prog, args, { stdio: 'inherit' });
28
- assert.equal(
29
- status,
30
- 0,
31
- `${BUNDLE_SOURCE_PROGRAM} failed with status ${status}`,
32
- );
33
- }
34
- };
35
-
36
- export const createBundles = async (sourceBundles, dirname = '.') => {
37
- const absBundleSources = sourceBundles.map(([srcPath, bundlePath]) => [
38
- require.resolve(srcPath, { paths: [dirname] }),
39
- path.resolve(dirname, bundlePath),
40
- ]);
41
- return createBundlesFromAbsolute(absBundleSources);
42
- };
43
-
44
- export const extractProposalBundles = async (
45
- dirProposalBuilder,
46
- dirname = '.',
47
- ) => {
48
- const toBundle = new Map();
49
-
50
- await Promise.all(
51
- dirProposalBuilder.map(async ([dir, proposalBuilder]) => {
52
- const home = path.resolve(dirname, dir);
53
- const publishRef = x => x;
54
- const install = async (src, bundleName) => {
55
- if (bundleName) {
56
- const bundlePath = path.resolve(home, bundleName);
57
- const srcPath = require.resolve(src, { paths: [home] });
58
- if (toBundle.has(bundlePath)) {
59
- const oldSrc = toBundle.get(bundlePath);
60
- assert.equal(
61
- oldSrc,
62
- srcPath,
63
- `${bundlePath} already installed as ${oldSrc}, also given ${srcPath}`,
64
- );
65
- }
66
- toBundle.set(bundlePath, srcPath);
67
- }
68
- };
69
- return proposalBuilder({ publishRef, install });
70
- }),
71
- );
72
-
73
- return createBundlesFromAbsolute(
74
- [...toBundle.entries()].map(([bundlePath, srcPath]) => [
75
- srcPath,
76
- bundlePath,
77
- ]),
78
- );
79
- };