diff --git a/packages/boot/test/bootstrapTests/ibcBridgeMock.js b/packages/boot/test/bootstrapTests/ibcBridgeMock.js deleted file mode 100644 index 0f20af5162a..00000000000 --- a/packages/boot/test/bootstrapTests/ibcBridgeMock.js +++ /dev/null @@ -1,60 +0,0 @@ -// @ts-check -import { - makePinnedHistoryTopic, - prepareDurablePublishKit, - subscribeEach, -} from '@agoric/notifier'; -import { M } from '@endo/patterns'; -import { makeScalarBigMapStore } from '@agoric/vat-data'; -import { makeDurableZone } from '@agoric/zone/durable.js'; - -// TODO: factor out overlap with packages/vats/test/network.test.js -export const makeBridge = ( - t, - baggage = makeScalarBigMapStore('baggage', { - keyShape: M.string(), - durable: true, - }), - zone = makeDurableZone(baggage), -) => { - const makeDurablePublishKit = prepareDurablePublishKit( - baggage, - 'DurablePublishKit', - ); - - const { subscriber, publisher } = makeDurablePublishKit(); - - const pinnedHistoryTopic = makePinnedHistoryTopic(subscriber); - const events = subscribeEach(pinnedHistoryTopic)[Symbol.asyncIterator](); - - let hndlr; - /** @type {import('@agoric/vats/src/types.js').ScopedBridgeManager} */ - const bridgeHandler = zone.exo('IBC Bridge Manager', undefined, { - toBridge: async obj => { - const { method, type, ...params } = obj; - publisher.publish([method, params]); - t.is(type, 'IBC_METHOD'); - if (method === 'sendPacket') { - const { packet } = params; - return { ...packet, sequence: '39' }; - } - return undefined; - }, - fromBridge: async obj => { - if (!hndlr) throw Error('no handler!'); - // EV must be late-bound; it is not availble at bridge construction time. - const { EV } = t.context.runutils; - await EV(hndlr).fromBridge(obj); - }, - initHandler: h => { - if (hndlr) throw Error('already init'); - hndlr = h; - }, - setHandler: h => { - if (!hndlr) throw Error('must init first'); - hndlr = h; - }, - }); - - return { bridgeHandler, events }; -}; diff --git a/packages/boot/test/bootstrapTests/net-ibc-upgrade.test.ts b/packages/boot/test/bootstrapTests/net-ibc-upgrade.test.ts index 3ac734c684f..47dcc7d963c 100644 --- a/packages/boot/test/bootstrapTests/net-ibc-upgrade.test.ts +++ b/packages/boot/test/bootstrapTests/net-ibc-upgrade.test.ts @@ -1,13 +1,15 @@ /** @file upgrade network / IBC vat at many points in state machine */ -import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; -import { createRequire } from 'module'; -import type { TestFn } from 'ava'; -import type { BridgeHandler } from '@agoric/vats'; import { BridgeId } from '@agoric/internal'; +import type { BridgeHandler } from '@agoric/vats'; +import { makeFakeIbcBridge } from '@agoric/vats/tools/fake-bridge.js'; +import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { makeNodeBundleCache } from '@endo/bundle-source/cache.js'; -// import { E } from '@endo/eventual-send'; -import { V as E } from '@agoric/vow/vat.js'; -import { makeBridge } from './ibcBridgeMock.js'; +import type { TestFn } from 'ava'; +import { createRequire } from 'module'; + +import type { Baggage } from '@agoric/swingset-liveslots'; +import { M, makeScalarBigMapStore } from '@agoric/vat-data'; +import { makeDurableZone } from '@agoric/zone/durable.js'; import { makeSwingsetTestKit } from '../../tools/supports.ts'; const { entries, assign } = Object; @@ -22,7 +24,13 @@ const asset = { export const makeTestContext = async t => { console.time('DefaultTestContext'); - const { bridgeHandler, events } = makeBridge(t); + + const baggage = makeScalarBigMapStore('baggage', { + keyShape: M.string(), + durable: true, + }) as Baggage; + const zone = makeDurableZone(baggage); + const bundleDir = 'bundles/vaults'; const bundleCache = await makeNodeBundleCache( bundleDir, @@ -31,9 +39,6 @@ export const makeTestContext = async t => { ); const swingsetTestKit = await makeSwingsetTestKit(t.log, bundleDir, { configSpecifier: PLATFORM_CONFIG, - bridgeHandlers: { - [BridgeId.DIBC]: obj => bridgeHandler.toBridge(obj), - }, }); console.timeLog('DefaultTestContext', 'swingsetTestKit'); diff --git a/packages/boot/test/bootstrapTests/vats-restart.test.ts b/packages/boot/test/bootstrapTests/vats-restart.test.ts index bd1f3340fef..fd3c35ef96f 100644 --- a/packages/boot/test/bootstrapTests/vats-restart.test.ts +++ b/packages/boot/test/bootstrapTests/vats-restart.test.ts @@ -110,7 +110,7 @@ test.serial('make IBC callbacks before upgrade', async t => { const vatStore = await EV.vat('bootstrap').consumeItem('vatStore'); const { root: ibc } = await EV(vatStore).get('ibc'); t.log('E(ibc).makeCallbacks(m1)'); - const dummyBridgeManager = null as unknown as ScopedBridgeManager; + const dummyBridgeManager = null as unknown as ScopedBridgeManager; const callbacks = await EV(ibc).makeCallbacks(dummyBridgeManager); t.truthy(callbacks); t.context.shared.ibcCallbacks = callbacks; diff --git a/packages/boot/tools/supports.ts b/packages/boot/tools/supports.ts index 882a4b14073..ee211d1c89a 100644 --- a/packages/boot/tools/supports.ts +++ b/packages/boot/tools/supports.ts @@ -249,7 +249,6 @@ export const matchIter = (t: AvaT, iter, valueRef) => { * @param [options.profileVats] * @param [options.debugVats] * @param [options.defaultManagerType] - * @param [options.bridgeHandlers] */ export const makeSwingsetTestKit = async ( log: (..._: any[]) => void, @@ -262,7 +261,6 @@ export const makeSwingsetTestKit = async ( profileVats = [] as string[], debugVats = [] as string[], defaultManagerType = 'local' as ManagerType, - bridgeHandlers = {} as Record unknown>, } = {}, ) => { console.time('makeBaseSwingsetTestKit'); @@ -305,9 +303,6 @@ export const makeSwingsetTestKit = async ( } outboundMessages.get(bridgeId).push(obj); - if (bridgeId in bridgeHandlers) { - return bridgeHandlers[bridgeId](obj); - } switch (bridgeId) { case BridgeId.BANK: { trace( diff --git a/packages/inter-protocol/test/smartWallet/contexts.js b/packages/inter-protocol/test/smartWallet/contexts.js index a2cb53e6919..99dd01ef4f1 100644 --- a/packages/inter-protocol/test/smartWallet/contexts.js +++ b/packages/inter-protocol/test/smartWallet/contexts.js @@ -104,6 +104,11 @@ export const makeDefaultTestContext = async (t, makeSpace) => { 'anyAddress', ); const bridgeManager = await consume.bridgeManager; + /** + * @type {| undefined + * | import('@agoric/vats').ScopedBridgeManager<'wallet'>} + */ + // @ts-expect-error XXX EProxy const walletBridgeManager = await (bridgeManager && E(bridgeManager).register(BridgeId.WALLET)); const walletFactory = await E(zoe).startInstance( diff --git a/packages/internal/src/config.js b/packages/internal/src/config.js index 2a68eb09c97..e401317d15c 100644 --- a/packages/internal/src/config.js +++ b/packages/internal/src/config.js @@ -14,7 +14,7 @@ /** * Event source ids used by the bridge device. */ -export const BridgeId = { +export const BridgeId = /** @type {const} */ ({ BANK: 'bank', CORE: 'core', DIBC: 'dibc', @@ -24,8 +24,9 @@ export const BridgeId = { VLOCALCHAIN: 'vlocalchain', VTRANSFER: 'vtransfer', WALLET: 'wallet', -}; +}); harden(BridgeId); +/** @typedef {(typeof BridgeId)[keyof typeof BridgeId]} BridgeIdValue */ export const CosmosInitKeyToBridgeId = { vbankPort: BridgeId.BANK, diff --git a/packages/orchestration/test/examples/swapExample.test.ts b/packages/orchestration/test/examples/swapExample.test.ts index b989dd49d4a..86b364bf441 100644 --- a/packages/orchestration/test/examples/swapExample.test.ts +++ b/packages/orchestration/test/examples/swapExample.test.ts @@ -9,7 +9,7 @@ import { makeHeapZone } from '@agoric/zone'; import { prepareLocalChainTools } from '@agoric/vats/src/localchain.js'; import { buildRootObject as buildBankVatRoot } from '@agoric/vats/src/vat-bank.js'; import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; -import { makeBridge } from '../supports.js'; +import { makeFakeLocalchainBridge } from '../supports.js'; const dirname = path.dirname(new URL(import.meta.url).pathname); @@ -34,11 +34,11 @@ test('start', async t => { await E(bankManager).addAsset('uist', 'IST', 'Inter Stable Token', issuerKit); - const fakeBridgeKit = makeBridge(t); + const localchainBridge = makeFakeLocalchainBridge(zone); const localchain = makeLocalChain({ bankManager, - system: fakeBridgeKit.bridgeHandler, + system: localchainBridge, }); const storage = makeFakeStorageKit('mockChainStorageRoot', { diff --git a/packages/orchestration/test/examples/unbondExample.test.ts b/packages/orchestration/test/examples/unbondExample.test.ts index e79376c72d3..eebe0bcb930 100644 --- a/packages/orchestration/test/examples/unbondExample.test.ts +++ b/packages/orchestration/test/examples/unbondExample.test.ts @@ -9,7 +9,7 @@ import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; import { makeHeapZone } from '@agoric/zone'; import { E } from '@endo/far'; import path from 'path'; -import { makeBridge } from '../supports.js'; +import { makeFakeLocalchainBridge } from '../supports.js'; const dirname = path.dirname(new URL(import.meta.url).pathname); @@ -34,11 +34,11 @@ test('start', async t => { await E(bankManager).addAsset('uist', 'IST', 'Inter Stable Token', issuerKit); - const fakeBridgeKit = makeBridge(t); + const localchainBridge = makeFakeLocalchainBridge(zone); const localchain = makeLocalChain({ bankManager, - system: fakeBridgeKit.bridgeHandler, + system: localchainBridge, }); const storage = makeFakeStorageKit('mockChainStorageRoot', { diff --git a/packages/orchestration/test/supports.ts b/packages/orchestration/test/supports.ts index da8af128eac..7e8600ad2f4 100644 --- a/packages/orchestration/test/supports.ts +++ b/packages/orchestration/test/supports.ts @@ -1,66 +1 @@ -import { Fail } from '@agoric/assert'; -import type { ScopedBridgeManager } from '@agoric/vats'; - -import { - makePinnedHistoryTopic, - prepareDurablePublishKit, - subscribeEach, -} from '@agoric/notifier'; -import type { Baggage } from '@agoric/swingset-liveslots'; -import { M, makeScalarBigMapStore } from '@agoric/vat-data'; -import { makeDurableZone } from '@agoric/zone/durable.js'; -import type { ExecutionContext } from 'ava'; - -// TODO DRY with ibcBridgeMock.js in package boot -export const makeBridge = ( - t: ExecutionContext, - baggage = makeScalarBigMapStore('baggage', { - keyShape: M.string(), - durable: true, - }) as Baggage, - zone = makeDurableZone(baggage), -) => { - const makeDurablePublishKit = prepareDurablePublishKit( - baggage, - 'DurablePublishKit', - ); - - const { subscriber, publisher } = makeDurablePublishKit(); - - const pinnedHistoryTopic = makePinnedHistoryTopic(subscriber); - const events = subscribeEach(pinnedHistoryTopic)[Symbol.asyncIterator](); - - let hndlr; - - const bridgeHandler: ScopedBridgeManager = zone.exo( - 'IBC Bridge Manager', - undefined, - { - toBridge: async obj => { - const { method, type, ...params } = obj; - publisher.publish([method, params]); - console.info('toBridge', type, method, params); - switch (type) { - case 'VLOCALCHAIN_ALLOCATE_ADDRESS': - return 'agoric1fixme'; - default: - Fail`unknown type ${type}`; - } - return undefined; - }, - fromBridge: async obj => { - console.info('fromBridge', obj); - }, - initHandler: h => { - if (hndlr) throw Error('already init'); - hndlr = h; - }, - setHandler: h => { - if (!hndlr) throw Error('must init first'); - hndlr = h; - }, - }, - ); - - return { bridgeHandler, events }; -}; +export { makeFakeLocalchainBridge } from '@agoric/vats/tools/fake-bridge.js'; diff --git a/packages/smart-wallet/src/walletFactory.js b/packages/smart-wallet/src/walletFactory.js index 9a751d74929..41c40f9f35b 100644 --- a/packages/smart-wallet/src/walletFactory.js +++ b/packages/smart-wallet/src/walletFactory.js @@ -142,7 +142,7 @@ export const makeAssetRegistry = assetPublisher => { * @param {ZCF} zcf * @param {{ * storageNode: ERef, - * walletBridgeManager?: ERef, + * walletBridgeManager?: ERef>, * walletReviver?: ERef, * }} privateArgs * @param {import('@agoric/vat-data').Baggage} baggage diff --git a/packages/smart-wallet/test/contexts.js b/packages/smart-wallet/test/contexts.js index 728c64a090a..a5e67942439 100644 --- a/packages/smart-wallet/test/contexts.js +++ b/packages/smart-wallet/test/contexts.js @@ -38,6 +38,8 @@ export const makeDefaultTestContext = async (t, makeSpace) => { 'anyAddress', ); const bridgeManager = await consume.bridgeManager; + /** @type {import('@agoric/vats').ScopedBridgeManager<'wallet'>} */ + // @ts-expect-error XXX generics through EProxy const walletBridgeManager = await (bridgeManager && E(bridgeManager).register(BridgeId.WALLET)); const walletFactory = await E(zoe).startInstance( diff --git a/packages/smart-wallet/test/supports.js b/packages/smart-wallet/test/supports.js index 429be3242db..007c2ac39cf 100644 --- a/packages/smart-wallet/test/supports.js +++ b/packages/smart-wallet/test/supports.js @@ -63,9 +63,13 @@ export const subscriptionKey = subscription => { /** @returns {import('@agoric/vats').BridgeManager} */ const makeFakeBridgeManager = () => + // @ts-expect-error XXX generics puzzle: could be instantiated with a different subtype of constraint Far('fakeBridgeManager', { register(bridgeId, handler) { return Far('scopedBridgeManager', { + getBridgeId() { + return bridgeId; + }, fromBridge(_obj) { assert.fail(`expected fromBridge`); }, diff --git a/packages/vats/src/core/basic-behaviors.js b/packages/vats/src/core/basic-behaviors.js index 947b399bf21..a8592295d6c 100644 --- a/packages/vats/src/core/basic-behaviors.js +++ b/packages/vats/src/core/basic-behaviors.js @@ -659,6 +659,8 @@ export const addBankAssets = async ({ const assetAdmin = E(agoricNamesAdmin).lookupAdmin('vbankAsset'); const bridgeManager = await bridgeManagerP; + /** @type {import('../types.js').ScopedBridgeManager<'bank'> | undefined} */ + // @ts-expect-error XXX EProxy const bankBridgeManager = bridgeManager && E(bridgeManager).register(BridgeId.BANK); const bankMgr = await E(E(loadCriticalVat)('bank')).makeBankManager( diff --git a/packages/vats/src/core/chain-behaviors.js b/packages/vats/src/core/chain-behaviors.js index f56b14b9f4f..48617e717b5 100644 --- a/packages/vats/src/core/chain-behaviors.js +++ b/packages/vats/src/core/chain-behaviors.js @@ -361,6 +361,8 @@ export const makeChainStorage = async ({ return; } + /** @type {import('../types.js').ScopedBridgeManager<'storage'>} */ + // @ts-expect-error XXX EProxy const storageBridgeManager = E(bridgeManager).register(BRIDGE_ID.STORAGE); storageBridgeManagerP.resolve(storageBridgeManager); diff --git a/packages/vats/src/core/startWalletFactory.js b/packages/vats/src/core/startWalletFactory.js index a2dd87df342..7a7a38eba94 100644 --- a/packages/vats/src/core/startWalletFactory.js +++ b/packages/vats/src/core/startWalletFactory.js @@ -70,8 +70,8 @@ const publishRevivableWalletState = async ( * >['creatorFacet']; * adminFacet: AdminFacet; * }; - * walletBridgeManager: import('../types.js').ScopedBridgeManager; - * provisionWalletBridgeManager: import('../types.js').ScopedBridgeManager; + * walletBridgeManager: import('../types.js').ScopedBridgeManager<'wallet'>; + * provisionWalletBridgeManager: import('../types.js').ScopedBridgeManager<'provisionWallet'>; * }>} powers * @param {{ * options?: { diff --git a/packages/vats/src/core/types-ambient.d.ts b/packages/vats/src/core/types-ambient.d.ts index 5d3daa5bc15..0cbf6bf7f4e 100644 --- a/packages/vats/src/core/types-ambient.d.ts +++ b/packages/vats/src/core/types-ambient.d.ts @@ -372,7 +372,9 @@ type ChainBootstrapSpaceT = { provisionWalletBridgeManager: | import('../types.js').ScopedBridgeManager | undefined; - storageBridgeManager: import('../types.js').ScopedBridgeManager | undefined; + storageBridgeManager: + | import('../types.js').ScopedBridgeManager<'storage'> + | undefined; /** * Convienence function for starting a contract (ungoverned) and saving its * facets (including adminFacet) diff --git a/packages/vats/src/ibc.js b/packages/vats/src/ibc.js index 334c264171a..e75e24afafc 100644 --- a/packages/vats/src/ibc.js +++ b/packages/vats/src/ibc.js @@ -814,7 +814,7 @@ export const prepareCallbacks = zone => { return zone.exoClass( 'callbacks', undefined, - /** @param {ScopedBridgeManager} dibcBridgeManager */ + /** @param {ScopedBridgeManager<'dibc'>} dibcBridgeManager */ dibcBridgeManager => ({ dibcBridgeManager }), { /** diff --git a/packages/vats/src/localchain.js b/packages/vats/src/localchain.js index eb1a6c7845b..09294b9f0d0 100644 --- a/packages/vats/src/localchain.js +++ b/packages/vats/src/localchain.js @@ -13,14 +13,14 @@ const { Fail } = assert; /** * @typedef {{ - * system: ScopedBridgeManager; + * system: ScopedBridgeManager<'vlocalchain'>; * bank: Bank; * }} AccountPowers */ /** * @typedef {{ - * system: ScopedBridgeManager; + * system: ScopedBridgeManager<'vlocalchain'>; * bankManager: BankManager; * }} LocalChainPowers */ diff --git a/packages/vats/src/proposals/localchain-proposal.js b/packages/vats/src/proposals/localchain-proposal.js index c45c6de5403..3d640fdfbdc 100644 --- a/packages/vats/src/proposals/localchain-proposal.js +++ b/packages/vats/src/proposals/localchain-proposal.js @@ -6,7 +6,7 @@ import { BridgeId as BRIDGE_ID } from '@agoric/internal'; * @param {BootstrapPowers & { * consume: { * loadCriticalVat: VatLoader; - * localchainBridgeManager: import('../types').ScopedBridgeManager; + * localchainBridgeManager: import('../types').ScopedBridgeManager<'vlocalchain'>; * }; * produce: { * localchain: Producer; @@ -51,9 +51,11 @@ export const setupLocalChainVat = async ( localchainVat.reset(); localchainVat.resolve(vats.localchain); - /** @type {import('../types').ScopedBridgeManager} */ + /** @type {import('../types').ScopedBridgeManager<'vlocalchain'>} */ let scopedManager; try { + /** @type {import('../types.js').ScopedBridgeManager<'vlocalchain'>} */ + // @ts-expect-error XXX EProxy scopedManager = await E(bridgeManager).register(BRIDGE_ID.VLOCALCHAIN); localchainBridgeManager.reset(); localchainBridgeManager.resolve(scopedManager); diff --git a/packages/vats/src/proposals/network-proposal.js b/packages/vats/src/proposals/network-proposal.js index 1972526d676..4691d9ebfc9 100644 --- a/packages/vats/src/proposals/network-proposal.js +++ b/packages/vats/src/proposals/network-proposal.js @@ -20,7 +20,7 @@ const NUM_IBC_PORTS_PER_CLIENT = 3; /** * @param {SoloVats | NetVats} vats - * @param {ERef} [dibcBridgeManager] + * @param {ERef>} [dibcBridgeManager] */ export const registerNetworkProtocols = async (vats, dibcBridgeManager) => { /** @type {Promise[]} */ @@ -130,6 +130,8 @@ export const setupNetworkProtocols = async ( const allocator = await portAllocatorP; const bridgeManager = await bridgeManagerP; + /** @type {import('../types.js').ScopedBridgeManager<'dibc'> | undefined} */ + // @ts-expect-error XXX EProxy const dibcBridgeManager = bridgeManager && E(bridgeManager).register(BRIDGE_ID.DIBC); diff --git a/packages/vats/src/types.d.ts b/packages/vats/src/types.d.ts index f91b4ae577e..f364d8f0bd7 100644 --- a/packages/vats/src/types.d.ts +++ b/packages/vats/src/types.d.ts @@ -2,6 +2,7 @@ import type { Bytes } from '@agoric/network'; import type { PromiseVow } from '@agoric/vow'; import type { Guarded } from '@endo/exo'; import type { ERef } from '@endo/far'; +import type { BridgeIdValue } from '@agoric/internal'; export type Board = ReturnType< ReturnType @@ -96,7 +97,13 @@ export type BridgeHandler = { }; /** An object which handles messages for a specific bridge */ -export type ScopedBridgeManager = Guarded<{ +export type ScopedBridgeManager = Guarded<{ + /** + * Optional bridge ID getter. Not part of the production bridge vat but + * available in fake bridges as a means for test reflection and for the type + * system to hang the bridgeId + */ + getBridgeId?: () => BridgeId; toBridge: (obj: any) => Promise; fromBridge: (obj: any) => PromiseVow; initHandler: (handler: ERef) => void; @@ -105,10 +112,10 @@ export type ScopedBridgeManager = Guarded<{ /** The object to manage this bridge */ export type BridgeManager = { - register: ( - bridgeId: string, + register: ( + bridgeId: BridgeId, handler?: ERef, - ) => ScopedBridgeManager; + ) => ScopedBridgeManager; }; export type IBCPortID = string; diff --git a/packages/vats/src/vat-bank.js b/packages/vats/src/vat-bank.js index b6289458565..023233746c9 100644 --- a/packages/vats/src/vat-bank.js +++ b/packages/vats/src/vat-bank.js @@ -52,7 +52,7 @@ const BalanceUpdaterI = M.interface('BalanceUpdater', { /** * @typedef {Pick< - * import('./types.js').ScopedBridgeManager, + * import('./types.js').ScopedBridgeManager, * 'fromBridge' | 'toBridge' * >} BridgeChannel */ @@ -863,7 +863,9 @@ export function buildRootObject(_vatPowers, _args, baggage) { return Far('bankMaker', { /** - * @param {ERef} [bankBridgeManagerP] + * @param {ERef< + * import('./types.js').ScopedBridgeManager<'bank'> | undefined + * >} [bankBridgeManagerP] * a bridge manager for the "remote" bank (such as on cosmos-sdk). If not * supplied (such as on sim-chain), we just use local purses. * @param {ERef<{ update: import('./types.js').NameAdmin['update'] }>} [nameAdminP] @@ -880,7 +882,7 @@ export function buildRootObject(_vatPowers, _args, baggage) { 'denomToAddressUpdater', ); - /** @param {ERef} [bankBridgeMgr] */ + /** @param {ERef>} [bankBridgeMgr] */ async function getBankChannel(bankBridgeMgr) { // We do the logic here if the bridge manager is available. Otherwise, // the bank is not "remote" (such as on sim-chain), so we just use diff --git a/packages/vats/src/vat-bridge.js b/packages/vats/src/vat-bridge.js index 1a5c00b3966..e18a80fea18 100644 --- a/packages/vats/src/vat-bridge.js +++ b/packages/vats/src/vat-bridge.js @@ -20,7 +20,7 @@ export function buildRootObject(vatPowers, _args, baggage) { ); /** - * @param {ERef} storageBridgeManagerP + * @param {ERef>} storageBridgeManagerP * @param {string} rootPath must be unique (caller responsibility to ensure) * @param {object} [options] */ diff --git a/packages/vats/test/localchain.test.js b/packages/vats/test/localchain.test.js index 1ce3144b5af..b960aac08cd 100644 --- a/packages/vats/test/localchain.test.js +++ b/packages/vats/test/localchain.test.js @@ -1,14 +1,16 @@ // @ts-check import { test as anyTest } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; + +import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; import { reincarnate } from '@agoric/swingset-liveslots/tools/setup-vat-data.js'; +import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; +import { makeDurableZone } from '@agoric/zone/durable.js'; import { E } from '@endo/far'; -import { M } from '@endo/patterns'; import { getInterfaceOf } from '@endo/marshal'; -import { makeDurableZone } from '@agoric/zone/durable.js'; -import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; -import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; -import { buildRootObject as buildBankVatRoot } from '../src/vat-bank.js'; +import { M } from '@endo/patterns'; import { prepareLocalChainTools } from '../src/localchain.js'; +import { buildRootObject as buildBankVatRoot } from '../src/vat-bank.js'; +import { makeFakeLocalchainBridge } from '../tools/fake-bridge.js'; /** * @import {LocalChainAccount, LocalChainPowers} from '../src/localchain.js'; @@ -25,41 +27,10 @@ const provideBaggage = key => { return zone.mapStore(`${key} baggage`); }; -// TODO use testing facilities from #9396 -const makeTestContext = async t => { - const makeBridgeManager = async () => { - const zone = makeDurableZone(provideBaggage('mockBridgeManager')); - /** @type {undefined | ERef} */ - let bridgeHandler; - - /** @type {ScopedBridgeManager} */ - const bridgeManager = zone.exo('BridgeManager', undefined, { - async fromBridge(obj) { - t.is(typeof obj, 'string'); - }, - async toBridge(obj) { - switch (obj.type) { - case 'VLOCALCHAIN_ALLOCATE_ADDRESS': { - t.log('VLOCALCHAIN_ALLOCATE_ADDRESS', obj); - return 'agoricfoo'; - } - default: { - t.is(obj, null); - return undefined; - } - } - }, - initHandler(newHandler) { - bridgeHandler = newHandler; - }, - setHandler(newHandler) { - bridgeHandler = newHandler; - }, - }); - return { bridgeManager, bridgeHandler }; - }; - - const { bridgeManager } = await makeBridgeManager(); +const makeTestContext = async _t => { + const localchainBridge = makeFakeLocalchainBridge( + makeDurableZone(provideBaggage('localchain')), + ); const makeBankManager = () => { const zone = makeDurableZone(provideBaggage('bank')); @@ -81,7 +52,7 @@ const makeTestContext = async t => { }; const localchain = await makeLocalChain({ - system: bridgeManager, + system: localchainBridge, bankManager, }); @@ -123,7 +94,7 @@ test('localchain - deposit and withdraw', async t => { t.is(getInterfaceOf(lca), 'Alleged: LocalChainAccount'); const address = await E(lca).getAddress(); - t.is(address, 'agoricfoo'); + t.is(address, 'agoric1fakeBridgeAddress'); contractsLca = lca; }, deposit: async () => { diff --git a/packages/vats/test/network.test.js b/packages/vats/test/network.test.js index 636de11ee78..326b9f05bcd 100644 --- a/packages/vats/test/network.test.js +++ b/packages/vats/test/network.test.js @@ -1,17 +1,18 @@ -import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { reincarnate } from '@agoric/swingset-liveslots/tools/setup-vat-data.js'; +import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; -import { E } from '@endo/far'; import { makePinnedHistoryTopic, prepareDurablePublishKit, subscribeEach, } from '@agoric/notifier'; -import { makeDurableZone } from '@agoric/zone/durable.js'; import { prepareVowTools } from '@agoric/vow/vat.js'; +import { makeDurableZone } from '@agoric/zone/durable.js'; +import { E } from '@endo/far'; import { buildRootObject as ibcBuildRootObject } from '../src/vat-ibc.js'; import { buildRootObject as networkBuildRootObject } from '../src/vat-network.js'; +import { makeFakeIbcBridge } from '../tools/fake-bridge.js'; import { registerNetworkProtocols } from '../src/proposals/network-proposal.js'; @@ -92,36 +93,18 @@ test('network - ibc', async t => { const pinnedHistoryTopic = makePinnedHistoryTopic(subscriber); const events = subscribeEach(pinnedHistoryTopic)[Symbol.asyncIterator](); - let hndlr; - /** @type {import('../src/types.js').ScopedBridgeManager} */ - const bridgeHandler = zone.exo('IBC Bridge Manager', undefined, { - toBridge: async obj => { - const { method, type, ...params } = obj; + const ibcBridge = makeFakeIbcBridge( + zone, + obj => { + const { method, type: _, ...params } = obj; publisher.publish([method, params]); - t.is(type, 'IBC_METHOD'); - if (method === 'sendPacket') { - const { packet } = params; - return { ...packet, sequence: '39' }; - } - return undefined; - }, - fromBridge: async obj => { - if (!hndlr) throw Error('no handler!'); - await when(E(hndlr).fromBridge(obj)); - }, - initHandler: h => { - if (hndlr) throw Error('already init'); - hndlr = h; }, - setHandler: h => { - if (!hndlr) throw Error('must init first'); - hndlr = h; - }, - }); + (target, obj) => when(E(target).fromBridge(obj)), + ); await registerNetworkProtocols( { network: networkVat, ibc: ibcVat, provisioning: undefined }, - bridgeHandler, + ibcBridge, ); const portAllocator = await E(networkVat).getPortAllocator(); @@ -181,7 +164,7 @@ test('network - ibc', async t => { }, ]); - await E(bridgeHandler).fromBridge({ + await E(ibcBridge).fromBridge({ event: 'channelOpenAck', portID: 'port-1', channelID: 'channel-1', @@ -221,7 +204,7 @@ test('network - ibc', async t => { }, ]); - await E(bridgeHandler).fromBridge({ + await E(ibcBridge).fromBridge({ event: 'acknowledgementPacket', packet: { data: 'c29tZS10cmFuc2Zlci1tZXNzYWdl', @@ -242,7 +225,7 @@ test('network - ibc', async t => { await testIBCOutbound(); const testIBCInbound = async () => { - await E(bridgeHandler).fromBridge({ + await E(ibcBridge).fromBridge({ event: 'channelOpenTry', channelID: 'channel-2', portID: 'port-1', @@ -253,7 +236,7 @@ test('network - ibc', async t => { counterpartyVersion: 'bazo', }); - await E(bridgeHandler).fromBridge({ + await E(ibcBridge).fromBridge({ event: 'channelOpenConfirm', portID: 'port-1', channelID: 'channel-2', @@ -270,7 +253,7 @@ test('network - ibc', async t => { }, ]); - await E(bridgeHandler).fromBridge({ + await E(ibcBridge).fromBridge({ event: 'receivePacket', packet: { data: 'aW5ib3VuZC1tc2c=', diff --git a/packages/vats/test/vat-bank.test.js b/packages/vats/test/vat-bank.test.js index 46502424180..c57ff95211e 100644 --- a/packages/vats/test/vat-bank.test.js +++ b/packages/vats/test/vat-bank.test.js @@ -27,13 +27,15 @@ test('provideAssetSubscription - MapStore insertion order preserved', async t => ); const forwardMap = zone.mapStore(`${name} forward map`); - handleToId.forEach((id, h) => forwardMap.init(h, id)); + for (const [h, id] of handleToId.entries()) { + forwardMap.init(h, id); + } const forwardMapIds = [...forwardMap.values()]; const reverseMap = zone.mapStore(`${name} reverse map`); - [...handleToId.entries()] - .reverse() - .forEach(([h, id]) => reverseMap.init(h, id)); + for (const [h, id] of [...handleToId.entries()].reverse()) { + reverseMap.init(h, id); + } const reverseMapIds = [...reverseMap.values()]; t.deepEqual( @@ -59,7 +61,7 @@ test('communication', async t => { /** @type {undefined | ERef} */ let bankHandler; - /** @type {import('../src/types.js').ScopedBridgeManager} */ + /** @type {import('../src/types.js').ScopedBridgeManager<'bank'>} */ const bankBridgeMgr = zone.exo('fakeBankBridgeManager', undefined, { async fromBridge(obj) { t.is(typeof obj, 'string'); diff --git a/packages/vats/tools/fake-bridge.js b/packages/vats/tools/fake-bridge.js new file mode 100644 index 00000000000..be4d9afbf26 --- /dev/null +++ b/packages/vats/tools/fake-bridge.js @@ -0,0 +1,80 @@ +import { Fail } from '@agoric/assert'; +import assert from 'node:assert/strict'; + +/** @import {ScopedBridgeManager} from '../src/types.js'; */ + +/** + * @param {import('@agoric/zone').Zone} zone + * @param {(obj) => void} onToBridge + * @param {(handler, obj) => Promise} onFromBridge + * @returns {ScopedBridgeManager<'dibc'>} + */ +export const makeFakeIbcBridge = (zone, onToBridge, onFromBridge) => { + let hndlr; + return zone.exo('Fake IBC Bridge Manager', undefined, { + getBridgeId: () => 'dibc', + toBridge: async obj => { + onToBridge(obj); + const { method, type, ...params } = obj; + assert.equal(type, 'IBC_METHOD'); + if (method === 'sendPacket') { + const { packet } = params; + return { ...packet, sequence: '39' }; + } + return undefined; + }, + fromBridge: async obj => { + if (!hndlr) throw Error('no handler!'); + await onFromBridge(hndlr, obj); + }, + initHandler: h => { + if (hndlr) throw Error('already init'); + hndlr = h; + }, + setHandler: h => { + if (!hndlr) throw Error('must init first'); + hndlr = h; + }, + }); +}; + +/** + * @param {import('@agoric/zone').Zone} zone + * @param {(obj) => void} [onToBridge] + * @param {(handler, obj) => ERef} [onFromBridge] + * @returns {ScopedBridgeManager<'vlocalchain'>} + */ +export const makeFakeLocalchainBridge = ( + zone, + onToBridge = () => {}, + onFromBridge = () => {}, +) => { + let hndlr; + return zone.exo('Fake Localchain Bridge Manager', undefined, { + getBridgeId: () => 'vlocalchain', + toBridge: async obj => { + onToBridge(obj); + const { method, type, ...params } = obj; + console.info('toBridge', type, method, params); + switch (type) { + case 'VLOCALCHAIN_ALLOCATE_ADDRESS': + return 'agoric1fakeBridgeAddress'; + default: + Fail`unknown type ${type}`; + } + return undefined; + }, + fromBridge: async obj => { + if (!hndlr) throw Error('no handler!'); + await onFromBridge(hndlr, obj); + }, + initHandler: h => { + if (hndlr) throw Error('already init'); + hndlr = h; + }, + setHandler: h => { + if (!hndlr) throw Error('must init first'); + hndlr = h; + }, + }); +};