Skip to content

Commit 3988235

Browse files
committed
fix: proper inbound IBC listening
1 parent 3424ca0 commit 3988235

File tree

5 files changed

+57
-49
lines changed

5 files changed

+57
-49
lines changed

packages/SwingSet/src/vats/network/network.js

+16-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { toBytes } from './bytes';
66

77
const harden = /** @type {<T>(x: T) => T} */ (rawHarden);
88

9+
export const ENDPOINT_SEPARATOR = '/';
10+
911
/**
1012
* @template T,U
1113
* @typedef {import('@agoric/store').Store<T,U>} Store
@@ -23,7 +25,7 @@ const harden = /** @type {<T>(x: T) => T} */ (rawHarden);
2325

2426
/**
2527
* @typedef {Object} Protocol The network Protocol
26-
* @property {(prefix: Endpoint) => Promise<Port>} bind Claim a port, or if ending in '/', a fresh name
28+
* @property {(prefix: Endpoint) => Promise<Port>} bind Claim a port, or if ending in ENDPOINT_SEPARATOR, a fresh name
2729
*/
2830

2931
/**
@@ -38,7 +40,7 @@ const harden = /** @type {<T>(x: T) => T} */ (rawHarden);
3840
/**
3941
* @typedef {Object} ListenHandler A handler for incoming connections
4042
* @property {(port: Port, l: ListenHandler) => Promise<void>} [onListen] The listener has been registered
41-
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<ConnectionHandler>} [onAccept] A new connection is incoming
43+
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<ConnectionHandler>} onAccept A new connection is incoming
4244
* @property {(port: Port, rej: any, l: ListenHandler) => Promise<void>} [onError] There was an error while listening
4345
* @property {(port: Port, l: ListenHandler) => Promise<void>} [onRemove] The listener has been removed
4446
*/
@@ -230,18 +232,17 @@ export function crossoverConnection(
230232
/**
231233
* Get the list of prefixes from longest to shortest.
232234
* @param {string} addr
233-
* @param {string} [sep='/']
234235
*/
235-
export function getPrefixes(addr, sep = '/') {
236-
const parts = addr.split(sep);
236+
export function getPrefixes(addr) {
237+
const parts = addr.split(ENDPOINT_SEPARATOR);
237238

238239
/**
239240
* @type {string[]}
240241
*/
241242
const ret = [];
242243
for (let i = parts.length; i > 0; i -= 1) {
243244
// Try most specific match.
244-
const prefix = parts.slice(0, i).join(sep);
245+
const prefix = parts.slice(0, i).join(ENDPOINT_SEPARATOR);
245246
ret.push(prefix);
246247
}
247248
return ret;
@@ -283,9 +284,7 @@ export function makeNetworkProtocol(protocolHandler, E = defaultE) {
283284

284285
const lchandler =
285286
/** @type {ConnectionHandler} */
286-
(await E(listener)
287-
.onAccept(port, localAddr, remoteAddr, listener)
288-
.catch(rethrowUnlessMissing));
287+
(await E(listener).onAccept(port, localAddr, remoteAddr, listener));
289288

290289
return crossoverConnection(
291290
lchandler,
@@ -301,7 +300,7 @@ export function makeNetworkProtocol(protocolHandler, E = defaultE) {
301300
/** @type {string} */
302301
(await E(port).getLocalAddress());
303302

304-
const ret = getPrefixes(remoteAddr, '/');
303+
const ret = getPrefixes(remoteAddr);
305304
if (await protocolImpl.isListening(ret)) {
306305
return protocolImpl.inbound(ret, remoteAddr, localAddr, lchandler);
307306
}
@@ -345,7 +344,7 @@ export function makeNetworkProtocol(protocolHandler, E = defaultE) {
345344
*/
346345
const bind = async localAddr => {
347346
// Check if we are underspecified (ends in slash)
348-
if (localAddr.endsWith('/')) {
347+
if (localAddr.endsWith(ENDPOINT_SEPARATOR)) {
349348
for (;;) {
350349
// eslint-disable-next-line no-await-in-loop
351350
const portID = await E(protocolHandler).generatePortID(localAddr);
@@ -536,9 +535,12 @@ export function makeLoopbackProtocolHandler(E = defaultE) {
536535
}
537536
const [lport, lhandler] = listeners.get(remoteAddr);
538537
// console.log(`looking up onAccept in`, lhandler);
539-
const rport = await E(lhandler)
540-
.onAccept(lport, remoteAddr, localAddr, lhandler)
541-
.catch(rethrowUnlessMissing);
538+
const rport = await E(lhandler).onAccept(
539+
lport,
540+
remoteAddr,
541+
localAddr,
542+
lhandler,
543+
);
542544
// console.log(`rport is`, rport);
543545
return rport;
544546
},

packages/SwingSet/src/vats/network/router.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { E as defaultE } from '@agoric/eventual-send';
33
import rawHarden from '@agoric/harden';
44
import makeStore from '@agoric/store';
5-
import { makeNetworkProtocol } from './network';
5+
import { makeNetworkProtocol, ENDPOINT_SEPARATOR } from './network';
66

77
const harden = /** @type {<T>(x: T) => T} */ (rawHarden);
88

@@ -26,29 +26,31 @@ const harden = /** @type {<T>(x: T) => T} */ (rawHarden);
2626
/**
2727
* Create a slash-delimited router.
2828
*
29-
* @param {string} [sep='/'] the delimiter of the routing strings
3029
* @returns {Router} a new Router
3130
*/
32-
export default function makeRouter(sep = '/') {
31+
export default function makeRouter() {
3332
/**
3433
* @type {Store<string, any>}
3534
*/
3635
const prefixToRoute = makeStore('prefix');
3736
return harden({
3837
getRoutes(addr) {
39-
const parts = addr.split(sep);
38+
const parts = addr.split(ENDPOINT_SEPARATOR);
4039
/**
4140
* @type {[string, any][]}
4241
*/
4342
const ret = [];
4443
for (let i = parts.length; i > 0; i -= 1) {
4544
// Try most specific match.
46-
const prefix = parts.slice(0, i).join(sep);
45+
const prefix = parts.slice(0, i).join(ENDPOINT_SEPARATOR);
4746
if (prefixToRoute.has(prefix)) {
4847
ret.push([prefix, prefixToRoute.get(prefix)]);
4948
}
5049
// Trim off the last value (after the slash).
51-
const defaultPrefix = prefix.substr(0, prefix.lastIndexOf('/') + 1);
50+
const defaultPrefix = prefix.substr(
51+
0,
52+
prefix.lastIndexOf(ENDPOINT_SEPARATOR) + 1,
53+
);
5254
if (prefixToRoute.has(defaultPrefix)) {
5355
ret.push([defaultPrefix, prefixToRoute.get(defaultPrefix)]);
5456
}
@@ -75,12 +77,11 @@ export default function makeRouter(sep = '/') {
7577
/**
7678
* Create a router that behaves like a Protocol.
7779
*
78-
* @param {string} [sep='/'] the route separator
7980
* @param {typeof defaultE} [E=defaultE] Eventual sender
8081
* @returns {RouterProtocol} The new delegated protocol
8182
*/
82-
export function makeRouterProtocol(sep = '/', E = defaultE) {
83-
const router = makeRouter(sep);
83+
export function makeRouterProtocol(E = defaultE) {
84+
const router = makeRouter();
8485
const protocols = makeStore('prefix');
8586
const protocolHandlers = makeStore('prefix');
8687

packages/SwingSet/test/test-network.js

+5
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ const makeProtocolHandler = t => {
2929
*/
3030
let l;
3131
let lp;
32+
let nonce = 0;
3233
return harden({
3334
async onCreate(_protocol, _impl) {
3435
log('created', _protocol, _impl);
3536
},
37+
async generatePortID() {
38+
nonce += 1;
39+
return `${nonce}`;
40+
},
3641
async onBind(port, localAddr) {
3742
t.assert(port, `port is supplied to onBind`);
3843
t.assert(localAddr, `local address is supplied to onBind`);

packages/cosmic-swingset/lib/ag-solo/vats/ibc.js

+25-25
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ export function makeIBCProtocolHandler(
100100
{ timerService },
101101
) {
102102
/**
103-
* @type {Store<string, Promise<Connection>>}
103+
* @type {Store<string, [ConnectionHandler, Promise<Connection>]>}
104104
*/
105-
const channelKeyToConnP = makeStore('CHANNEL:PORT');
105+
const channelKeyToHandler = makeStore('CHANNEL:PORT');
106106

107107
/**
108108
* @typedef {Object} Counterparty
@@ -122,7 +122,7 @@ export function makeIBCProtocolHandler(
122122
/**
123123
* @type {Store<string, ConnectingInfo>}
124124
*/
125-
const channelKeyToConnectingInfo = makeStore('CHANNEL:PORT');
125+
const channelKeyToInfo = makeStore('CHANNEL:PORT');
126126

127127
/**
128128
* @type {Set<string>}
@@ -409,7 +409,7 @@ export function makeIBCProtocolHandler(
409409
version,
410410
};
411411
const channelKey = `${channelID}:${portID}`;
412-
channelKeyToConnectingInfo.init(channelKey, obj);
412+
channelKeyToInfo.init(channelKey, obj);
413413

414414
if (!FIXME_ALLOW_NAIVE_RELAYS || !chandler) {
415415
// Just wait until the connection handler resolves.
@@ -547,10 +547,10 @@ paths:
547547
);
548548
if (!waiter) {
549549
await E(protocolImpl).isListening([`/ibc-port/${portID}`]);
550-
channelKeyToConnectingInfo.init(channelKey, obj);
550+
channelKeyToInfo.init(channelKey, obj);
551551
} else {
552552
// We have more specific information.
553-
channelKeyToConnectingInfo.set(channelKey, obj);
553+
channelKeyToInfo.set(channelKey, obj);
554554
}
555555
break;
556556
}
@@ -569,8 +569,8 @@ paths:
569569
connectionHops: hops,
570570
counterparty: { port_id: rPortID, channel_id: rChannelID },
571571
counterpartyVersion: storedVersion,
572-
} = channelKeyToConnectingInfo.get(channelKey);
573-
channelKeyToConnectingInfo.delete(channelKey);
572+
} = channelKeyToInfo.get(channelKey);
573+
channelKeyToInfo.delete(channelKey);
574574

575575
const rVersion = updatedVersion || storedVersion;
576576
const localAddr = `/ibc-port/${portID}/${order.toLowerCase()}/${version}`;
@@ -610,7 +610,7 @@ paths:
610610
}
611611

612612
// Check for a listener for this subprotocol.
613-
const listenSearch = getPrefixes(localAddr, '/');
613+
const listenSearch = getPrefixes(localAddr);
614614
const rchandler = makeIBCConnectionHandler(
615615
channelID,
616616
portID,
@@ -620,17 +620,17 @@ paths:
620620
);
621621

622622
// Actually connect.
623-
const connP =
624-
/** @type {Promise<Connection>} */
625-
(E(protocolImpl).inbound(
626-
listenSearch,
627-
localAddr,
628-
remoteAddr,
629-
rchandler,
630-
));
623+
// eslint-disable-next-line prettier/prettier
624+
const connP = /** @type {Promise<Connection>} */
625+
(E(protocolImpl).inbound(listenSearch, localAddr, remoteAddr, rchandler))
626+
.then(conn => {
627+
console.info(`FIGME: got connection`, conn);
628+
return conn;
629+
});
631630

632631
/* Stash it for later use. */
633-
channelKeyToConnP.init(channelKey, connP);
632+
console.info(`FIGME: Stashing ${channelKey}`, rchandler);
633+
channelKeyToHandler.init(channelKey, [rchandler, connP]);
634634
break;
635635
}
636636

@@ -643,11 +643,11 @@ paths:
643643
} = packet;
644644
const channelKey = `${channelID}:${portID}`;
645645

646-
const connP = channelKeyToConnP.get(channelKey);
646+
const [chandler, connP] = channelKeyToHandler.get(channelKey);
647647
const data = base64ToBytes(data64);
648648

649-
E(connP)
650-
.send(data)
649+
connP
650+
.then(conn => E(chandler).onReceive(conn, data, chandler))
651651
.then(ack => {
652652
const ack64 = dataToBase64(/** @type {Bytes} */ (ack));
653653
return callIBCDevice('packetExecuted', { packet, ack: ack64 });
@@ -688,10 +688,10 @@ paths:
688688
case 'channelCloseConfirm': {
689689
const { portID, channelID } = obj;
690690
const channelKey = `${channelID}:${portID}`;
691-
if (channelKeyToConnP.has(channelKey)) {
692-
const connP = channelKeyToConnP.get(channelKey);
693-
channelKeyToConnP.delete(channelKey);
694-
E(connP).close();
691+
if (channelKeyToHandler.has(channelKey)) {
692+
const [chandler, connP] = channelKeyToHandler.get(channelKey);
693+
channelKeyToHandler.delete(channelKey);
694+
connP.then(conn => E(chandler).onClose(conn, undefined, chandler));
695695
}
696696
break;
697697
}

packages/cosmic-swingset/lib/ag-solo/vats/vat-network.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import harden from '@agoric/harden';
33
import { makeRouterProtocol } from '@agoric/swingset-vat/src/vats/network/router';
44

55
function build(E) {
6-
return harden(makeRouterProtocol('/', E));
6+
return harden(makeRouterProtocol(E));
77
}
88

99
export default function setup(syscall, state, helpers) {

0 commit comments

Comments
 (0)