Skip to content

Commit

Permalink
test: RunUtils test of vtransfer
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg authored and michaelfig committed Jun 8, 2024
1 parent 61bb791 commit 42b2e7e
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 5 deletions.
94 changes: 92 additions & 2 deletions packages/boot/test/bootstrapTests/demo-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
/* eslint-disable @jessie.js/safe-await-separator -- confused by casting 'as' */
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { PowerFlags } from '@agoric/vats/src/walletFlags.js';

import type { TestFn } from 'ava';
import type { NameAdmin, NameHub } from '@agoric/vats';

import { makeSwingsetTestKit, keyArrayEqual } from '../../tools/supports.ts';
import type { BridgeHandler, ScopedBridgeManager } from '@agoric/vats';
import type {
TransferMiddleware,
TransferVat,
} from '@agoric/vats/src/vat-transfer.js';
import { BridgeId } from '@agoric/internal';
import { keyArrayEqual, makeSwingsetTestKit } from '../../tools/supports.ts';

const { keys } = Object;

Expand Down Expand Up @@ -76,6 +82,7 @@ test('namesByAddress contains provisioned account', async t => {
const { EV } = t.context.runUtils;
const addr = 'agoric1234new';
const home = await makeHomeFor(addr, EV);
t.truthy(home);
const namesByAddress =
await EV.vat('bootstrap').consumeItem('namesByAddress');
await t.notThrowsAsync(EV(namesByAddress).lookup(addr));
Expand Down Expand Up @@ -111,3 +118,86 @@ test('demo config meets loadgen constraint: no USDC', async t => {

// FIXME tests can pass when console shows "BOOTSTRAP FAILED"
test.todo('demo config bootstrap succeeds');

test('vtransfer', async t => {
const { buildProposal, evalProposal, getOutboundMessages, runUtils } =
t.context;
const { EV } = runUtils;

// Pull what transfer-proposal produced into local scope
const transferVat = (await EV.vat('bootstrap').consumeItem(
'transferVat',
)) as ERef<TransferVat>;
t.truthy(transferVat);
const transferMiddleware = (await EV.vat('bootstrap').consumeItem(
'transferMiddleware',
)) as TransferMiddleware;
t.truthy(transferMiddleware);
const vtransferBridgeManager = (await EV.vat('bootstrap').consumeItem(
'vtransferBridgeManager',
)) as ScopedBridgeManager;
t.truthy(vtransferBridgeManager);

// only VTRANSFER_IBC_EVENT is supported by vtransferBridgeManager
await t.throwsAsync(
EV(vtransferBridgeManager).fromBridge({
type: 'VTRANSFER_OTHER',
}),
{
message:
'Invalid inbound event type "VTRANSFER_OTHER"; expected "VTRANSFER_IBC_EVENT"',
},
);

const target = 'agoric1vtransfertest';

// 0 interceptors for target

// TODO see if I can make a string template for Agoric address `agoric1…`
// it's an error to target an address before an interceptor is registered
await t.throwsAsync(
EV(vtransferBridgeManager).fromBridge({
target,
type: 'VTRANSFER_IBC_EVENT',
event: 'echo',
}),
{
message:
'key "agoric1vtransfertest" not found in collection "targetToApp"',
},
);

// 1 interceptors for target

// Tap into VTRANSFER_IBC_EVENT messages
await evalProposal(
buildProposal('@agoric/builders/scripts/vats/test-vtransfer.js'),
);

// simulate a Golang upcall with arbitrary payload
await EV(vtransferBridgeManager).fromBridge({
target,
type: 'VTRANSFER_IBC_EVENT',
event: 'writeAcknowledgement',
packet: 'thisIsPacket',
});

// verify the ackMethod outbound
const messages = getOutboundMessages(BridgeId.VTRANSFER);
t.deepEqual(messages, [
{
ack: 'eyJldmVudCI6IndyaXRlQWNrbm93bGVkZ2VtZW50IiwicGFja2V0IjoidGhpc0lzUGFja2V0IiwidGFyZ2V0IjoiYWdvcmljMXZ0cmFuc2ZlcnRlc3QiLCJ0eXBlIjoiVlRSQU5TRkVSX0lCQ19FVkVOVCJ9',
method: 'receiveExecuted',
packet: 'thisIsPacket',
type: 'IBC_METHOD',
},
]);
t.deepEqual(JSON.parse(atob(messages[0].ack)), {
event: 'writeAcknowledgement',
packet: 'thisIsPacket',
target: 'agoric1vtransfertest',
type: 'VTRANSFER_IBC_EVENT',
});

// TODO test adding an interceptor for the same target, which should fail
});
2 changes: 1 addition & 1 deletion packages/boot/tools/supports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import {
boardSlottingMarshaller,
slotToBoardRemote,
} from '@agoric/vats/tools/board-utils.js';
import { makeRunUtils } from '@agoric/swingset-vat/tools/run-utils.js';

import type { ExecutionContext as AvaT } from 'ava';

import { makeRunUtils } from '@agoric/swingset-vat/tools/run-utils.js';
import type { CoreEvalSDKType } from '@agoric/cosmic-proto/swingset/swingset.js';
import type { BridgeHandler, IBCMethod } from '@agoric/vats';
import { icaMocks, protoMsgMocks } from './ibc/mocks.js';
Expand Down
18 changes: 18 additions & 0 deletions packages/builders/scripts/vats/test-vtransfer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { makeHelpers } from '@agoric/deploy-script-support';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */
export const defaultProposalBuilder = async _powers =>
harden({
sourceSpec: '@agoric/vats/src/proposals/vtransfer-echoer.js',
getManifestCall: [
'getManifestForVtransferEchoer',
{
target: 'agoric1vtransfertest',
},
],
});

export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);
await writeCoreProposal('test-vtransfer', defaultProposalBuilder);
};
2 changes: 1 addition & 1 deletion packages/vats/src/bridge-target.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { Fail } = assert;

/**
* @typedef {object} App
* @property {(obj: any) => Promise<void>} upcall
* @property {(obj: any) => Promise<unknown>} upcall
*/
export const AppI = M.interface('App', {
upcall: M.call(M.any()).returns(M.promise()),
Expand Down
44 changes: 44 additions & 0 deletions packages/vats/src/proposals/vtransfer-echoer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// @ts-check
import { makeExo } from '@agoric/store';
import { E } from '@endo/far';

/**
* @param {BootstrapPowers & {
* consume: {
* transferMiddleware: import('../vat-transfer.js').TransferMiddleware;
* };
* }} powers
* @param {object} options
* @param {{ target: string }} options.options
*/
export const echoVtransfer = async (
{ consume: { transferMiddleware } },
{ options: { target } },
) => {
console.warn(`=== vtransfer echoer targeting ${target}`);

// a tap that simply returns what it received
const tap = makeExo('echoer', undefined, {
// ack value must be stringlike
upcall: async param => JSON.stringify(param),
});

// TODO put something in promise space to unregister this one and register again
// or maybe put all imperative stuff into promise space
await E(transferMiddleware).intercept(target, tap);

console.warn('=== vtransfer echoer registered');
};

export const getManifestForVtransferEchoer = (_powers, { target }) => ({
manifest: {
[echoVtransfer.name]: {
consume: {
transferMiddleware: 'transferMiddleware',
},
},
},
options: {
target,
},
});
4 changes: 3 additions & 1 deletion packages/vats/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ export type ScopedBridgeManager<BridgeId extends BridgeIdValue> = Guarded<{
* system to hang the bridgeId
*/
getBridgeId?: () => BridgeId;
/** Downcall from the VM into Golang */
toBridge: (obj: any) => Promise<any>;
fromBridge: (obj: any) => PromiseVow<void>;
/** Upcall from Golang into the VM */
fromBridge: (obj: any) => Promise<unknown>;
initHandler: (handler: Remote<BridgeHandler>) => void;
setHandler: (handler: Remote<BridgeHandler>) => void;
}>;
Expand Down
1 change: 1 addition & 0 deletions packages/vats/src/vat-transfer.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ export const buildRootObject = (_vatPowers, _args, baggage) => {
};

/** @typedef {ReturnType<typeof buildRootObject>} TransferVat */
/** @typedef {ReturnType<TransferVat['makeTransferMiddleware']>} TransferMiddleware */

0 comments on commit 42b2e7e

Please sign in to comment.