Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move port allocation in network vat to PortAllocator #9228

Merged
merged 18 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 41 additions & 12 deletions packages/network/src/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ export function getPrefixes(addr) {
return ret;
}

/**
* Validate IBC port name
* @param {string} specifiedName
*/
function throwIfInvalidPortName(specifiedName) {
// Contains between 2 and 128 characters
// Can contain alphanumeric characters
// Valid symbols: ., ,, _, +, -, #, [, ], <, >
const portNameRegex = new RegExp('^[a-zA-Z0-9.,_+\\-#<>\\[\\]]{2,128}$');
if (!portNameRegex.test(specifiedName)) {
throw new Error(`Invalid IBC port name: ${specifiedName}`);
}
}

/**
* @typedef {object} ConnectionOpts
* @property {Endpoint[]} addrs
Expand Down Expand Up @@ -1436,17 +1450,28 @@ export const preparePortAllocator = (zone, { watch }) =>
zone.exoClass(
'PortAllocator',
M.interface('PortAllocator', {
allocateIBCPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
allocateIBCPort: M.callWhen()
iomekam marked this conversation as resolved.
Show resolved Hide resolved
.optional(M.string())
.returns(Shape.Vow$(Shape.Port)),
allocateICAControllerPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
allocateIBCPegasusPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
allocateLocalPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
allocateLocalPort: M.callWhen()
iomekam marked this conversation as resolved.
Show resolved Hide resolved
.optional(M.string())
.returns(Shape.Vow$(Shape.Port)),
}),
({ protocol }) => ({ protocol, lastICAPortNum: 0n }),
{
allocateIBCPort() {
allocateIBCPort(specifiedName = '') {
const { state } = this;
let localAddr = `/ibc-port/`;

if (specifiedName) {
throwIfInvalidPortName(specifiedName);

localAddr = `/ibc-port/custom-${specifiedName}`;
}

// Allocate an IBC port with a unique generated name.
return watch(E(state.protocol).bindPort(`/ibc-port/`));
return watch(E(state.protocol).bindPort(localAddr));
},
allocateICAControllerPort() {
const { state } = this;
Expand All @@ -1457,15 +1482,19 @@ export const preparePortAllocator = (zone, { watch }) =>
),
);
},
allocateIBCPegasusPort() {
const { state } = this;
// Allocate a Pegasus IBC port with a unique generated name.
return watch(E(state.protocol).bindPort(`/ibc-port/pegasus`));
},
allocateLocalPort() {
allocateLocalPort(specifiedName = '') {
const { state } = this;

let localAddr = `/local/`;

if (specifiedName) {
throwIfInvalidPortName(specifiedName);

localAddr = `/local/custom-${specifiedName}`;
}

// Allocate a local port with a unique generated name.
return watch(E(state.protocol).bindPort(`/local/`));
return watch(E(state.protocol).bindPort(localAddr));
},
},
);
7 changes: 1 addition & 6 deletions packages/network/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,4 @@
* Create an outbound connection
*/

/**
* @typedef {object} PortAllocator
* @property {() => PromiseVow<Port>} allocateIBCPort
* @property {() => PromiseVow<Port>} allocateICAControllerPort
* @property {() => PromiseVow<Port>} allocateIBCPegasusPort
*/
/** @typedef {ReturnType<ReturnType<typeof import('@agoric/network').preparePortAllocator>>} PortAllocator */
17 changes: 15 additions & 2 deletions packages/network/test/test-network-misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const prepareProtocolHandler = (
},
async generatePortID() {
this.state.nonce += 1;
return `${this.state.nonce}`;
return `port-${this.state.nonce}`;
},
async onBind(port, localAddr) {
t.assert(port, `port is supplied to onBind`);
Expand Down Expand Up @@ -187,7 +187,10 @@ test('verify port allocation', async t => {
const portAllocator = makePortAllocator({ protocol });

const ibcPort = await when(portAllocator.allocateIBCPort());
t.is(ibcPort.getLocalAddress(), '/ibc-port/1');
t.is(ibcPort.getLocalAddress(), '/ibc-port/port-1');

const namedIbcPort = await when(portAllocator.allocateIBCPort('test-1'));
t.is(namedIbcPort.getLocalAddress(), '/ibc-port/custom-test-1');

const icaControllerPort1 = await when(
portAllocator.allocateICAControllerPort(),
Expand All @@ -198,6 +201,16 @@ test('verify port allocation', async t => {
portAllocator.allocateICAControllerPort(),
);
t.is(icaControllerPort2.getLocalAddress(), '/ibc-port/icacontroller-2');

const localPort = await when(portAllocator.allocateLocalPort());
t.is(localPort.getLocalAddress(), '/local/port-5');

const namedLocalPort = await when(portAllocator.allocateLocalPort('local-1'));
t.is(namedLocalPort.getLocalAddress(), '/local/custom-local-1');

await t.throwsAsync(when(portAllocator.allocateIBCPort('/test-1')), {
message: 'Invalid IBC port name: /test-1',
});
});

test('protocol connection listen', async t => {
Expand Down
21 changes: 8 additions & 13 deletions packages/orchestration/src/proposals/orchestration-proposal.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// @ts-check
import { V as E } from '@agoric/vat-data/vow.js';
import { Far } from '@endo/far';

/** @import { AttenuatedPortAllocator, Orchestration, OrchestrationVat } from '../types' */
/**
* @import { OrchestrationService } from '../service.js'
* @import { OrchestrationVat } from '../vat-orchestration.js'
*/

/**
* @param {BootstrapPowers & {
* consume: {
* loadCriticalVat: VatLoader<any>;
* portAllocator: AttenuatedPortAllocator;
* portAllocator: PortAllocator;
* };
* produce: {
* orchestration: Producer<any>;
Expand All @@ -25,7 +27,7 @@ import { Far } from '@endo/far';
*/
export const setupOrchestrationVat = async (
{
consume: { loadCriticalVat, portAllocator },
consume: { loadCriticalVat, portAllocator: portAllocatorP },
produce: {
orchestrationVat,
orchestration,
Expand All @@ -45,17 +47,10 @@ export const setupOrchestrationVat = async (
orchestrationVat.reset();
orchestrationVat.resolve(vats.orchestration);

await portAllocator;

/** @type {AttenuatedPortAllocator} */
const allocator = Far('PortAllocator', {
async allocateICAControllerPort() {
return E(portAllocator).allocateICAControllerPort();
},
});
const portAllocator = await portAllocatorP;

const newOrchestrationKit = await E(vats.orchestration).makeOrchestration({
portAllocator: allocator,
portAllocator,
});

orchestration.reset();
Expand Down
5 changes: 3 additions & 2 deletions packages/orchestration/src/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { makeICAConnectionAddress, parseAddress } from './utils/address.js';
import { makeTxPacket, parsePacketAck } from './utils/tx.js';

/**
* @import { AttenuatedPortAllocator } from './types.js';
* @import { ChainAccount, ChainAddress } from './types.js';
* @import { IBCConnectionID } from '@agoric/vats';
* @import { Zone } from '@agoric/base-zone';
* @import { TxBody } from '@agoric/cosmic-proto/cosmos/tx/v1beta1/tx.js';
*
*/

const { Fail, bare } = assert;
Expand All @@ -24,7 +25,7 @@ const trace = makeTracer('Orchestration');

/**
* @typedef {object} OrchestrationPowers
* @property {ERef<AttenuatedPortAllocator>} portAllocator
* @property {ERef<PortAllocator>} portAllocator
*/

/**
Expand Down
20 changes: 14 additions & 6 deletions packages/orchestration/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import type { PortAllocator } from '@agoric/network/src/network';

export type AttenuatedPortAllocator = Pick<
PortAllocator,
'allocateICAControllerPort'
>;
import type { Amount, Brand, Payment, Purse } from '@agoric/ertp/exported.js';
import type { Timestamp } from '@agoric/time';
import type { Invitation } from '@agoric/zoe/exported.js';
import type { Any } from '@agoric/cosmic-proto/google/protobuf/any';
import type { AnyJson } from '@agoric/cosmic-proto';
import type {
MsgCancelUnbondingDelegation,
MsgUndelegateResponse,
} from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js';
import type {
Delegation,
Redelegation,
UnbondingDelegation,
} from '@agoric/cosmic-proto/cosmos/staking/v1beta1/staking.js';

/**
* static declaration of known chain types will allow type support for
Expand Down
2 changes: 1 addition & 1 deletion packages/pegasus/src/proposals/core-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const listenPegasus = async ({
pegasusConnectionsAdmin.resolve(nameAdmin);

const pegasus = await E(zoe).getPublicFacet(pegasusInstance);
const port = await E(portAllocator).allocateIBCPegasusPort();
const port = await E(portAllocator).allocateIBCPort('pegasus');
return addPegasusTransferPort(port, pegasus, pegasusNameAdmin);
};
harden(listenPegasus);
5 changes: 3 additions & 2 deletions packages/vats/src/proposals/network-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const registerNetworkProtocols = async (vats, dibcBridgeManager) => {
* Testing facilities include:
*
* - loopback ports: `E(portAllocator).allocateLocalPort()`
* - an echo port: `E(portAllocator).allocateIBCPort()`
* - an echo port: `E(portAllocator).allocateIBCPort("echo")d
* /ibc-port/custom-echo
*
* @param {BootstrapPowers & {
* consume: { loadCriticalVat: VatLoader<any> };
Expand Down Expand Up @@ -151,7 +152,7 @@ export const setupNetworkProtocols = async (
await registerNetworkProtocols(vats, dibcBridgeManager);

// Add an echo listener on our ibc-port network (whether real or virtual).
const echoPort = await when(E(allocator).allocateIBCPort());
const echoPort = await when(E(allocator).allocateIBCPort('echo'));
const { listener } = await E(vats.network).makeEchoConnectionKit();
await when(E(echoPort).addListener(listener));
return E(client).assignBundle([_a => ({ ibcport: makePorts() })]);
Expand Down
Loading