Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(orchestration): ZCFTools #10057

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const contract = async (

// orchestrate uses the names on orchestrationFns to do a "prepare" of the associated behavior
const orchFns = orchestrateAll(flows, {
zcf,
contractState,
zoeTools,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ const contract = async (
makeCombineInvitationMakers,
makeExtraInvitationMaker,
flows,
zcf,
zoeTools,
});

Expand Down
1 change: 0 additions & 1 deletion packages/orchestration/src/examples/swap.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ const contract = async (
const { brands } = zcf.getTerms();

const { stakeAndSwap } = orchestrateAll(flows, {
zcf,
localTransfer: zoeTools.localTransfer,
});

Expand Down
9 changes: 7 additions & 2 deletions packages/orchestration/src/examples/unbond.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ import * as flows from './unbond.flows.js';
* @param {Zone} zone
* @param {OrchestrationTools} tools
*/
const contract = async (zcf, privateArgs, zone, { orchestrateAll }) => {
const { unbondAndTransfer } = orchestrateAll(flows, { zcf });
const contract = async (
zcf,
privateArgs,
zone,
{ orchestrateAll, zcfTools },
) => {
const { unbondAndTransfer } = orchestrateAll(flows, { zcfTools });

const publicFacet = zone.exo('publicFacet', undefined, {
makeUnbondAndTransferInvitation() {
Expand Down
8 changes: 4 additions & 4 deletions packages/orchestration/src/examples/unbond.flows.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import { makeTracer } from '@agoric/internal';
const trace = makeTracer('UnbondAndTransfer');

/**
* @import {Orchestrator, OrchestrationFlow, CosmosDelegationResponse} from '../types.js'
* @import {Orchestrator, OrchestrationFlow, CosmosDelegationResponse, ZcfTools} from '../types.js'
*/

/**
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} orch
* @param {object} ctx
* @param {ZCF} ctx.zcf
* @param {ZcfTools} ctx.zcfTools
*/
export const unbondAndTransfer = async (orch, { zcf }) => {
trace('zcf within the membrane', zcf);
export const unbondAndTransfer = async (orch, { zcfTools }) => {
trace('zcfTools within the membrane', zcfTools);
// Osmosis is one of the few chains with icqEnabled
const osmosis = await orch.getChain('osmosis');
const osmoDenom = (await osmosis.getChainInfo()).stakingTokens[0].denom;
Expand Down
7 changes: 7 additions & 0 deletions packages/orchestration/src/facade.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ export const makeOrchestrationFacade = ({
const [wrappedCtx] = prepareEndowment(subZone, 'endowments', [hostCtx]);
const hostFn = asyncFlow(subZone, 'asyncFlow', guestFn);

deepMapObject(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nb: the usage here somewhat abuses the "map" idea. Kind of a deepAssert or visitObject

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quite

wrappedCtx,
val =>
val === zcf &&
assert.fail('do not use zcf in orchestration context; try zcfTools'),
);

// cast because return could be arbitrary subtype
const orcFn = /** @type {HostForGuest<GF>} */ (
(...args) => {
Expand Down
9 changes: 9 additions & 0 deletions packages/orchestration/src/types.ts
mhofman marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,12 @@ export type * from './orchestration-api.js';
export type * from './exos/cosmos-interchain-service.js';
export type * from './exos/chain-hub.js';
export type * from './vat-orchestration.js';

/**
* ({@link ZCF})-like tools for use in {@link OrchestrationFlow}s.
*/
export interface ZcfTools {
assertUniqueKeyword: ZCF['assertUniqueKeyword'];
atomicRearrange: ZCF['atomicRearrange'];
makeInvitation: ZCF['makeInvitation'];
}
5 changes: 5 additions & 0 deletions packages/orchestration/src/utils/start-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { prepareOrchestrator } from '../exos/orchestrator.js';
import { prepareRemoteChainFacade } from '../exos/remote-chain-facade.js';
import { makeOrchestrationFacade } from '../facade.js';
import { makeZoeTools } from './zoe-tools.js';
import { makeZcfTools } from './zcf-tools.js';

/**
* @import {LocalChain} from '@agoric/vats/src/localchain.js';
Expand Down Expand Up @@ -76,6 +77,8 @@ export const provideOrchestration = (

const zoeTools = makeZoeTools(zcf, vowTools);

const zcfTools = makeZcfTools(zcf, vowTools);

const { makeRecorderKit } = prepareRecorderKitMakers(baggage, marshaller);
const makeLocalOrchestrationAccountKit = prepareLocalOrchestrationAccountKit(
zones.orchestration,
Expand Down Expand Up @@ -164,12 +167,14 @@ export const provideOrchestration = (
const defaultOrchestrateKit = makeOrchestrateKit(
zones.contract.subZone('orchestration'),
);

return {
...defaultOrchestrateKit,
makeOrchestrateKit,
chainHub,
vowTools,
asyncFlowTools,
zcfTools,
zoeTools,
zone: zones.contract,
};
Expand Down
35 changes: 35 additions & 0 deletions packages/orchestration/src/utils/zcf-tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @import {HostInterface} from '@agoric/async-flow';
* @import {VowTools} from '@agoric/vow';
* @import {ZcfTools} from '../types.js';
*/

import { M, mustMatch } from '@endo/patterns';

const HandlerShape = M.remotable('OfferHandler');

/**
* @param {ZCF} zcf
* @param {VowTools} vowTools
* @returns {HostInterface<ZcfTools>}
*/
turadg marked this conversation as resolved.
Show resolved Hide resolved
export const makeZcfTools = (zcf, vowTools) =>
harden({
makeInvitation(offerHandler, description, customDetails, proposalShape) {
mustMatch(offerHandler, HandlerShape);
return vowTools.watch(
zcf.makeInvitation(
offerHandler,
description,
customDetails,
proposalShape,
),
);
},
atomicRearrange(transfers) {
zcf.atomicRearrange(transfers);
},
assertUniqueKeyword(keyword) {
zcf.assertUniqueKeyword(keyword);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ Generated by [AVA](https://avajs.dev).
orchestration: {
unbondAndTransfer: {
asyncFlow_kindHandle: 'Alleged: kind',
endowments: {
0: {
zcfTools: {
assertUniqueKeyword_kindHandle: 'Alleged: kind',
assertUniqueKeyword_singleton: 'Alleged: assertUniqueKeyword',
atomicRearrange_kindHandle: 'Alleged: kind',
atomicRearrange_singleton: 'Alleged: atomicRearrange',
makeInvitation_kindHandle: 'Alleged: kind',
makeInvitation_singleton: 'Alleged: makeInvitation',
},
mhofman marked this conversation as resolved.
Show resolved Hide resolved
},
},
},
},
publicFacet_kindHandle: 'Alleged: kind',
Expand Down
Binary file not shown.
2 changes: 0 additions & 2 deletions packages/orchestration/test/facade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ test('calls between flows', async t => {

const { outer, outer2, inner } = orchestrateAll(flows, {
peerFlows: flows,
zcf,
});

t.deepEqual(await vt.when(inner('a', 'b', 'c')), 'a b c');
Expand All @@ -70,7 +69,6 @@ test('context mapping individual flows', async t => {

const { outer } = orchestrateAll(flows, {
peerFlows: { inner: flows.inner },
zcf,
});

t.deepEqual(await vt.when(outer('a', 'b', 'c')), 'Hello a b c');
Expand Down
20 changes: 20 additions & 0 deletions packages/orchestration/test/fixtures/zcfTester.contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Far } from '@endo/far';

/**
* Tests ZCF
*
* @param {ZCF} zcf
*/
export const start = async zcf => {
// make the `zcf` and `instance` available to the tests
const instance = zcf.getInstance();
zcf.setTestJig(() => harden({ instance }));

const publicFacet = Far('public facet', {
makeInvitation: () => zcf.makeInvitation(() => 17, 'simple'),
});

return { publicFacet };
};

harden(start);
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ const contract = async (
const creatorFacet = prepareChainHubAdmin(zone, chainHub);

const orchFns = orchestrateAll(flows, {
zcf,
contractState,
zoeTools,
});
Expand Down
76 changes: 76 additions & 0 deletions packages/orchestration/test/utils/zcf-tools.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { AmountMath, makeIssuerKit } from '@agoric/ertp';
import { prepareSwingsetVowTools } from '@agoric/vow';
import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin.js';
import { makeZoeKitForTest } from '@agoric/zoe/tools/setup-zoe.js';
import { makeNodeBundleCache } from '@endo/bundle-source/cache.js';
import { E, Far } from '@endo/far';
import type { TestFn } from 'ava';
import { createRequire } from 'node:module';
import { makeZcfTools } from '../../src/utils/zcf-tools.js';
import { provideDurableZone } from '../supports.js';

const nodeRequire = createRequire(import.meta.url);
const contractEntry = nodeRequire.resolve('../fixtures/zcfTester.contract.js');

const makeTestContext = async () => {
let testJig;
const setJig = jig => (testJig = jig);
const fakeVatAdmin = makeFakeVatAdmin(setJig);
const { zoeService: zoe, feeMintAccess } = makeZoeKitForTest(
fakeVatAdmin.admin,
);

const bundleCache = await makeNodeBundleCache('bundles', {}, s => import(s));
const contractBundle = await bundleCache.load(contractEntry);

fakeVatAdmin.vatAdminState.installBundle('b1-contract', contractBundle);
const installation = await E(zoe).installBundleID('b1-contract');

const stuff = makeIssuerKit('Stuff');
await E(zoe).startInstance(installation, { Stuff: stuff.issuer });
assert(testJig, 'startInstance did not call back to setTestJig');

const zcf: ZCF = testJig.zcf;

const zone = provideDurableZone('root');
const vt = prepareSwingsetVowTools(zone);
const zcfTools = makeZcfTools(zcf, vt);
return { zoe, zcf, stuff, feeMintAccess, zcfTools, vt };
};

type TestContext = Awaited<ReturnType<typeof makeTestContext>>;

const test = anyTest as TestFn<TestContext>;

test.before('set up context', async t => (t.context = await makeTestContext()));

test('unchanged: atomicRearrange(), assertUniqueKeyword()', async t => {
const { zcf, zcfTools } = t.context;

t.notThrows(() => zcfTools.atomicRearrange([]));

t.notThrows(() => zcfTools.assertUniqueKeyword('K1'));
t.throws(() => zcfTools.assertUniqueKeyword('Stuff'));
});

test('changed: makeInvitation: watch promise', async t => {
const { zoe, zcf, zcfTools, vt } = t.context;

const handler = Far('Trade', { handle: seat => {} });
const toTradeVow = zcfTools.makeInvitation(handler, 'trade');

const toTrade = await vt.when(toTradeVow);
const amt = await E(E(zoe).getInvitationIssuer()).getAmountOf(toTrade);
t.like(amt, { value: [{ description: 'trade' }] });
});

test('removed: makeInvitation: non-passable handler', async t => {
const { zcfTools } = t.context;

const handler = harden(_seat => {});
t.throws(() => zcfTools.makeInvitation(handler, 'trade'), {
message: /Remotables must be explicitly declared/,
});
});
Loading