From 440fc82285db7a5580f4261c7155863b140393ec Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 1 May 2024 19:13:09 -0400 Subject: [PATCH] refactor(orchestration): prefer ChainAddress object to string --- .../bootstrapTests/test-vat-orchestration.ts | 19 +++++----- .../src/exos/stakingAccountKit.js | 19 +++++----- packages/orchestration/src/service.js | 35 ++++++++++++++----- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/packages/boot/test/bootstrapTests/test-vat-orchestration.ts b/packages/boot/test/bootstrapTests/test-vat-orchestration.ts index 21c18ffcaf2c..d3a347260cb8 100644 --- a/packages/boot/test/bootstrapTests/test-vat-orchestration.ts +++ b/packages/boot/test/bootstrapTests/test-vat-orchestration.ts @@ -76,22 +76,21 @@ test('makeAccount returns an ICA connection', async t => { matches(account, M.remotable('ChainAccount')), 'account is a remotable', ); - const [remoteAddress, localAddress, accountAddress, port] = await Promise.all( - [ - EV(account).getRemoteAddress(), - EV(account).getLocalAddress(), - EV(account).getAddress(), - EV(account).getPort(), - ], - ); + const [remoteAddress, localAddress, chainAddress, port] = await Promise.all([ + EV(account).getRemoteAddress(), + EV(account).getLocalAddress(), + EV(account).getAddress(), + EV(account).getPort(), + ]); t.regex(remoteAddress, /icahost/); t.regex(localAddress, /icacontroller/); - t.regex(accountAddress, /cosmos1/); + t.regex(chainAddress.address, /cosmos1/); + t.regex(chainAddress.chainId, /FIXME/); // TODO, use a real chainId #9063 t.truthy(matches(port, M.remotable('Port'))); t.log('ICA Account Addresses', { remoteAddress, localAddress, - accountAddress, + chainAddress, }); }); diff --git a/packages/orchestration/src/exos/stakingAccountKit.js b/packages/orchestration/src/exos/stakingAccountKit.js index c1fc2dd80247..716926820966 100644 --- a/packages/orchestration/src/exos/stakingAccountKit.js +++ b/packages/orchestration/src/exos/stakingAccountKit.js @@ -14,8 +14,7 @@ import { E } from '@endo/far'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any'; /** - * @import { ChainAddress } from '../types.js'; - * @import { ChainAccountKit } from '../service.js'; + * @import { ChainAccount, ChainAddress } from '../types.js'; * @import { RecorderKit, MakeRecorderKit } from '@agoric/zoe/src/contractSupport/recorder.js'; * @import { Baggage } from '@agoric/swingset-liveslots'; * @import {AnyJson} from '@agoric/cosmic-proto'; @@ -26,14 +25,14 @@ const trace = makeTracer('StakingAccountHolder'); const { Fail } = assert; /** * @typedef {object} StakingAccountNotification - * @property {ChainAddress['address']} address + * @property {ChainAddress} chainAddress */ /** * @typedef {{ * topicKit: RecorderKit; - * account: ChainAccountKit['account']; - * address: ChainAddress['address']; + * account: ChainAccount; + * chainAddress: ChainAddress; * }} State */ @@ -70,16 +69,16 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => { }), }, /** - * @param {ChainAccountKit['account']} account + * @param {ChainAccount} account * @param {StorageNode} storageNode - * @param {ChainAddress['address']} address + * @param {ChainAddress} chainAddress * @returns {State} */ - (account, storageNode, address) => { + (account, storageNode, chainAddress) => { // must be the fully synchronous maker because the kit is held in durable state const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); - return { account, address, topicKit }; + return { account, chainAddress, topicKit }; }, { helper: { @@ -110,7 +109,7 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => { }; const account = this.facets.helper.owned(); - const delegatorAddress = this.state.address; + const delegatorAddress = this.state.chainAddress.address; const result = await E(account).executeEncodedTx([ /** @type {AnyJson} */ ( diff --git a/packages/orchestration/src/service.js b/packages/orchestration/src/service.js index d3b951ff0d73..3e816703ffbf 100644 --- a/packages/orchestration/src/service.js +++ b/packages/orchestration/src/service.js @@ -19,7 +19,7 @@ import { makeTxPacket, parsePacketAck } from './utils/tx.js'; * @import { IBCConnectionID } from '@agoric/vats'; * @import { Zone } from '@agoric/base-zone'; * @import { TxBody } from '@agoric/cosmic-proto/cosmos/tx/v1beta1/tx.js'; - * @import { AttenuatedNetwork, ChainAccount, ChainAddress } from './types.js'; + * @import { ChainAccount, ChainAddress } from './types.js'; */ const { Fail, bare } = assert; @@ -58,8 +58,17 @@ export const Proto3Shape = { value: M.string(), }; +export const ChainAddressShape = { + address: M.string(), + chainId: M.string(), + addressEncoding: M.string(), +}; + +/** @typedef {'UNPARSABLE_CHAIN_ADDRESS'} UnparsableChainAddress */ +const UNPARSABLE_CHAIN_ADDRESS = 'UNPARSABLE_CHAIN_ADDRESS'; + export const ChainAccountI = M.interface('ChainAccount', { - getAddress: M.call().returns(M.string()), + getAddress: M.call().returns(ChainAddressShape), getLocalAddress: M.call().returns(M.string()), getRemoteAddress: M.call().returns(M.string()), getPort: M.call().returns(M.remotable('Port')), @@ -96,7 +105,7 @@ const prepareChainAccount = zone => * localAddress: string | undefined; * requestedRemoteAddress: string; * remoteAddress: string | undefined; - * address: ChainAddress['address'] | undefined; + * chainAddress: ChainAddress | undefined; * }} */ ( harden({ @@ -104,19 +113,19 @@ const prepareChainAccount = zone => connection: undefined, requestedRemoteAddress, remoteAddress: undefined, - address: undefined, + chainAddress: undefined, localAddress: undefined, }) ), { account: { /** - * @returns {ChainAddress['address']} the address of the account on the chain + * @returns {ChainAddress} */ getAddress() { return NonNullish( - this.state.address, - 'Error parsing account address from remote address', + this.state.chainAddress, + 'ICA channel creation acknowledgement not yet received.', ); }, getLocalAddress() { @@ -194,7 +203,15 @@ const prepareChainAccount = zone => this.state.remoteAddress = remoteAddr; this.state.localAddress = localAddr; // XXX parseAddress currently throws, should it return '' instead? - this.state.address = parseAddress(remoteAddr); + this.state.chainAddress = harden({ + address: parseAddress(remoteAddr) || UNPARSABLE_CHAIN_ADDRESS, + // TODO get this from `Chain` object #9063 + // XXX how do we get a chainId for an unknown chain? seems it may need to be a user supplied arg + chainId: 'FIXME', + addressEncoding: 'bech32', + }); + trace('got chainAddress', this.state.chainAddress); + trace('parseAddress(remoteAddr)', parseAddress(remoteAddr)); }, async onClose(_connection, reason) { trace(`ICA Channel closed. Reason: ${reason}`); @@ -252,7 +269,7 @@ const prepareOrchestration = (zone, createChainAccount) => * the counterparty connection_id * @param {IBCConnectionID} controllerConnectionId * self connection_id - * @returns {Promise} + * @returns {Promise} */ async makeAccount(hostConnectionId, controllerConnectionId) { const port = await this.facets.self.bindPort();