From 527ac1afcd8cb096b34d2e39c140266e39017009 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 20 Jun 2024 17:46:45 -0700 Subject: [PATCH 1/2] test: quieter chain-info --- packages/orchestration/src/chain-info.js | 4 ++-- packages/orchestration/test/chain-info.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/orchestration/src/chain-info.js b/packages/orchestration/src/chain-info.js index b76fea8f8c4..c6e63636fcf 100644 --- a/packages/orchestration/src/chain-info.js +++ b/packages/orchestration/src/chain-info.js @@ -69,7 +69,7 @@ const knownChains = /** @satisfies {Record} */ ( * @param {ERef} agoricNamesAdmin * @param {string} name * @param {CosmosChainInfo} chainInfo - * @param {(...messages: string[]) => void} log + * @param {(...messages: string[]) => void} [log] */ export const registerChain = async ( agoricNamesAdmin, @@ -105,7 +105,7 @@ export const registerChain = async ( /** * @param {ERef} agoricNamesAdmin - * @param {(...messages: string[]) => void} log + * @param {(...messages: string[]) => void} [log] */ export const registerChainNamespace = async (agoricNamesAdmin, log) => { for await (const [name, info] of Object.entries(knownChains)) { diff --git a/packages/orchestration/test/chain-info.test.js b/packages/orchestration/test/chain-info.test.js index 615596d71f8..1b938fabdb2 100644 --- a/packages/orchestration/test/chain-info.test.js +++ b/packages/orchestration/test/chain-info.test.js @@ -7,7 +7,7 @@ test('chain-info', async t => { const { nameHub: agoricNames, nameAdmin: agoricNamesAdmin } = makeNameHubKit(); - await registerChainNamespace(agoricNamesAdmin, t.log); + await registerChainNamespace(agoricNamesAdmin); const chainNames = await agoricNames.lookup('chain'); t.like(await chainNames.lookup('cosmoshub'), { chainId: 'cosmoshub-4', From f9b685714382dae88b23bdae541620d0b2c948d4 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 20 Jun 2024 17:35:48 -0700 Subject: [PATCH 2/2] feat: chain facades return vows --- .../src/examples/sendAnywhere.contract.js | 9 +++- .../src/examples/swapExample.contract.js | 7 ++- .../src/exos/local-chain-facade.js | 46 ++++++++++------- .../src/exos/remote-chain-facade.js | 49 ++++++++++++------- packages/orchestration/src/typeGuards.js | 5 +- .../orchestration/src/utils/start-helper.js | 2 + packages/orchestration/test/facade.test.ts | 3 +- 7 files changed, 78 insertions(+), 43 deletions(-) diff --git a/packages/orchestration/src/examples/sendAnywhere.contract.js b/packages/orchestration/src/examples/sendAnywhere.contract.js index 5b1f415e08b..6ccd9571e78 100644 --- a/packages/orchestration/src/examples/sendAnywhere.contract.js +++ b/packages/orchestration/src/examples/sendAnywhere.contract.js @@ -83,11 +83,16 @@ export const start = async (zcf, privateArgs, baggage) => { // FIXME ok to use a heap var crossing the membrane scope this way? if (!contractAccount) { const agoricChain = await orch.getChain('agoric'); - contractAccount = await agoricChain.makeAccount(); + // XXX when() until membrane + contractAccount = await V.when(agoricChain.makeAccount()); + console.log('contractAccount', contractAccount); } - const info = await chain.getChainInfo(); + // XXX when() until membrane + const info = await V.when(chain.getChainInfo()); + console.log('info', info); const { chainId } = info; + assert(typeof chainId === 'string', 'bad chainId'); const { [kw]: pmtP } = await withdrawFromSeat(zcf, seat, give); await E.when(pmtP, pmt => contractAccount.deposit(pmt)); await contractAccount.transfer( diff --git a/packages/orchestration/src/examples/swapExample.contract.js b/packages/orchestration/src/examples/swapExample.contract.js index cba2326800e..3fc390af7b1 100644 --- a/packages/orchestration/src/examples/swapExample.contract.js +++ b/packages/orchestration/src/examples/swapExample.contract.js @@ -4,6 +4,7 @@ import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js' import { Far } from '@endo/far'; import { deeplyFulfilled } from '@endo/marshal'; import { M, objectMap } from '@endo/patterns'; +import { when } from '@agoric/vow/vat.js'; import { orcUtils } from '../utils/orc.js'; import { provideOrchestration } from '../utils/start-helper.js'; @@ -95,8 +96,10 @@ export const start = async (zcf, privateArgs, baggage) => { const agoric = await orch.getChain('agoric'); const [omniAccount, localAccount] = await Promise.all([ - omni.makeAccount(), - agoric.makeAccount(), + // XXX when() until membrane + when(omni.makeAccount()), + // XXX when() until membrane + when(agoric.makeAccount()), ]); const omniAddress = omniAccount.getAddress(); diff --git a/packages/orchestration/src/exos/local-chain-facade.js b/packages/orchestration/src/exos/local-chain-facade.js index 1c0afc12597..3533d392d6c 100644 --- a/packages/orchestration/src/exos/local-chain-facade.js +++ b/packages/orchestration/src/exos/local-chain-facade.js @@ -1,5 +1,5 @@ /** @file ChainAccount exo */ -import { V } from '@agoric/vow/vat.js'; +import { V, watch } from '@agoric/vow/vat.js'; import { ChainFacadeI } from '../typeGuards.js'; @@ -8,6 +8,7 @@ import { ChainFacadeI } from '../typeGuards.js'; * @import {TimerService} from '@agoric/time'; * @import {Remote} from '@agoric/internal'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; + * @import {Vow, VowTools} from '@agoric/vow'; * @import {OrchestrationService} from '../service.js'; * @import {MakeLocalOrchestrationAccountKit} from './local-orchestration-account.js'; * @import {ChainInfo, CosmosChainInfo, IBCConnectionInfo, OrchestrationAccount} from '../types.js'; @@ -21,11 +22,17 @@ import { ChainFacadeI } from '../typeGuards.js'; * storageNode: Remote; * timer: Remote; * localchain: Remote; + * vowTools: VowTools; * }} powers */ export const prepareLocalChainFacade = ( zone, - { makeLocalOrchestrationAccountKit, localchain, storageNode }, + { + makeLocalOrchestrationAccountKit, + localchain, + storageNode, + vowTools: { allVows }, + }, ) => zone.exoClass( 'LocalChainFacade', @@ -37,29 +44,32 @@ export const prepareLocalChainFacade = ( return { localChainInfo }; }, { - async getChainInfo() { - return this.state.localChainInfo; + getChainInfo() { + return watch(this.state.localChainInfo); }, // FIXME parameterize on the remoteChainInfo to make() // That used to work but got lost in the migration to Exo - /** @returns {Promise>} */ - async makeAccount() { + /** @returns {Vow>} */ + makeAccount() { const { localChainInfo } = this.state; const lcaP = V(localchain).makeAccount(); - const [lca, address] = await Promise.all([lcaP, V(lcaP).getAddress()]); - const { holder: account } = makeLocalOrchestrationAccountKit({ - account: lca, - address: harden({ - address, - chainId: localChainInfo.chainId, - addressEncoding: 'bech32', - }), - // FIXME storage path https://github.com/Agoric/agoric-sdk/issues/9066 - storageNode, + // FIXME use watch() from vowTools + return watch(allVows([lcaP, V(lcaP).getAddress()]), { + onFulfilled: ([lca, address]) => { + const { holder: account } = makeLocalOrchestrationAccountKit({ + account: lca, + address: harden({ + address, + addressEncoding: 'bech32', + chainId: localChainInfo.chainId, + }), + // FIXME storage path https://github.com/Agoric/agoric-sdk/issues/9066 + storageNode, + }); + return account; + }, }); - - return account; }, }, ); diff --git a/packages/orchestration/src/exos/remote-chain-facade.js b/packages/orchestration/src/exos/remote-chain-facade.js index 3ba96ca57fc..de244e05f89 100644 --- a/packages/orchestration/src/exos/remote-chain-facade.js +++ b/packages/orchestration/src/exos/remote-chain-facade.js @@ -1,6 +1,6 @@ /** @file ChainAccount exo */ import { makeTracer } from '@agoric/internal'; -import { V } from '@agoric/vow/vat.js'; +import { V, watch } from '@agoric/vow/vat.js'; import { ChainFacadeI } from '../typeGuards.js'; @@ -8,6 +8,7 @@ import { ChainFacadeI } from '../typeGuards.js'; * @import {Zone} from '@agoric/base-zone'; * @import {TimerService} from '@agoric/time'; * @import {Remote} from '@agoric/internal'; + * @import {Vow, VowTools} from '@agoric/vow'; * @import {OrchestrationService} from '../service.js'; * @import {prepareCosmosOrchestrationAccount} from './cosmos-orchestration-account.js'; * @import {ChainInfo, CosmosChainInfo, IBCConnectionInfo, OrchestrationAccount} from '../types.js'; @@ -28,11 +29,18 @@ const anyVal = null; * orchestration: Remote; * storageNode: Remote; * timer: Remote; + * vowTools: VowTools; * }} powers */ export const prepareRemoteChainFacade = ( zone, - { makeCosmosOrchestrationAccount, orchestration, storageNode, timer }, + { + makeCosmosOrchestrationAccount, + orchestration, + storageNode, + timer, + vowTools: { allVows }, + }, ) => zone.exoClass( 'RemoteChainFacade', @@ -46,33 +54,38 @@ export const prepareRemoteChainFacade = ( return { remoteChainInfo, connectionInfo }; }, { - async getChainInfo() { - return this.state.remoteChainInfo; + getChainInfo() { + return watch(this.state.remoteChainInfo); }, // FIXME parameterize on the remoteChainInfo to make() // That used to work but got lost in the migration to Exo - /** @returns {Promise>} */ - async makeAccount() { + /** @returns {Vow>} */ + makeAccount() { const { remoteChainInfo, connectionInfo } = this.state; + const stakingDenom = remoteChainInfo.stakingTokens?.[0]?.denom; + if (!stakingDenom) { + // FIXME methods that return vows must not throw synchronously + throw Fail`chain info lacks staking denom`; + } - const icaAccount = await V(orchestration).makeAccount( + const icaP = V(orchestration).makeAccount( remoteChainInfo.chainId, connectionInfo.id, connectionInfo.counterparty.connection_id, ); - const address = await V(icaAccount).getAddress(); - - const stakingDenom = remoteChainInfo.stakingTokens?.[0]?.denom; - if (!stakingDenom) { - throw Fail`chain info lacks staking denom`; - } - return makeCosmosOrchestrationAccount(address, stakingDenom, { - account: icaAccount, - storageNode, - icqConnection: anyVal, - timer, + // FIXME use watch() from vowTools + return watch(allVows([icaP, V(icaP).getAddress()]), { + onFulfilled: ([account, address]) => { + return makeCosmosOrchestrationAccount(address, stakingDenom, { + account, + storageNode, + // FIXME provide real ICQ connection + icqConnection: anyVal, + timer, + }); + }, }); }, }, diff --git a/packages/orchestration/src/typeGuards.js b/packages/orchestration/src/typeGuards.js index 9a4a7391c21..13f59166071 100644 --- a/packages/orchestration/src/typeGuards.js +++ b/packages/orchestration/src/typeGuards.js @@ -1,4 +1,5 @@ import { AmountShape } from '@agoric/ertp'; +import { VowShape } from '@agoric/vow'; import { M } from '@endo/patterns'; export const ConnectionHandlerI = M.interface('ConnectionHandler', { @@ -89,6 +90,6 @@ export const DenomAmountShape = { denom: DenomShape, value: M.bigint() }; /** @see {Chain} */ export const ChainFacadeI = M.interface('ChainFacade', { - getChainInfo: M.callWhen().returns(ChainInfoShape), - makeAccount: M.callWhen().returns(M.remotable('OrchestrationAccount')), + getChainInfo: M.call().returns(VowShape), + makeAccount: M.call().returns(VowShape), }); diff --git a/packages/orchestration/src/utils/start-helper.js b/packages/orchestration/src/utils/start-helper.js index 6b7db2acc96..5c14d99dee1 100644 --- a/packages/orchestration/src/utils/start-helper.js +++ b/packages/orchestration/src/utils/start-helper.js @@ -77,6 +77,7 @@ export const provideOrchestration = ( orchestration: remotePowers.orchestrationService, storageNode: remotePowers.storageNode, timer: remotePowers.timerService, + vowTools, }); const makeLocalChainFacade = prepareLocalChainFacade(zone, { @@ -86,6 +87,7 @@ export const provideOrchestration = ( storageNode: remotePowers.storageNode, orchestration: remotePowers.orchestrationService, timer: remotePowers.timerService, + vowTools, }); const facade = makeOrchestrationFacade({ diff --git a/packages/orchestration/test/facade.test.ts b/packages/orchestration/test/facade.test.ts index 5ccb3206e9a..bab337baca5 100644 --- a/packages/orchestration/test/facade.test.ts +++ b/packages/orchestration/test/facade.test.ts @@ -1,5 +1,6 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; +import { V } from '@agoric/vow/vat.js'; import { setupZCFTest } from '@agoric/zoe/test/unitTests/zcf/setupZcfTest.js'; import type { CosmosChainInfo, IBCConnectionInfo } from '../src/cosmos-api.js'; import type { Chain } from '../src/orchestration-api.js'; @@ -73,7 +74,7 @@ test('chain info', async t => { }); const result = (await handle()) as Chain; - t.deepEqual(await result.getChainInfo(), mockChainInfo); + t.deepEqual(await V.when(result.getChainInfo()), mockChainInfo); }); test.todo('contract upgrade');