diff --git a/packages/boot/test/bootstrapTests/orchestration.test.ts b/packages/boot/test/bootstrapTests/orchestration.test.ts index 1e22fe8dea8..5deaca784a1 100644 --- a/packages/boot/test/bootstrapTests/orchestration.test.ts +++ b/packages/boot/test/bootstrapTests/orchestration.test.ts @@ -2,12 +2,12 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { Fail } from '@agoric/assert'; import { AmountMath } from '@agoric/ertp'; +import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js'; import type { CosmosValidatorAddress } from '@agoric/orchestration'; import type { start as startStakeIca } from '@agoric/orchestration/src/examples/stakeIca.contract.js'; import type { Instance } from '@agoric/zoe/src/zoeService/utils.js'; import { M, matches } from '@endo/patterns'; import type { TestFn } from 'ava'; -import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js'; import { makeWalletFactoryContext, type WalletFactoryTestContext, @@ -231,3 +231,35 @@ test.serial('stakeAtom - smart wallet', async t => { 'delegate fails with invalid validator', ); }); + +// XXX rely on .serial to be in sequence, and keep this one last +test.serial('revise chain info', async t => { + const { + buildProposal, + evalProposal, + runUtils: { EV }, + } = t.context; + + const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames'); + + await t.throwsAsync(EV(agoricNames).lookup('chain', 'hot'), { + message: '"nameKey" not found: "hot"', + }); + + // Revise chain info in agoricNames with the fixture in this script + await evalProposal( + buildProposal('@agoric/builders/scripts/testing/append-chain-info.js'), + ); + + const hotchain = await EV(agoricNames).lookup('chain', 'hot'); + t.deepEqual(hotchain, { allegedName: 'Hot New Chain', chainId: 'hot-1' }); + + const connection = await EV(agoricNames).lookup( + 'chainConnection', + 'cosmoshub-4_hot-1', + ); + t.like(connection, { + id: 'connection-99', + client_id: '07-tendermint-3', + }); +}); diff --git a/packages/builders/scripts/testing/append-chain-info.js b/packages/builders/scripts/testing/append-chain-info.js new file mode 100644 index 00000000000..f141fe49074 --- /dev/null +++ b/packages/builders/scripts/testing/append-chain-info.js @@ -0,0 +1,50 @@ +/// +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {Record} */ +const chainInfo = { + hot: { + allegedName: 'Hot New Chain', + chainId: 'hot-1', + connections: { + 'cosmoshub-4': { + id: 'connection-99', + client_id: '07-tendermint-3', + counterparty: { + client_id: '07-tendermint-2', + connection_id: 'connection-1', + prefix: { + key_prefix: '', + }, + }, + state: 3 /* IBCConnectionState.STATE_OPEN */, + transferChannel: { + portId: 'transfer', + channelId: 'channel-1', + counterPartyChannelId: 'channel-1', + counterPartyPortId: 'transfer', + ordering: 1 /* Order.ORDER_UNORDERED */, + state: 3 /* IBCConnectionState.STATE_OPEN */, + version: 'ics20-1', + }, + }, + }, + }, +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async () => + harden({ + sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js', + getManifestCall: [ + 'getManifestForReviseChains', + { + chainInfo, + }, + ], + }); + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('revise-chain-info', defaultProposalBuilder); +}; diff --git a/packages/builders/scripts/testing/tweak-chain-info.js b/packages/builders/scripts/testing/tweak-chain-info.js new file mode 100644 index 00000000000..922300ea7c0 --- /dev/null +++ b/packages/builders/scripts/testing/tweak-chain-info.js @@ -0,0 +1,53 @@ +/// +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {Record} */ +const chainInfo = { + agoric: { + chainId: 'agoric-4', + }, + hot: { + allegedName: 'Hot New Chain', + chainId: 'hot-1', + connections: { + 'cosmoshub-4': { + id: 'connection-99', + client_id: '07-tendermint-3', + counterparty: { + client_id: '07-tendermint-2', + connection_id: 'connection-1', + prefix: { + key_prefix: '', + }, + }, + state: 3 /* IBCConnectionState.STATE_OPEN */, + transferChannel: { + portId: 'transfer', + channelId: 'channel-1', + counterPartyChannelId: 'channel-1', + counterPartyPortId: 'transfer', + ordering: 1 /* Order.ORDER_UNORDERED */, + state: 3 /* IBCConnectionState.STATE_OPEN */, + version: 'ics20-1', + }, + }, + }, + }, +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async () => + harden({ + sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js', + getManifestCall: [ + 'getManifestForReviseChains', + { + chainInfo, + }, + ], + }); + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('revise-chain-info', defaultProposalBuilder); +}; diff --git a/packages/orchestration/src/proposals/revise-chain-info.js b/packages/orchestration/src/proposals/revise-chain-info.js new file mode 100644 index 00000000000..b864bfedfc1 --- /dev/null +++ b/packages/orchestration/src/proposals/revise-chain-info.js @@ -0,0 +1,44 @@ +import { makeTracer } from '@agoric/internal'; +import { registerChain } from '../chain-info.js'; + +const trace = makeTracer('ReviseChainInfo', true); + +/** @import {CosmosChainInfo} from '../types.js'; */ + +/** + * This will add news values AND overwrite any existing values. Voters on a + * proposal of core-eval must be careful not to overwrite any values operating + * in production. + * + * @param {BootstrapPowers} powers + * @param {{ options: { chainInfo: Record } }} opt + */ +export const reviseChainInfo = async ( + { consume: { agoricNamesAdmin } }, + { options: { chainInfo } }, +) => { + trace('init-chainInfo'); + + assert(chainInfo, 'chainInfo is required'); + + trace(chainInfo); + + // Now register the names + for await (const [name, info] of Object.entries(chainInfo)) { + await registerChain(agoricNamesAdmin, name, info, trace); + } +}; +harden(reviseChainInfo); + +export const getManifestForReviseChains = (_powers, { chainInfo }) => ({ + manifest: { + [reviseChainInfo.name]: { + consume: { + agoricNamesAdmin: true, + }, + }, + }, + options: { + chainInfo, + }, +});