Skip to content

Commit

Permalink
fix(orchestration): fix race in getChain
Browse files Browse the repository at this point in the history
  • Loading branch information
mhofman committed Oct 4, 2024
1 parent 2ab7df9 commit 609867c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 21 deletions.
56 changes: 37 additions & 19 deletions packages/orchestration/src/exos/orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ const prepareOrchestratorKit = (
vowTools: { watch, asVow },
},
) => {
/** @type {MapStore<string, HostInterface<Chain>>} */
/**
* @template T
* @typedef {{ vow: Vow<T>; pending: true } | { value: T; pending: false }} MaybePendingValue
*/

/** @type {MapStore<string, MaybePendingValue<HostInterface<Chain>>>} */
const chainByName = zone.mapStore('chainName');

return zone.exoClassKit(
Expand Down Expand Up @@ -98,7 +103,7 @@ const prepareOrchestratorKit = (
*/
onFulfilled(agoricChainInfo) {
const it = makeLocalChainFacade(agoricChainInfo);
chainByName.init('agoric', it);
chainByName.set('agoric', harden({ value: it, pending: false }));
return it;
},
},
Expand All @@ -116,27 +121,32 @@ const prepareOrchestratorKit = (
*/
onFulfilled([_agoricChainInfo, remoteChainInfo, connectionInfo], name) {
const it = makeRemoteChainFacade(remoteChainInfo, connectionInfo);
chainByName.init(name, it);
chainByName.set(name, harden({ value: it, pending: false }));
return it;
},
},
orchestrator: {
/** @type {HostOf<Orchestrator['getChain']>} */
getChain(name) {
if (chainByName.has(name)) {
return asVow(() => chainByName.get(name));
}
if (name === 'agoric') {
return watch(
chainHub.getChainInfo('agoric'),
this.facets.makeLocalChainFacadeWatcher,
);
}
return watch(
chainHub.getChainsAndConnection('agoric', name),
this.facets.makeRemoteChainFacadeWatcher,
name,
);
return asVow(() => {
if (chainByName.has(name)) {
const maybeChain = chainByName.get(name);
return maybeChain.pending ? maybeChain.vow : maybeChain.value;
}
const vow =
name === 'agoric'
? watch(
chainHub.getChainInfo('agoric'),
this.facets.makeLocalChainFacadeWatcher,
)
: watch(
chainHub.getChainsAndConnection('agoric', name),
this.facets.makeRemoteChainFacadeWatcher,
name,
);
chainByName.init(name, harden({ vow, pending: true }));
return vow;
});
},
makeLocalAccount() {
return watch(E(localchain).makeAccount());
Expand All @@ -148,10 +158,18 @@ const prepareOrchestratorKit = (
const { chainName, baseName, baseDenom, brand } = denomDetail;
chainByName.has(chainName) ||
Fail`use getChain(${q(chainName)}) before getDenomInfo(${q(denom)})`;
const chain = chainByName.get(chainName);
const maybeChain = chainByName.get(chainName);
if (maybeChain.pending) {
throw Fail`wait until getChain(${q(chainName)}) completes before getDenomInfo(${q(denom)})`;
}
const chain = maybeChain.value;
chainByName.has(baseName) ||
Fail`use getChain(${q(baseName)}) before getDenomInfo(${q(denom)})`;
const base = chainByName.get(baseName);
const maybeBase = chainByName.get(baseName);
if (maybeBase.pending) {
throw Fail`wait until getChain(${q(baseName)}) completes before getDenomInfo(${q(denom)})`;
}
const base = maybeBase.value;
return harden({ chain, base, brand, baseDenom });
},
/** @type {HostOf<Orchestrator['asAmount']>} */
Expand Down
6 changes: 4 additions & 2 deletions packages/orchestration/test/facade-durability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ test.serial('faulty chain info', async t => {
});
});

test.serial.failing('racy chain info', async t => {
test.serial('racy chain info', async t => {
const { facadeServices, commonPrivateArgs } = await commonSetup(t);

// XXX relax again
Expand Down Expand Up @@ -244,7 +244,9 @@ test.serial('asset / denom info', async t => {
});
}

const ag = await orc.getChain('agoric');
const agP = orc.getChain('agoric');
t.throws(() => orc.getDenomInfo(agDenom));
const ag = await agP;
{
const actual = orc.getDenomInfo(agDenom);

Expand Down

0 comments on commit 609867c

Please sign in to comment.