Skip to content

Commit

Permalink
chore: refactor based on review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
FUDCo committed Oct 7, 2023
1 parent 3f2f5b9 commit 0fa53ac
Show file tree
Hide file tree
Showing 23 changed files with 260 additions and 451 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/test-all-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,6 @@ jobs:
- name: yarn test (swing-store)
if: (success() || failure())
run: cd packages/swing-store && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT
- name: yarn test (test-support)
if: (success() || failure())
run: cd packages/test-support && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT
- name: yarn test (cosmic-proto)
if: (success() || failure())
run: cd packages/cosmic-proto && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT
Expand Down
1 change: 1 addition & 0 deletions packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@endo/patterns": "^0.2.5",
"@endo/promise-kit": "^0.2.59",
"@endo/ses-ava": "^0.2.43",
"@endo/stream": "^0.3.28",
"@endo/zip": "^0.2.34",
"ansi-styles": "^6.2.1",
"anylogger": "^0.21.0",
Expand Down
156 changes: 156 additions & 0 deletions packages/SwingSet/tools/run-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* eslint-disable @jessie.js/safe-await-separator */
import { Fail, q } from '@agoric/assert';
import { kunser } from '@agoric/kmarshal';
import { makeQueue } from '@endo/stream';
import type { E } from '@endo/eventual-send';

import type { SwingsetController } from '../src/controller/controller.js';

const sink = () => {};

export const makeRunUtils = (
controller: SwingsetController,
log = (..._) => {},
) => {
let cranksRun = 0;

const mutex = makeQueue();

mutex.put(controller.run());

const runThunk = async <T extends () => any>(
thunk: T,
): Promise<ReturnType<T>> => {
try {
// this promise for the last lock may fail
await mutex.get();
} catch {
// noop because the result will resolve for the previous runMethod return
}

const thunkResult = await thunk();

const result = controller.run().then(cranks => {
cranksRun += cranks;
log(`kernel ran ${cranks} cranks`);
return thunkResult;
});
mutex.put(result.then(sink, sink));
return result;
};

const queueAndRun = async (deliveryThunk, voidResult = false) => {
log('queueAndRun at', cranksRun);

const kpid = await runThunk(deliveryThunk);

if (voidResult) {
return undefined;
}
const status = controller.kpStatus(kpid);
switch (status) {
case 'fulfilled':
return kunser(controller.kpResolution(kpid));
case 'rejected':
throw kunser(controller.kpResolution(kpid));
case 'unresolved':
throw Fail`unsettled value for ${q(kpid)}`;
default:
throw Fail`unknown promise status ${q(kpid)} ${q(status)}`;
}
};

type EVProxy = typeof E & {
sendOnly: (presence: unknown) => Record<string, (...args: any) => void>;
vat: (name: string) => Record<string, (...args: any) => Promise<any>>;
};

// IMPORTANT WARNING TO USERS OF `EV`
//
// `EV` presents an abstraction that can be used (within tests only!) to get
// much of the convenience with respect to messaging that `E` provides in
// normal code. However, this convenience comes with a huge caveat that all
// users of this convenience feature MUST keep in mind.
//
// A test can drop messages onto the kernel's run queue using the
// `controller.queueToVatRoot` and `controller.queueToVatObject` methods.
// These are synchronous operations which merely place messages onto the run
// queue without causing execution. Execution, on the other hand, is
// initiated by calling `controller.run`, which will cause the kernel to begin
// delivering messages to vats from the run queue, continuing until the run
// queue is exhausted. HOWEVER, exhaustion of the run queue, which resolves
// the result promise returned by the `run` call, IS NOT coupled in any causal
// way to the resolution of result promises associated with the individual
// queued messages themselves. The status and resolution values of these
// promises can be synchronously queried (by kpid) via the
// `controller.kpStatus` and `controller.kpResolution` methods once `run` has
// completed. These queries are only available once the swingset has
// reqlinquished agency, i.e., when the work initiated by `controller.run` has
// finished. At that point, nothing is going on inside the kernel, and
// nothing WILL be going on inside the kernel until a subsequent call to
// `controller.run`, which in turn will only have an effect if additional
// messages have been placed on the kernel run queue in the meantime. You MAY
// NOT call `queueToVatRoot`, `queueToVatObject`, `kpStatus`, or
// `kpResolution` while run queue execution, triggered by a call to `run`, is
// in progress
//
// The functionality made available by `EV` looks similar to that provided by
// `E`, but it is very much not. When you send a message using `EV`, it
// places the message onto the kernel run queue and then immediately invokes
// `controller.run`. When the result of `run` resolves, the kpid returned by
// the message enqueueing operation is queried. If at that time the promise
// it identifies is resolved (or rejected), the value it was resolved (or
// rejected) to is used as the result from the `EV` invocation. However, if
// it is still pending at that time, `EV` will throw an exception, which will
// manifest as a rejection and your test will fail confusingly or abort. This
// means that if you initiate some operation via an `EV` message send, it must
// complete within a single `run` cycle for it to be of any use to you. This
// is quite different from a message sent using `E`, which will return a
// promise that can remain pending indefinitely, possibly to be settled by a
// future message delivery.

// @ts-expect-error cast, approximate
const EV: EVProxy = presence =>
new Proxy(harden({}), {
get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(() =>
controller.queueToVatObject(presence, method, args),
);
return harden(boundMethod);
},
});
EV.vat = vatName =>
new Proxy(harden({}), {
get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(() => controller.queueToVatRoot(vatName, method, args));
return harden(boundMethod);
},
});
// @ts-expect-error xxx
EV.sendOnly = presence =>
new Proxy(harden({}), {
get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(
() => controller.queueToVatObject(presence, method, args),
true,
);
return harden(boundMethod);
},
});
// @ts-expect-error xxx
EV.get = presence =>
new Proxy(harden({}), {
get: (_t, pathElement, _rx) =>
queueAndRun(() =>
controller.queueToVatRoot('bootstrap', 'awaitVatObject', [
presence,
[pathElement],
]),
),
});
return harden({ runThunk, EV });
};
export type RunUtils = ReturnType<typeof makeRunUtils>;
1 change: 0 additions & 1 deletion packages/agoric-cli/src/sdk-package-names.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export default [
"@agoric/swingset-vat",
"@agoric/swingset-xsnap-supervisor",
"@agoric/telemetry",
"@agoric/test-support",
"@agoric/time",
"@agoric/vat-data",
"@agoric/vats",
Expand Down
70 changes: 70 additions & 0 deletions packages/benchmark/benchmark/benchmark-vault-adjust.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { bench } from '../src/benchmarkerator.js';

// eslint-disable-next-line import/order
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';

const collateralBrandKey = 'ATOM';
const adjustOpenOfferId = 'adjust-open';

// The benchmark-defined option `size` (default 1) indicates how many operations
// will be performed per round. The difference between performing 10 rounds of
// 1 operation each (command line: `--rounds 10`) and performing 1 round of 10
// operations (command line: `-o size 10`) is that while both will perform 10
// operations, in the first case the 10 operations will be done sequentially
// while in the second case they will be done concurrently. These are two
// different modes you might want to measure. (Of course, you could do 10
// rounds of 10 operations each: `--rounds 10 -o size 10`, and that would work
// fine also.)

bench.addBenchmark('adjust vault balance', {
setup: async context => {
const { alice } = context.actors;

await alice.executeOfferMaker(Offers.vaults.OpenVault, {
offerId: adjustOpenOfferId,
collateralBrandKey,
wantMinted: 5.0,
giveCollateral: 9.0,
});
const upd = alice.getLatestUpdateRecord();
assert(
upd.updated === 'offerStatus' &&
upd.status.id === adjustOpenOfferId &&
upd.status.numWantsSatisfied === 1,
);
return undefined;
},

executeRound: async (context, round) => {
const { alice } = context.actors;

const adjustVault = async (i, n, r) => {
const offerId = `adjust-vault-${i}-of-${n}=round-${r}`;
await alice.executeOfferMaker(
Offers.vaults.AdjustBalances,
{
offerId,
collateralBrandKey,
giveMinted: 0.0005,
},
adjustOpenOfferId,
);
const upd = alice.getLatestUpdateRecord();
assert(
upd.updated === 'offerStatus' &&
upd.status.id === offerId &&
upd.status.numWantsSatisfied === 1,
);
};

const adjustN = async n => {
const range = [...Array(n)].map((_, i) => i + 1);
await Promise.all(range.map(i => adjustVault(i, n, round)));
};

const roundSize = context.options.size ? Number(context.options.size) : 1;
await adjustN(roundSize);
},
});

await bench.run('vault-adjust');
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { bench } from '@agoric/benchmark';
import { bench } from '../src/benchmarkerator.js';

// eslint-disable-next-line import/order
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';

const collateralBrandKey = 'ATOM';

bench.addBenchmark('vault open', {
bench.addBenchmark('open vault', {
executeRound: async (context, round) => {
const { alice } = context.actors;

Expand Down Expand Up @@ -36,4 +36,4 @@ bench.addBenchmark('vault open', {
},
});

await bench.run('vaults');
await bench.run('vault-open');
2 changes: 1 addition & 1 deletion packages/benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
"license": "Apache-2.0",
"dependencies": {
"@agoric/assert": "^0.6.0",
"@agoric/boot": "^0.1.0",
"@agoric/cosmic-swingset": "^0.41.3",
"@agoric/internal": "^0.3.2",
"@agoric/inter-protocol": "^0.16.1",
"@agoric/test-support": "^0.1.0",
"@agoric/vats": "^0.15.1",
"@agoric/zoe": "^0.26.2",
"@endo/init": "^0.5.59"
Expand Down
8 changes: 3 additions & 5 deletions packages/benchmark/src/benchmarkerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import '@agoric/cosmic-swingset/src/launch-chain.js';
import { Fail } from '@agoric/assert';
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
import { makeAgoricNamesRemotesFromFakeStorage } from '@agoric/vats/tools/board-utils.js';
import {
makeSwingsetTestKit,
makeWalletFactoryDriver,
} from '@agoric/test-support';
import { makeSwingsetTestKit } from '@agoric/boot/tools/supports.ts';
import { makeWalletFactoryDriver } from '@agoric/boot/tools/drivers.ts';

// When I was a child my family took a lot of roadtrips around California to go
// camping and backpacking and so on. It was not uncommon in those days (nor is
Expand Down Expand Up @@ -46,7 +44,7 @@ import {
* @typedef {{
* options: Record<string, string>,
* argv: string[],
* actors: Record<string, import('@agoric/test-support').SmartWalletDriver>,
* actors: Record<string, import('@agoric/boot/tools/drivers.ts').SmartWalletDriver>,
* title?: string,
* rounds?: number,
* config?: Record<string, unknown>,
Expand Down
2 changes: 2 additions & 0 deletions packages/benchmark/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"*.js",
"scripts/**/*.js",
"src/**/*.js",
"benchmark/**/*.js",
"benchmark/**/*.ts",
"test/**/*.js",
"test/**/*.ts",
"tools/**/*.js",
Expand Down
17 changes: 7 additions & 10 deletions packages/boot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"build": "exit 0",
"test": "ava",
"test:xs": "SWINGSET_WORKER_TYPE=xs-worker ava 'test/bootstrapTests/**/test-*.js' 'test/upgrading/**/test-*.js'",
"bench": "ava --config ./ava.bench.config.js",
"lint-fix": "yarn lint:eslint --fix",
"lint": "run-s --continue-on-error lint:*",
"lint:types": "tsc",
Expand All @@ -19,9 +18,16 @@
"author": "Agoric",
"license": "Apache-2.0",
"dependencies": {
"@agoric/assert": "^0.6.0",
"@agoric/builders": "^0.1.0",
"@agoric/cosmic-swingset": "^0.41.3",
"@agoric/ertp": "^0.16.2",
"@agoric/internal": "^0.3.2",
"@agoric/inter-protocol": "^0.16.1",
"@agoric/kmarshal": "^0.1.0",
"@agoric/swing-store": "^0.9.1",
"@agoric/swingset-vat": "^0.32.2",
"@agoric/time": "^0.3.2",
"@agoric/vat-data": "^0.5.2",
"@agoric/vats": "^0.15.1",
"@agoric/vm-config": "^0.1.0",
Expand All @@ -37,19 +43,10 @@
"import-meta-resolve": "^2.2.1"
},
"devDependencies": {
"@agoric/assert": "^0.6.0",
"@agoric/benchmark": "^0.1.0",
"@agoric/cosmic-swingset": "^0.41.3",
"@agoric/deploy-script-support": "^0.10.3",
"@agoric/governance": "^0.10.3",
"@agoric/inter-protocol": "^0.16.1",
"@agoric/kmarshal": "^0.1.0",
"@agoric/store": "^0.9.2",
"@agoric/swing-store": "^0.9.1",
"@agoric/swingset-liveslots": "^0.10.2",
"@agoric/swingset-vat": "^0.32.2",
"@agoric/test-support": "^0.1.0",
"@agoric/time": "^0.3.2",
"ava": "^5.3.0",
"c8": "^7.13.0",
"tsx": "^3.12.8"
Expand Down
Loading

0 comments on commit 0fa53ac

Please sign in to comment.