Skip to content

Commit

Permalink
chore(bootstrap-exports): test provisioningHandler is now durable, im…
Browse files Browse the repository at this point in the history
…prove logging

Refs: #10425
Refs: #8849
  • Loading branch information
anilhelvaci committed Nov 20, 2024
1 parent ff167e4 commit 0096916
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 1 deletion.
159 changes: 159 additions & 0 deletions packages/boot/test/bootstrapTests/replace-provisioningHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* @file The goal here is to showcase bootstrap vat exports a durable provisioningHandler
* object after replacing it. Related issues are #10425, #8849.
*
* Test "audit bootstrap exports" is copied from vaults-upgrade.test.js but tweaked to
* trigger a GC sweep and specifically check for the iface "provisioningHandler" belongs
* to a durable object.
*/

import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';
import type { TestFn } from 'ava';
import { Far, makeMarshal } from '@endo/marshal';
import {
makeLiquidationTestContext,
type LiquidationTestContext,
} from '../../tools/liquidation.js';

const test = anyTest as TestFn<LiquidationTestContext>;

test.before(async t => {
const context = await makeLiquidationTestContext(t);

t.context = {
...context,
};
});

test.serial('run replace-provisioningHandler core eval', async t => {
const { buildProposal, evalProposal } = t.context;
const proposal = await buildProposal(
'@agoric/builders/scripts/vats/replace-provisioningHandler.js',
);

await evalProposal(proposal);
t.pass();
});

test.serial('audit bootstrap exports', async t => {
const expected = {
maxExports: 5,
maxNonDurable: 4,
ifaces: {
durable: {
// in bridgeProvisioner()
provisioningHandler: true,
},
nonDurable: {
// in bridgeCoreEval()
coreHandler: true,
'prioritySenders manager': true,
// TODO? move to provisioning vat?
clientCreator: true,
},
},
};

const { controller } = t.context;

// Schedule a GC run and wait until it completes before dumping the state
controller.reapAllVats();
await controller.run();

const kState = controller.dump();

const myVatID = 'v1';

const myPromises = kState.promises.filter(
// @ts-expect-error kernel.dump() .promises type is wrong
p => p.decider === myVatID,
);
t.true(myPromises.length <= 1, 'bootstrap is the decider of only its return');

const myExports = kState.kernelTable.filter(
o => o[1] === myVatID && o[2].startsWith('o+'),
);
const v1VatTable =
kState.vatTables.find(vt => vt.vatID === myVatID) || assert.fail();
const { transcript } = v1VatTable.state;

const oids = new Set(myExports.map(o => o[2]));
const oidsDurable = [...oids].filter(o => o.startsWith('o+d'));
t.log(
'bootstrap exports:',
oidsDurable.length,
'durable',
oids.size - oidsDurable.length,
'non-durable',
oids.size,
'total',
);
t.true(oids.size <= expected.maxExports, 'too many exports');
t.true(
oids.size - oidsDurable.length <= expected.maxNonDurable,
'too many non-durable',
);

// Map oid to iface by poring over transcript syscalls
const toIface = new Map();
const anObj = Far('obj', {});
const aPromise = harden(new Promise(() => {}));
const saveBootstrapIface = (slot, iface) => {
if (slot.startsWith('p')) return aPromise;
if (oids.has(slot)) {
toIface.set(slot, iface);
}
return anObj;
};
const m = makeMarshal(undefined, saveBootstrapIface);
for (const oid of oids) {
for (const [_ix, ev] of transcript) {
for (const sc of ev.sc) {
if (sc.s[0] === 'send') {
const { methargs } = sc.s[2];
if (!methargs.slots.includes(oid)) continue;
m.fromCapData(methargs);
break;
} else if (sc.s[0] === 'resolve') {
for (const res of sc.s[1]) {
const capdata = res[2];
if (!capdata.slots.includes(oid)) continue;
m.fromCapData(capdata);
break;
}
}
}
}
}

for (const [key, value] of toIface.entries()) {
t.log('IFACE_VAL', key, value);
}

const exportedInterfacesNonDurable = Object.fromEntries(
[...toIface.entries()]
.filter(([slot, _]) => !slot.startsWith('o+d'))
.map(([_, iface]) => [iface.replace(/^Alleged: /, ''), true]),
);

const exportedInterfacesDurable = Object.fromEntries(
[...toIface.entries()]
.filter(([slot, _]) => slot.startsWith('o+d'))
.map(([_, iface]) => [iface.replace(/^Alleged: /, ''), true]),
);

t.deepEqual(
exportedInterfacesNonDurable,
expected.ifaces.nonDurable,
'expected non-durable interfaces',
);
t.deepEqual(
exportedInterfacesDurable,
expected.ifaces.durable,
'expected durable interfaces',
);
t.true(
oids.size - oidsDurable.length <= expected.maxNonDurable,
'too many non-durable',
);
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { E } from '@endo/far';
import { makeTracer } from '@agoric/internal';
import { prepareProvisionBridgeHandler } from '../lib-provisioning.js';

const convertProvisioningHandlerDurable = async ({
const trace = makeTracer('ReplaceProvisioningHandler');

export const convertProvisioningHandlerDurable = async ({
consume: {
provisioning: provisioningP,
provisionBridgeManager: provisionBridgeManagerP,
provisionWalletBridgeManager: provisionWalletBridgeManagerP,
powerStore: powerStoreP,
},
}) => {
trace('start core eval for replacing provisioningHandler with a durable one');

const [
provisioning,
provisionBridgeManager,
Expand All @@ -20,21 +25,33 @@ const convertProvisioningHandlerDurable = async ({
provisionWalletBridgeManagerP,
powerStoreP,
]);
trace('Powers awaited', {
provisionBridgeManager,
provisioning,
provisionWalletBridgeManager,
powerStore,
});
if (!provisionBridgeManager || !provisionWalletBridgeManager) {
return;
}

// Using powerStore as the durable map here
trace('building the exo object');
const makeProvisionBridgeHandler = prepareProvisionBridgeHandler(powerStore);
const provisioningHandler = makeProvisionBridgeHandler(
provisioning,
provisionWalletBridgeManager,
);

trace('setting handler');
const handler = provisioning
? provisioningHandler
: provisionWalletBridgeManager;

trace('new handler:', handler);
await E(provisionBridgeManager).setHandler(handler);

trace('Done.');
};

export const getConvertProvisioningHandlerDurable = _powers => ({
Expand Down

0 comments on commit 0096916

Please sign in to comment.