Skip to content

Commit

Permalink
Merge pull request #8146 from Agoric/8045-backwards-compatibility
Browse files Browse the repository at this point in the history
8045 backwards compatibility
  • Loading branch information
turadg authored Aug 9, 2023
2 parents d97cea7 + 876cf12 commit cbec0c6
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 158 deletions.
1 change: 1 addition & 0 deletions packages/zoe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"test/unitTests/zcf/test-feeMintAccess.js",
"# import.meta.url by way of setupZcfTest",
"test/unitTests/test-zoe.js",
"test/unitTests/test-zoe-startInstance.js",
"test/unitTests/test-blockedOffers.js",
"test/unitTests/zcf/test-reallocate-empty.js",
"test/unitTests/zcf/test-zoeHelpersWZcf.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/zoe/src/cleanProposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ const assertKeywordNotInBoth = (want, give) => {
const wantKeywordSet = new Set(ownKeys(want));
const giveKeywords = ownKeys(give);

giveKeywords.forEach(keyword => {
for (const keyword of giveKeywords) {
!wantKeywordSet.has(keyword) ||
Fail`a keyword cannot be in both 'want' and 'give'`;
});
}
};

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/zoe/src/contractFacet/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@
* @typedef ContractMeta
* @property {CopyRecord<Pattern>} [customTermsShape]
* @property {CopyRecord<Pattern>} [privateArgsShape]
* @property {'canBeUpgraded' | 'canUpgrade'} [upgradability]
* @property {'none' | 'canBeUpgraded' | 'canUpgrade'} [upgradability='none']
*/

/**
Expand Down
83 changes: 59 additions & 24 deletions packages/zoe/src/contractFacet/zcfZygote.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { E } from '@endo/eventual-send';
import { passStyleOf, Remotable } from '@endo/marshal';
import { AssetKind } from '@agoric/ertp';
import { makePromiseKit } from '@endo/promise-kit';
import { assertPattern, mustMatch } from '@agoric/store';
import {
canBeDurable,
M,
makeScalarBigMapStore,
provideDurableMapStore,
prepareExo,
prepareExoClass,
provideDurableMapStore,
} from '@agoric/vat-data';
import { E } from '@endo/eventual-send';
import { passStyleOf, Remotable } from '@endo/marshal';
import { makePromiseKit } from '@endo/promise-kit';

import { objectMap } from '@agoric/internal';
import { cleanProposal } from '../cleanProposal.js';
import { handlePKitWarning } from '../handleWarning.js';
import { makeInstanceRecordStorage } from '../instanceRecordStorage.js';
import { provideIssuerStorage } from '../issuerStorage.js';
import { defineDurableHandle } from '../makeHandle.js';
import { evalContractBundle } from './evalContractCode.js';
import { makeMakeExiter } from './exit.js';
import { defineDurableHandle } from '../makeHandle.js';
import { provideIssuerStorage } from '../issuerStorage.js';
import { createSeatManager } from './zcfSeat.js';
import { makeInstanceRecordStorage } from '../instanceRecordStorage.js';
import { handlePKitWarning } from '../handleWarning.js';
import { makeOfferHandlerStorage } from './offerHandlerStorage.js';
import { createSeatManager } from './zcfSeat.js';

import '../internal-types.js';
import './internal-types.js';
Expand Down Expand Up @@ -211,15 +211,24 @@ export const makeZCFZygote = async (
const handleOfferObj = makeHandleOfferObj(taker);

/**
* @type {() => Promise< {
* buildRootObject: any,
* start: undefined,
* meta: undefined,
* } | {
* buildRootObject: undefined,
* start: ContractStartFn,
* meta?: ContractMeta,
}>} */
* @type {() => Promise<
* | {
* buildRootObject: any;
* start: undefined;
* meta: undefined;
* }
* | {
* prepare: ContractStartFn;
* customTermsShape?: Pick<ContractMeta, 'customTermsShape'>,
* privateArgsShape?: Pick<ContractMeta, 'privateArgsShape'>,
* }
* | {
* buildRootObject: undefined;
* start: ContractStartFn;
* meta?: ContractMeta;
* }
* >}
*/
const evaluateContract = () => {
let bundle;
if (passStyleOf(contractBundleCap) === 'remotable') {
Expand All @@ -232,18 +241,44 @@ export const makeZCFZygote = async (
return evalContractBundle(bundle);
};
// evaluate the contract (either the first version, or an upgrade)
const { start, buildRootObject, meta = {} } = await evaluateContract();
const bundleResult = await evaluateContract();

//#region backwards compatibility with prepare()
const { start, meta = {} } = (() => {
if ('prepare' in bundleResult) {
if ('start' in bundleResult) {
Fail`contract must provide exactly one of "start" and "prepare"`;
}
// A contract must have one expression of upgradability
if (/** @type {any} */ (bundleResult).meta?.upgradability) {
Fail`prepare() is deprecated and incompatible with the 'upgradability' indicator`;
}
return {
start: bundleResult.prepare,
meta: {
upgradability: 'canUpgrade',
customTermsShape: bundleResult.customTermsShape,
privateArgsShape: bundleResult.privateArgsShape,
},
};
}
// normal behavior
return bundleResult;
})();
//#endregion

if (start === undefined) {
buildRootObject === undefined ||
Fail`Did you provide a vat bundle instead of a contract bundle?`;
if ('buildRootObject' in bundleResult) {
// diagnose a common mistake
throw Fail`Did you provide a vat bundle instead of a contract bundle?`;
}
throw Fail`contract exports missing start`;
}

start.length <= 3 || Fail`invalid start parameters`;
const durabilityRequired = meta.upgradability
? ['canBeUpgraded', 'canUpgrade'].includes(meta.upgradability)
: false;
const durabilityRequired =
meta.upgradability &&
['canBeUpgraded', 'canUpgrade'].includes(meta.upgradability);

/** @type {ZCF} */
// Using Remotable rather than Far because there are too many complications
Expand Down
8 changes: 4 additions & 4 deletions packages/zoe/src/contracts/auction/firstPriceLogic.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const calcWinnerAndClose = (zcf, sellSeat, bidSeats) => {
let highestBidSeat = bidSeats[0];
let activeBidsCount = 0n;

bidSeats.forEach(bidSeat => {
for (const bidSeat of bidSeats) {
if (!bidSeat.hasExited()) {
activeBidsCount += 1n;
/** @type {Amount<'nat'>} */
Expand All @@ -34,7 +34,7 @@ export const calcWinnerAndClose = (zcf, sellSeat, bidSeats) => {
highestBidSeat = bidSeat;
}
}
});
}

if (activeBidsCount === 0n) {
throw sellSeat.fail(Error(`Could not close auction. No bids were active`));
Expand All @@ -49,10 +49,10 @@ export const calcWinnerAndClose = (zcf, sellSeat, bidSeats) => {
);

sellSeat.exit();
bidSeats.forEach(bidSeat => {
for (const bidSeat of bidSeats) {
if (!bidSeat.hasExited()) {
bidSeat.exit();
}
});
}
zcf.shutdown('Auction closed.');
};
11 changes: 3 additions & 8 deletions packages/zoe/src/contracts/scaledPriceAuthority.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ import { provideQuoteMint } from '../contractSupport/priceAuthorityQuoteMint.js'
* @property {Ratio} [initialPrice] - targetAmountIn:targetAmountOut
*/

/** @type {ContractMeta} */
export const meta = {
upgradability: 'canUpgrade',
};
harden(meta);

/**
* A contract that scales a source price authority to a target price authority
* via ratios.
Expand All @@ -36,7 +30,8 @@ harden(meta);
* @param {object} privateArgs
* @param {import('@agoric/vat-data').Baggage} baggage
*/
export const start = async (zcf, privateArgs, baggage) => {
// 'prepare' is deprecated but still supported
export const prepare = async (zcf, privateArgs, baggage) => {
const quoteMint = provideQuoteMint(baggage);

const { sourcePriceAuthority, scaleIn, scaleOut, initialPrice } =
Expand Down Expand Up @@ -91,4 +86,4 @@ export const start = async (zcf, privateArgs, baggage) => {
);
return harden({ publicFacet });
};
harden(start);
harden(prepare);
3 changes: 2 additions & 1 deletion packages/zoe/test/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import { E } from '@endo/eventual-send';
import { expectType } from 'tsd';

import type { start as scaledPriceAuthorityStart } from '../src/contracts/scaledPriceAuthority.js';
// 'prepare' is deprecated but still supported
import type { prepare as scaledPriceAuthorityStart } from '../src/contracts/scaledPriceAuthority.js';

{
const zoe = {} as ZoeService;
Expand Down
7 changes: 7 additions & 0 deletions packages/zoe/test/unitTests/beforeMetaContract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @file a valid contract before 'meta' export was introduced */

export const privateArgsShape = harden({ greeting: 'hello' });

export const prepare = () => {
return harden({ creatorFacet: {} });
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import { makeManualPriceAuthority } from '../../../tools/manualPriceAuthority.js

import '../../../src/contracts/exported.js';

// This contract still uses 'prepare', so this test covers that case.
/**
* @typedef {object} TestContext
* @property {ZoeService} zoe
* @property {Installation<typeof import('../../../src/contracts/scaledPriceAuthority.js').start>} scaledPriceInstallation
* @property {Installation<typeof import('../../../src/contracts/scaledPriceAuthority.js').prepare>} scaledPriceInstallation
* @property {Brand<'nat'>} atomBrand
* @property {Brand<'nat'>} usdBrand
* @property {IssuerKit<'nat'>} atom
Expand Down
3 changes: 3 additions & 0 deletions packages/zoe/test/unitTests/redundantPrepareContract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const start = () => ({});

export const prepare = start;
Loading

0 comments on commit cbec0c6

Please sign in to comment.