From 1e8f8d0657fecf6b581832f1ef372a9948a77928 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Mon, 25 Nov 2024 23:31:46 +0300 Subject: [PATCH] chore: durable bridgeHandler Refs: #10425 Refs: #10564 --- packages/inter-protocol/src/provisionPool.js | 11 +- .../inter-protocol/src/provisionPoolKit.js | 101 ++++++++++++------ .../inter-protocol/test/provisionPool.test.js | 24 +++-- 3 files changed, 91 insertions(+), 45 deletions(-) diff --git a/packages/inter-protocol/src/provisionPool.js b/packages/inter-protocol/src/provisionPool.js index 7eb37c61dd1..88f9ef07fd8 100644 --- a/packages/inter-protocol/src/provisionPool.js +++ b/packages/inter-protocol/src/provisionPool.js @@ -12,10 +12,16 @@ import { prepareExo } from '@agoric/vat-data'; import { provideSingleton } from '@agoric/zoe/src/contractSupport/durability.js'; import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js'; import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/topics.js'; -import { prepareProvisionPoolKit } from './provisionPoolKit.js'; +import { makeDurableZone } from '@agoric/zone/durable.js'; +import { makeTracer } from '@agoric/internal'; +import { + prepareProvisionPoolKit, +} from './provisionPoolKit.js'; /** @import {Marshal} from '@endo/marshal'; */ +const tracer = makeTracer('DEBUG_PP'); + /** @type {ContractMeta} */ export const meta = { privateArgsShape: M.splitRecord( @@ -72,7 +78,8 @@ export const start = async (zcf, privateArgs, baggage) => { privateArgs.marshaller, ); - const makeProvisionPoolKit = prepareProvisionPoolKit(baggage, { + const zone = makeDurableZone(baggage); + const makeProvisionPoolKit = prepareProvisionPoolKit(zone, { makeRecorderKit, params, poolBank, diff --git a/packages/inter-protocol/src/provisionPoolKit.js b/packages/inter-protocol/src/provisionPoolKit.js index 4e1c71aa704..fb28b6076be 100644 --- a/packages/inter-protocol/src/provisionPoolKit.js +++ b/packages/inter-protocol/src/provisionPoolKit.js @@ -1,7 +1,6 @@ // @ts-check import { X, q, Fail } from '@endo/errors'; -import { E } from '@endo/far'; -import { Far } from '@endo/marshal'; +import { E, Far } from '@endo/far'; import { AmountMath, BrandShape } from '@agoric/ertp'; import { deeplyFulfilledObject, makeTracer } from '@agoric/internal'; @@ -15,7 +14,6 @@ import { M, makeScalarBigMapStore, makeScalarBigSetStore, - prepareExoClassKit, } from '@agoric/vat-data'; import { PowerFlags } from '@agoric/vats/src/walletFlags.js'; import { @@ -66,17 +64,16 @@ const FIRST_LOWER_NEAR_KEYWORD = /^[a-z][a-zA-Z0-9_$]*$/; * Given attenuated access to the funding purse, handle requests to provision * smart wallets. * - * @param {(depositBank: ERef) => Promise} sendInitialPayment - * @param {() => void} onProvisioned + * @param {import('@agoric/zone').Zone} zone + * @param helpers */ -export const makeBridgeProvisionTool = (sendInitialPayment, onProvisioned) => { - /** @param {ProvisionPoolKitReferences} refs */ - const makeBridgeHandler = ({ - bankManager, - namesByAddressAdmin, - walletFactory, - }) => - Far('provisioningHandler', { +export const prepareBridgeProvisionTool = (zone, helpers) => + zone.exo( + 'smartWalletProvisioningHandler', + M.interface('ProvisionBridgeHandlerMaker', { + fromBridge: M.callWhen(M.record()).returns(), + }), + { fromBridge: async obj => { obj.type === 'PLEASE_PROVISION' || Fail`Unrecognized request ${obj.type}`; @@ -85,9 +82,14 @@ export const makeBridgeProvisionTool = (sendInitialPayment, onProvisioned) => { powerFlags.includes(PowerFlags.SMART_WALLET) || Fail`missing SMART_WALLET in powerFlags`; + const { bankManager, walletFactory, namesByAddressAdmin } = + await E(helpers).getReferences(); + + trace({ bankManager, walletFactory, namesByAddressAdmin }); + const bank = E(bankManager).getBankForAddress(address); // only proceed if we can provide funds - await sendInitialPayment(bank); + await E(helpers).sendInitialPayment(bank); const [_, created] = await E(walletFactory).provideSmartWallet( address, @@ -95,16 +97,15 @@ export const makeBridgeProvisionTool = (sendInitialPayment, onProvisioned) => { namesByAddressAdmin, ); if (created) { - onProvisioned(); + E(helpers).onProvisioned(); } trace(created ? 'provisioned' : 're-provisioned', address); }, - }); - return makeBridgeHandler; -}; + }, + ); /** - * @param {import('@agoric/vat-data').Baggage} baggage + * @param {import('@agoric/zone').Zone} zone * @param {{ * makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit; * params: any; @@ -113,13 +114,12 @@ export const makeBridgeProvisionTool = (sendInitialPayment, onProvisioned) => { * }} powers */ export const prepareProvisionPoolKit = ( - baggage, + zone, { makeRecorderKit, params, poolBank, zcf }, ) => { const zoe = zcf.getZoeService(); - const makeProvisionPoolKitInternal = prepareExoClassKit( - baggage, + const makeProvisionPoolKitInternal = zone.exoClassKit( 'ProvisionPoolKit', { machine: M.interface('ProvisionPoolKit machine', { @@ -132,7 +132,12 @@ export const prepareProvisionPoolKit = ( namesByAddressAdmin: M.eref(M.remotable('nameAdmin')), walletFactory: M.eref(M.remotable('walletFactory')), }).returns(), - makeHandler: M.call().returns(M.remotable('BridgeHandler')), + makeHandler: M.callWhen().returns(M.remotable('handler')), + getReferences: M.call().returns({ + bankManager: M.eref(M.remotable()), + namesByAddressAdmin: M.eref(M.remotable('nameAdmin')), + walletFactory: M.eref(M.remotable('walletFactory')), + }), initPSM: M.call(BrandShape, InstanceHandleShape).returns(), }), walletReviver: M.interface('ProvisionPoolKit wallet reviver', { @@ -183,6 +188,7 @@ export const prepareProvisionPoolKit = ( totalMintedProvided: AmountMath.makeEmpty(poolBrand), totalMintedConverted: AmountMath.makeEmpty(poolBrand), revivableAddresses, + provisionHandler: undefined, ...references, }; }, @@ -208,23 +214,34 @@ export const prepareProvisionPoolKit = ( const refs = await deeplyFulfilledObject(obj); Object.assign(this.state, refs); }, - makeHandler() { - const { bankManager, namesByAddressAdmin, walletFactory } = + getReferences() { + const { bankManager, walletFactory, namesByAddressAdmin } = this.state; + return harden({ bankManager, walletFactory, namesByAddressAdmin }); + }, + /** @returns {import('@agoric/vats').BridgeHandler} */ + makeHandler() { + const { + bankManager, + namesByAddressAdmin, + walletFactory, + provisionHandler, + } = this.state; if (!bankManager || !namesByAddressAdmin || !walletFactory) { throw Fail`must set references before handling requests`; } - const { helper } = this.facets; - // a bit obtuse but leave for backwards compatibility with tests - const innerMaker = makeBridgeProvisionTool( - bank => helper.sendInitialPayment(bank), - () => helper.onProvisioned(), - ); - return innerMaker({ + + if (!provisionHandler) { + throw Fail`provisionHandler not created`; + } + trace({ bankManager, namesByAddressAdmin, walletFactory, + provisionHandler, }); + + return provisionHandler; }, /** * @param {Brand} brand @@ -494,8 +511,23 @@ export const prepareProvisionPoolKit = ( }, }, { - finish: ({ facets }) => { - facets.helper.publishMetrics(); + finish: ({ facets, state }) => { + const { helper, machine } = facets; + helper.publishMetrics(); + const handlerZone = zone.subZone('HandlerZone'); // see what options are available + // use provide here maybe? + const provisionHandler = prepareBridgeProvisionTool( + handlerZone, + Far('Helpers', { + sendInitialPayment: bank => helper.sendInitialPayment(bank), + onProvisioned: () => helper.onProvisioned(), + getReferences: () => machine.getReferences(), + }), + ); + + trace('PROVISION_HANDLER', provisionHandler); + + Object.assign(state, { provisionHandler }); }, }, ); @@ -506,6 +538,7 @@ export const prepareProvisionPoolKit = ( * @param {object} opts * @param {Brand<'nat'>} opts.poolBrand * @param {ERef} opts.storageNode + * @param {ERef} opts.bridgeHandlerKit */ const makeProvisionPoolKit = async ({ poolBrand, storageNode }) => { const fundPurse = await E(poolBank).getPurse(poolBrand); diff --git a/packages/inter-protocol/test/provisionPool.test.js b/packages/inter-protocol/test/provisionPool.test.js index 48ea08f7312..9d07dc1bae9 100644 --- a/packages/inter-protocol/test/provisionPool.test.js +++ b/packages/inter-protocol/test/provisionPool.test.js @@ -19,7 +19,8 @@ import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js'; import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio.js'; import { E, Far } from '@endo/far'; import path from 'path'; -import { makeBridgeProvisionTool } from '../src/provisionPoolKit.js'; +import { makeHeapZone } from '@agoric/zone'; +import { prepareBridgeProvisionTool } from '../src/provisionPoolKit.js'; import { makeMockChainStorageRoot, setUpZoeForTest, @@ -364,15 +365,20 @@ test('makeBridgeProvisionTool handles duplicate requests', async t => { const { nameHub: namesByAddress, nameAdmin: namesByAddressAdmin } = makeNameHubKit(); const publishMetrics = () => {}; - const makeHandler = makeBridgeProvisionTool( - sendInitialPayment, - publishMetrics, + const zone = makeHeapZone(); + const handler = prepareBridgeProvisionTool( + zone, + Far('helper', { + sendInitialPayment, + onProvisioned: () => publishMetrics(), + getReferences: () => + harden({ + bankManager, + namesByAddressAdmin, + walletFactory, + }), + }), ); - const handler = makeHandler({ - bankManager, - namesByAddressAdmin, - walletFactory, - }); t.log('1st request to provision a SMART_WALLET for', address); await handler.fromBridge({