diff --git a/a3p-integration/proposals/p:upgrade-19/.gitignore b/a3p-integration/proposals/p:upgrade-19/.gitignore index ba9fa18d3e4..70e47ab7438 100644 --- a/a3p-integration/proposals/p:upgrade-19/.gitignore +++ b/a3p-integration/proposals/p:upgrade-19/.gitignore @@ -4,4 +4,4 @@ addUsdLemons/ addUsdOlives/ upgradeProvisionPool/ upgradeAgoricNames/ -appendChainInfo/ +publishTestInfo/ diff --git a/a3p-integration/proposals/p:upgrade-19/agoricNames.test.js b/a3p-integration/proposals/p:upgrade-19/agoricNames.test.js index 7c6173fb7f5..0d61c976b45 100644 --- a/a3p-integration/proposals/p:upgrade-19/agoricNames.test.js +++ b/a3p-integration/proposals/p:upgrade-19/agoricNames.test.js @@ -3,17 +3,21 @@ /** * @file The goal of this file is to test different aspects of agoricNames to make sure * everything works after an upgrade. Here's the test plan; - * 1. upgrade agoricNames - * 2. send a core-eval that writes into children of agoricNames (brand, issuer, instance...) - * 2b. expect a child nameHub of agoricNames will publish ALL its entries when a new item is written to it - * 2c. check the values in the vstorage match before and after the upgrade - * 2d. also check that new items are in the vstorage as well - * 3. append new chain + * 1. publish a new node called 'testInfo' under agoricNames + * CONTEXT: onUpdate callback of testInfo nameAdmin is registered in a core-eval. Which means it is + * both ephemeral and lives in bootstrap vat. We create a scenario like this to make sure any ephemeral + * onUpdate keeps working after an agoricNames upgrade. + * 2. upgrade agoricNames + * 3. send a core-eval that writes into children of agoricNames (brand, issuer, instance...) + * 3b. expect a child nameHub of agoricNames will publish ALL its entries when a new item is written to it + * 3c. check the values in the vstorage match before and after the upgrade + * 3d. also check that new items are in the vstorage as well + * 4. append new chain * CONTEXT: there are two new children introduced to agoricNames by orchestration and their * onUpdate callback isn't durable. So we must check that if we write a new chain info to those child * nameHubs, we should observe the new value in vstorage. - * 3b. send a core-eval that writes new chain info to published.agoricNames.chain and published.agoricNames.chainConnection - * 3c. wait until the expected data observed in vstorage + * 4b. send a core-eval that writes new chain info to published.agoricNames.chain and published.agoricNames.chainConnection + * 4c. wait until the expected data observed in vstorage * * * TESTING CODE THAT HOLDS ONTO 'agoricNames': smartWallet is one of the vats that depend on agoricNames to work properly the most. @@ -29,19 +33,19 @@ * and agoricNames.issuer returned correct values * * - * 4. add a new PSM and swap against it - * 4b. adding the new PSM requires introducing a new asset to the chain and writing - * the PSM instance to agoricNames.instance - * 4c. being able to deposit the new asset to a user means that smartWallet created a purse - * for the new brand - * 4d. being able to send the offer to the PSM instance means smartWallet can find the instance - * in agoricNames.instance + * 5. add a new PSM and swap against it + * 5b. adding the new PSM requires introducing a new asset to the chain and writing + * the PSM instance to agoricNames.instance + * 5c. being able to deposit the new asset to a user means that smartWallet created a purse + * for the new brand + * 5d. being able to send the offer to the PSM instance means smartWallet can find the instance + * in agoricNames.instance * - * 5. we want to make sure objects that were already in agoricNames works as well, so open a vault - * in an existing collateralManager - * 5a. fund GOV1 with ATOM - * 5b. open a vault - * 5c. check the vault is opened successfully + * 6. we want to make sure objects that were already in agoricNames works as well, so open a vault + * in an existing collateralManager + * 6a. fund GOV1 with ATOM + * 6b. open a vault + * 6c. check the vault is opened successfully * */ @@ -67,9 +71,10 @@ import { walletUtils } from './test-lib/index.js'; const AGORIC_NAMES_UPGRADE_DIR = 'agoricNamesCoreEvals/upgradeAgoricNames'; const WRITE_AGORIC_NAMES_DIR = 'agoricNamesCoreEvals/writeToAgoricNames'; -const APPEND_CHAIN_DIR = 'agoricNamesCoreEvals/appendChainInfo'; const ADD_USD_OLIVES_DIR = 'agoricNamesCoreEvals/addUsdOlives'; const DEPOSIT_USD_OLIVES_DIR = 'agoricNamesCoreEvals/depositUsdOlives'; +const PUBLISH_TEST_INFO_DIR = 'agoricNamesCoreEvals/publishTestInfo'; +const WRITE_TEST_INFO_DIR = 'agoricNamesCoreEvals/writeToTestInfo'; const makeWaitUntilKeyFound = (keyFinder, vstorage) => (path, targetKey) => retryUntilCondition( @@ -90,6 +95,29 @@ test.before(async t => { }; }); +test.serial('publish test info', async t => { + // @ts-expect-error casting + const { vstorageKit } = t.context; + + const waitUntilKeyFound = makeWaitUntilKeyFound( + (keys, targetKey) => keys.includes(targetKey), + vstorageKit.vstorage, + ); + + await evalBundles(PUBLISH_TEST_INFO_DIR); + await waitUntilKeyFound('published.agoricNames', 'testInfo'); + + const testInfo = await vstorageKit.readLatestHead( + 'published.agoricNames.testInfo', + ); + t.deepEqual(Object.fromEntries(testInfo), { + agoric: { + isAwesome: 'yes', + tech: ['HardenedJs', 'Orchestration', 'Async_Execution'], + }, + }); +}); + test.serial('upgrade agoricNames', async t => { await evalBundles(AGORIC_NAMES_UPGRADE_DIR); @@ -98,7 +126,7 @@ test.serial('upgrade agoricNames', async t => { }); test.serial('check all existing values are preserved', async t => { - // @ts-expect-error + // @ts-expect-error casting const { vstorageKit } = t.context; const agoricNamesChildren = [ 'brand', @@ -135,59 +163,28 @@ test.serial('check all existing values are preserved', async t => { ); }); -test.serial('check we can add new chains', async t => { - // @ts-expect-error +test.serial('check testInfo still works', async t => { + // @ts-expect-error casting const { vstorageKit } = t.context; - await evalBundles(APPEND_CHAIN_DIR); + await evalBundles(WRITE_TEST_INFO_DIR); - const waitUntilKeyFound = makeWaitUntilKeyFound( - (keys, targetKey) => keys.includes(targetKey), - vstorageKit.vstorage, + const testInfo = await vstorageKit.readLatestHead( + 'published.agoricNames.testInfo', ); - await Promise.all([ - waitUntilKeyFound('published.agoricNames.chain', 'hot'), - waitUntilKeyFound( - 'published.agoricNames.chainConnection', - 'cosmoshub-4_hot-1', - ), - ]); - - const [chainInfo, connectionInfo] = await Promise.all([ - vstorageKit.readLatestHead('published.agoricNames.chain.hot'), - vstorageKit.readLatestHead( - 'published.agoricNames.chainConnection.cosmoshub-4_hot-1', - ), - ]); - - t.log({ - chainInfo, - connectionInfo, - }); - - t.deepEqual(chainInfo, { allegedName: 'Hot New Chain', chainId: 'hot-1' }); - t.deepEqual(connectionInfo, { - client_id: '07-tendermint-2', - counterparty: { - client_id: '07-tendermint-3', - connection_id: 'connection-99', + t.deepEqual(Object.fromEntries(testInfo), { + agoric: { + isAwesome: 'yes', + tech: ['HardenedJs', 'Orchestration', 'Async_Execution'], }, - id: 'connection-1', - state: 3, - transferChannel: { - channelId: 'channel-1', - counterPartyChannelId: 'channel-1', - counterPartyPortId: 'transfer', - ordering: 1, - portId: 'transfer', - state: 3, - version: 'ics20-1', + ethereum: { + isAwesome: 'yes', + tech: ['Solidity', 'EVM'], }, }); }); test.serial('check contracts depend on agoricNames are not broken', async t => { await evalBundles(ADD_USD_OLIVES_DIR); - await evalBundles(DEPOSIT_USD_OLIVES_DIR); const psmSwapIo = { diff --git a/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo-permit.json b/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo-permit.json new file mode 100644 index 00000000000..7204f88ad23 --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo-permit.json @@ -0,0 +1,5 @@ +{ + "consume": { + "agoricNamesAdmin": true + } +} diff --git a/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo.js b/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo.js new file mode 100644 index 00000000000..a155259902b --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo.js @@ -0,0 +1,18 @@ +// @ts-nocheck +/* eslint-disable no-undef */ +const writeToTestInfo = async powers => { + const { + consume: { agoricNamesAdmin }, + } = powers; + + console.log('writing to testInfo...'); + + E(E(agoricNamesAdmin).lookupAdmin('testInfo')).update('ethereum', { + isAwesome: 'yes', + tech: ['Solidity', 'EVM'], + }); + + console.log('DONE'); +}; + +writeToTestInfo; diff --git a/a3p-integration/proposals/p:upgrade-19/package.json b/a3p-integration/proposals/p:upgrade-19/package.json index 1a900e8bee7..d5503b4d1c6 100644 --- a/a3p-integration/proposals/p:upgrade-19/package.json +++ b/a3p-integration/proposals/p:upgrade-19/package.json @@ -9,8 +9,8 @@ "vats/upgrade-board.js", "testing/test-upgraded-board.js testUpgradedBoard", "vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames", - "testing/append-chain-info agoricNamesCoreEvals/appendChainInfo", - "testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives" + "testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives", + "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo" ] }, "type": "module", diff --git a/packages/builders/scripts/testing/publish-test-info.js b/packages/builders/scripts/testing/publish-test-info.js new file mode 100644 index 00000000000..b5798688727 --- /dev/null +++ b/packages/builders/scripts/testing/publish-test-info.js @@ -0,0 +1,79 @@ +import { makeTracer } from '@agoric/internal'; +import { E, Far } from '@endo/far'; +import { makeMarshal } from '@endo/marshal'; + +const trace = makeTracer('PublishTestInfo'); +const { Fail } = assert; + +/** + * @param {BootstrapPowers} powers + */ +export const publishTestInfo = async powers => { + const { + consume: { agoricNamesAdmin, chainStorage: chainStorageP }, + } = powers; + + const chainStorage = await chainStorageP; + if (!chainStorage) { + trace('no chain storage, not registering chain info'); + return; + } + + trace('publishing testInfo'); + const agoricNamesNode = E(chainStorage).makeChildNode('agoricNames'); + const testInfoNode = E(agoricNamesNode).makeChildNode('testInfo'); + const { nameAdmin } = await E(agoricNamesAdmin).provideChild('testInfo'); + + trace('registering onUpdate...'); + await E(nameAdmin).onUpdate( + Far('chain info writer', { + write(entries) { + const marshalData = makeMarshal(_val => Fail`data only`); + const value = JSON.stringify(marshalData.toCapData(entries)); + void E(testInfoNode) + .setValue(value) + .catch(() => + console.log('cannot update vstorage after write to testInfo'), + ); + }, + }), + ); + + trace('writing to testInfo...'); + await E(nameAdmin).update('agoric', { + isAwesome: 'yes', + tech: ['HardenedJs', 'Orchestration', 'Async_Execution'], + }); + + trace('Done.'); +}; + +export const getManifestForPublishTestInfo = () => { + return { + manifest: { + [publishTestInfo.name]: { + consume: { + agoricNamesAdmin: true, + chainStorage: true, + }, + }, + }, + }; +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async () => + harden({ + // Somewhat unorthodox, source the exports from this builder module + sourceSpec: '@agoric/builders/scripts/testing/publish-test-info.js', + getManifestCall: ['getManifestForPublishTestInfo'], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + // import dynamically so the module can work in CoreEval environment + const dspModule = await import('@agoric/deploy-script-support'); + const { makeHelpers } = dspModule; + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('publish-test-info', defaultProposalBuilder); +};