Skip to content

Commit

Permalink
chore(vat-upgrade): simulate what init-chain-info.js is doing
Browse files Browse the repository at this point in the history
2195ace removes write-chain-info.js from f:fast-usdc. So we simulate what is does (relative to agoricNames) in order to test ephemeral onUpdate callbacks keep working after an agoricNames upgrade.

Refs: #10408
  • Loading branch information
anilhelvaci committed Dec 7, 2024
1 parent 6dc28f7 commit 47c9309
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 68 deletions.
2 changes: 1 addition & 1 deletion a3p-integration/proposals/p:upgrade-19/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ addUsdLemons/
addUsdOlives/
upgradeProvisionPool/
upgradeAgoricNames/
appendChainInfo/
publishTestInfo/
127 changes: 62 additions & 65 deletions a3p-integration/proposals/p:upgrade-19/agoricNames.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
*
*/

Expand All @@ -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(
Expand All @@ -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);

Expand All @@ -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',
Expand Down Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"consume": {
"agoricNamesAdmin": true
}
}
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 2 additions & 2 deletions a3p-integration/proposals/p:upgrade-19/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
79 changes: 79 additions & 0 deletions packages/builders/scripts/testing/publish-test-info.js
Original file line number Diff line number Diff line change
@@ -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);
};

0 comments on commit 47c9309

Please sign in to comment.