diff --git a/packages/boot/test/bootstrapTests/vat-orchestration.test.ts b/packages/boot/test/bootstrapTests/vat-orchestration.test.ts index 7757344b6bc..22781f38ac1 100644 --- a/packages/boot/test/bootstrapTests/vat-orchestration.test.ts +++ b/packages/boot/test/bootstrapTests/vat-orchestration.test.ts @@ -55,6 +55,11 @@ test.before(async t => { await evalProposal( buildProposal('@agoric/builders/scripts/vats/init-orchestration.js'), ); + await evalProposal( + buildProposal( + '@agoric/builders/scripts/orchestration/write-chain-info.js', + ), + ); const vatStore = await EV.vat('bootstrap').consumeItem('vatStore'); t.true(await EV(vatStore).has('ibc'), 'ibc'); t.true(await EV(vatStore).has('network'), 'network'); diff --git a/packages/builders/scripts/orchestration/write-chain-info.js b/packages/builders/scripts/orchestration/write-chain-info.js new file mode 100644 index 00000000000..10e8e9abad3 --- /dev/null +++ b/packages/builders/scripts/orchestration/write-chain-info.js @@ -0,0 +1,13 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async () => + harden({ + sourceSpec: '@agoric/orchestration/src/proposals/init-chain-info.js', + getManifestCall: ['getManifestForChainInfo'], + }); + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('gov-orchestration', defaultProposalBuilder); +}; diff --git a/packages/orchestration/src/proposals/init-chain-info.js b/packages/orchestration/src/proposals/init-chain-info.js new file mode 100644 index 00000000000..d47c074bb3f --- /dev/null +++ b/packages/orchestration/src/proposals/init-chain-info.js @@ -0,0 +1,98 @@ +import { Fail } from '@endo/errors'; +import { E, Far } from '@endo/far'; +import { makeMarshal } from '@endo/marshal'; +import { makeTracer } from '@agoric/internal'; +import { registerKnownChains } from '../chain-info.js'; +import { CHAIN_KEY, CONNECTIONS_KEY } from '../exos/chain-hub.js'; + +const trace = makeTracer('InitChainInfo', true); + +/** + * Similar to publishAgoricNamesToChainStorage but publishes a node per chain + * instead of one list of entries + */ + +/** + * @param {ERef} agoricNamesAdmin + * @param {ERef} chainStorageP + */ +const publishChainInfoToChainStorage = async ( + agoricNamesAdmin, + chainStorageP, +) => { + const chainStorage = await chainStorageP; + if (!chainStorage) { + console.warn('no chain storage, not registering chain info'); + return; + } + + const agoricNamesNode = await E(chainStorage).makeChildNode('agoricNames'); + + /** + * @param {string} subpath + */ + const echoNameUpdates = async subpath => { + const chainNamesNode = E(agoricNamesNode).makeChildNode(subpath); + const { nameAdmin } = await E(agoricNamesAdmin).provideChild(subpath); + + /** + * Previous entries, to prevent redundant updates + * + * @type {Record} chainName => stringified chainInfo + */ + const prev = {}; + + // XXX cannot be changed until we upgrade vat-agoricNames to allow it + await E(nameAdmin).onUpdate( + // XXX will live on the heap in the bootstrap vat. When we upgrade or kill + // that this handler will sever and vat-agoricNames will need to be upgraded + // to allow changing the handler, or to use pubsub mechanics instead. + Far('chain info writer', { + write(entries) { + // chainInfo has no cap data but we need to marshal bigints + const marshalData = makeMarshal(_val => Fail`data only`); + for (const [chainName, info] of entries) { + const value = JSON.stringify(marshalData.toCapData(info)); + if (prev[chainName] === value) { + continue; + } + const chainNode = E(chainNamesNode).makeChildNode(chainName); + prev[chainName] = value; + void E(chainNode) + .setValue(value) + .catch(() => delete prev[chainName]); + } + }, + }), + ); + }; + await echoNameUpdates(CHAIN_KEY); + await echoNameUpdates(CONNECTIONS_KEY); +}; + +/** + * @param {BootstrapPowers} powers + */ +export const initChainInfo = async ({ + consume: { agoricNamesAdmin, chainStorage: chainStorageP }, +}) => { + trace('init-chainInfo'); + + // First set up callback to write updates to vstorage + await publishChainInfoToChainStorage(agoricNamesAdmin, chainStorageP); + + // Now register the names + await registerKnownChains(agoricNamesAdmin, trace); +}; +harden(initChainInfo); + +export const getManifestForChainInfo = () => ({ + manifest: { + [initChainInfo.name]: { + consume: { + agoricNamesAdmin: true, + chainStorage: true, + }, + }, + }, +}); diff --git a/packages/orchestration/src/proposals/orchestration-proposal.js b/packages/orchestration/src/proposals/orchestration-proposal.js index 1f38c512f0c..160f284d425 100644 --- a/packages/orchestration/src/proposals/orchestration-proposal.js +++ b/packages/orchestration/src/proposals/orchestration-proposal.js @@ -1,9 +1,5 @@ -import { Fail } from '@endo/errors'; -import { E, Far } from '@endo/far'; -import { makeMarshal } from '@endo/marshal'; import { makeTracer } from '@agoric/internal'; -import { registerKnownChains } from '../chain-info.js'; -import { CHAIN_KEY, CONNECTIONS_KEY } from '../exos/chain-hub.js'; +import { E } from '@endo/far'; const trace = makeTracer('CoreEvalOrchestration', true); @@ -27,14 +23,16 @@ export const setupOrchestrationVat = async ( consume: { loadCriticalVat, portAllocator: portAllocatorP }, produce: { orchestrationVat, ...produce }, }, - options, + { options }, ) => { - const { orchestrationRef } = options.options; + trace('setupOrchestrationVat', options); + const { orchestrationRef } = options; const vats = { orchestration: E(loadCriticalVat)('orchestration', orchestrationRef), }; // don't proceed if loadCriticalVat fails await Promise.all(Object.values(vats)); + trace('setupOrchestrationVat got vats'); orchestrationVat.reset(); orchestrationVat.resolve(vats.orchestration); @@ -49,87 +47,9 @@ export const setupOrchestrationVat = async ( produce.cosmosInterchainService.reset(); produce.cosmosInterchainService.resolve(cosmosInterchainService); + trace('setupOrchestrationVat complete'); }; -/** - * Similar to publishAgoricNamesToChainStorage but publishes a node per chain - * instead of one list of entries - */ - -/** - * @param {ERef} agoricNamesAdmin - * @param {ERef} chainStorageP - */ -const publishChainInfoToChainStorage = async ( - agoricNamesAdmin, - chainStorageP, -) => { - const chainStorage = await chainStorageP; - if (!chainStorage) { - console.warn('no chain storage, not registering chain info'); - return; - } - - const agoricNamesNode = await E(chainStorage).makeChildNode('agoricNames'); - - /** - * @param {string} subpath - */ - const echoNameUpdates = async subpath => { - const chainNamesNode = E(agoricNamesNode).makeChildNode(subpath); - const { nameAdmin } = await E(agoricNamesAdmin).provideChild(subpath); - - /** - * Previous entries, to prevent redundant updates - * - * @type {Record} chainName => stringified chainInfo - */ - const prev = {}; - - // XXX cannot be changed until we upgrade vat-agoricNames to allow it - await E(nameAdmin).onUpdate( - // XXX will live on the heap in the bootstrap vat. When we upgrade or kill - // that this handler will sever and vat-agoricNames will need to be upgraded - // to allow changing the handler, or to use pubsub mechanics instead. - Far('chain info writer', { - write(entries) { - // chainInfo has no cap data but we need to marshal bigints - const marshalData = makeMarshal(_val => Fail`data only`); - for (const [chainName, info] of entries) { - const value = JSON.stringify(marshalData.toCapData(info)); - if (prev[chainName] === value) { - continue; - } - const chainNode = E(chainNamesNode).makeChildNode(chainName); - prev[chainName] = value; - void E(chainNode) - .setValue(value) - .catch(() => delete prev[chainName]); - } - }, - }), - ); - }; - await echoNameUpdates(CHAIN_KEY); - await echoNameUpdates(CONNECTIONS_KEY); -}; - -/** - * @param {BootstrapPowers} powers - */ -export const initChainInfo = async ({ - consume: { agoricNamesAdmin, chainStorage: chainStorageP }, -}) => { - trace('init-chainInfo'); - - // First set up callback to write updates to vstorage - await publishChainInfoToChainStorage(agoricNamesAdmin, chainStorageP); - - // Now register the names - await registerKnownChains(agoricNamesAdmin, trace); -}; -harden(initChainInfo); - export const getManifestForOrchestration = (_powers, { orchestrationRef }) => ({ manifest: { [setupOrchestrationVat.name]: { @@ -142,12 +62,6 @@ export const getManifestForOrchestration = (_powers, { orchestrationRef }) => ({ orchestrationVat: 'orchestrationVat', }, }, - [initChainInfo.name]: { - consume: { - agoricNamesAdmin: true, - chainStorage: true, - }, - }, }, options: { orchestrationRef, diff --git a/packages/vm-config/decentral-devnet-config.json b/packages/vm-config/decentral-devnet-config.json index 232420684cc..1295b8eea9d 100644 --- a/packages/vm-config/decentral-devnet-config.json +++ b/packages/vm-config/decentral-devnet-config.json @@ -13,7 +13,8 @@ "@agoric/builders/scripts/vats/init-transfer.js" ], [ - "@agoric/builders/scripts/vats/init-orchestration.js" + "@agoric/builders/scripts/vats/init-orchestration.js", + "@agoric/builders/scripts/orchestration/write-chain-info.js" ], [ { diff --git a/packages/vm-config/decentral-itest-orchestration-config.json b/packages/vm-config/decentral-itest-orchestration-config.json index f0db27308e5..ff410f43245 100644 --- a/packages/vm-config/decentral-itest-orchestration-config.json +++ b/packages/vm-config/decentral-itest-orchestration-config.json @@ -8,6 +8,7 @@ "@agoric/builders/scripts/vats/init-localchain.js", "@agoric/builders/scripts/vats/init-transfer.js", "@agoric/builders/scripts/vats/init-orchestration.js", + "@agoric/builders/scripts/orchestration/write-chain-info.js", { "module": "@agoric/builders/scripts/inter-protocol/init-core.js", "entrypoint": "defaultProposalBuilder",