Skip to content

Commit

Permalink
chore(vat-upgrade): enhance test coverage of agoricNames functionalit…
Browse files Browse the repository at this point in the history
…y after upgrade

Refs: #10408
  • Loading branch information
anilhelvaci committed Dec 5, 2024
1 parent ecc1cda commit 890ad0b
Show file tree
Hide file tree
Showing 14 changed files with 1,944 additions and 69 deletions.
3 changes: 2 additions & 1 deletion a3p-integration/proposals/p:upgrade-19/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
replaceFeeDistributor/
testUpgradedBoard/
addUsdLemons/
addUsdOlives/
upgradeProvisionPool/
upgradeAgoricNames/

appendChainInfo/
211 changes: 174 additions & 37 deletions a3p-integration/proposals/p:upgrade-19/agoricNames.test.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,83 @@
/* eslint-env node */

/**
* @file
* Ideas:
* - write something new to agoricNames and check vstorage
* - can you add a new chain for orc?
* - can you add a new psm?
* - can you open a vault?
* @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
* 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
*
*
* TESTING CODE THAT HOLDS ONTO 'agoricNames': smartWallet is one of the vats that depend on agoricNames to work properly the most.
* smartWallet uses agoricNames to;
* - create purses for known brands
* - looks for the brand in agoricNames.brand
* - creates a purse for the brand using the issuer in agoricNames.issuer
* - create invitations for a from the publicFacet of a given instance (agoricNames.instance)
*
* So the fact that a user can complete an offer successfully means;
* - smartWallet can find the instance on agoricNames.instance (for invitationSource = 'agoricContract')
* - smartWallet can find, if not present create, a purse for known brand, agoricNames.brand
* 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. 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
*
*/

import '@endo/init';
import test from 'ava';
import {
evalBundles,
agd as agdAmbient,
agoric,
getDetailsMatchingVats,
ATOM_DENOM,
evalBundles,
getIncarnation,
GOV1ADDR,
openVault,
} from '@agoric/synthetic-chain';
import { makeVstorageKit } from '@agoric/client-utils';

const AGORIC_NAMES_UPGRADE_DIR = 'upgradeAgoricNames';
const WRITE_AGORIC_NAMES = 'writeToAgoricNames';

const ambientAuthority = {
query: agdAmbient.query,
follow: agoric.follow,
setTimeout,
log: console.log,
};
import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils';
import {
bankSend,
extractBalance,
psmSwap,
tryISTBalances,
} from './test-lib/psm-lib.js';
import { getBalances, listVaults } from './test-lib/utils.js';
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 makeWaitUntilKeyFound = (keyFinder, vstorage) => (path, targetKey) =>
retryUntilCondition(
() => vstorage.keys(path),
keys => keyFinder(keys, targetKey),
'Key not found.',
{ maxRetries: 5, retryIntervalMs: 2000, log: console.log, setTimeout },
);

test.before(async t => {
const vstorageKit = await makeVstorageKit(
Expand All @@ -40,20 +90,14 @@ test.before(async t => {
};
});

test.serial.only('upgrade agoricNames', async t => {
test.serial('upgrade agoricNames', async t => {
await evalBundles(AGORIC_NAMES_UPGRADE_DIR);

const vatDetailsAfter = await getDetailsMatchingVats('agoricNames');
const { incarnation } = vatDetailsAfter.find(vat =>
vat.vatName.endsWith('agoricNames'),
);

t.log(vatDetailsAfter);
const incarnation = await getIncarnation('agoricNames');
t.is(incarnation, 1, 'incorrect incarnation');
t.pass();
});

test.serial.only('check all existing values are preserved', async t => {
test.serial('check all existing values are preserved', async t => {
// @ts-expect-error
const { vstorageKit } = t.context;
const agoricNamesChildren = [
Expand All @@ -78,7 +122,7 @@ test.serial.only('check all existing values are preserved', async t => {
const agoricNamesBefore = await getAgoricNames();
console.log('AGORIC_NAMES_BEFORE', agoricNamesBefore);

await evalBundles(WRITE_AGORIC_NAMES);
await evalBundles(WRITE_AGORIC_NAMES_DIR);

const agoricNamesAfter = await getAgoricNames();
t.like(agoricNamesAfter, agoricNamesBefore);
Expand All @@ -91,12 +135,105 @@ test.serial.only('check all existing values are preserved', async t => {
);
});

test.serial.only('check we can add new chains', async t => {
await evalBundles('chainInfoTest');
t.pass();
test.serial('check we can add new chains', async t => {
// @ts-expect-error
const { vstorageKit } = t.context;
await evalBundles(APPEND_CHAIN_DIR);

const waitUntilKeyFound = makeWaitUntilKeyFound(
(keys, targetKey) => keys.includes(targetKey),
vstorageKit.vstorage,
);
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',
},
id: 'connection-1',
state: 3,
transferChannel: {
channelId: 'channel-1',
counterPartyChannelId: 'channel-1',
counterPartyPortId: 'transfer',
ordering: 1,
portId: 'transfer',
state: 3,
version: 'ics20-1',
},
});
});

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 = {
now: Date.now,
follow: agoric.follow,
setTimeout,
log: console.log,
};

const balancesBefore = await getBalances([GOV1ADDR]);

await psmSwap(
GOV1ADDR,
['swap', '--pair', 'IST.USD_OLIVES', '--wantMinted', 1],
psmSwapIo,
);

const balancesAfter = await getBalances([GOV1ADDR]);
await tryISTBalances(
t,
extractBalance(balancesAfter, 'uist'),
extractBalance(balancesBefore, 'uist') + 1000000, // in uist
);
});

test.serial.skip(
'check contracts depend on agoricNames are not broken',
async t => {},
);
test.serial('open a vault', async t => {
await bankSend(GOV1ADDR, `200000000000000000${ATOM_DENOM}`);
const istBalanceBefore = await getBalances([GOV1ADDR]);
const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils);

const mint = '5.0';
const collateral = '10.0';
await openVault(GOV1ADDR, mint, collateral);

const istBalanceAfter = await getBalances([GOV1ADDR]);
const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils);

await tryISTBalances(
t,
extractBalance(istBalanceAfter, 'uist'),
extractBalance(istBalanceBefore, 'uist') + 5000000,
);

t.is(
activeVaultsAfter.length,
activeVaultsBefore.length + 1,
`The number of active vaults should increase after opening a new vault.`,
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"consume": {
"contractKits": true,
"namesByAddressAdmin": true,
"agoricNames": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// @ts-nocheck
/* eslint-disable no-undef */
const GOV_ONE_ADDR = 'agoric1ee9hr0jyrxhy999y755mp862ljgycmwyp4pl7q';

const depositUsdOlives = async powers => {
const {
consume: {
contractKits: contractKitsP,
namesByAddressAdmin: namesByAddressAdminP,
agoricNames,
},
} = powers;

const namesByAddressAdmin = await namesByAddressAdminP;

const getDepositFacet = async address => {
const hub = E(E(namesByAddressAdmin).lookupAdmin(address)).readonly();
return E(hub).lookup('depositFacet');
};

const [contractKits, usdOlivesIssuer, usdOlivesBrand, ppDepositFacet] =
await Promise.all([
contractKitsP,
E(agoricNames).lookup('issuer', 'USD_OLIVES'),
E(agoricNames).lookup('brand', 'USD_OLIVES'),
getDepositFacet(GOV_ONE_ADDR),
]);

console.log('[CONTRACT_KITS]', contractKits);
console.log('[ISSUER]', usdOlivesIssuer);

let usdOlivesMint;
for (const { publicFacet, creatorFacet: mint } of contractKits.values()) {
if (publicFacet === usdOlivesIssuer) {
usdOlivesMint = mint;
console.log('BINGO', mint);
break;
}
}

console.log('Minting USD_OLIVES');
const helloPayment = await E(usdOlivesMint).mintPayment(
harden({ brand: usdOlivesBrand, value: 1_000_000n }),
);

console.log('Funding provision pool...');
await E(ppDepositFacet).receive(helloPayment);

console.log('Done.');
};

depositUsdOlives;
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"consume": {
"agoricNamesAdmin": true
}
}
}
5 changes: 4 additions & 1 deletion a3p-integration/proposals/p:upgrade-19/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"vats/upgrade-paRegistry.js",
"vats/upgrade-board.js",
"testing/test-upgraded-board.js testUpgradedBoard",
"vats/upgrade-agoricNames.js upgradeAgoricNames"
"vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames",
"testing/append-chain-info agoricNamesCoreEvals/appendChainInfo",
"testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives"
]
},
"type": "module",
Expand All @@ -22,6 +24,7 @@
"@endo/errors": "1.2.7",
"@endo/init": "^1.1.5",
"@endo/marshal": "^1.5.4",
"agoric": "dev",
"ava": "^5.3.1",
"better-sqlite3": "^9.6.0",
"execa": "9.1.0"
Expand Down
20 changes: 20 additions & 0 deletions a3p-integration/proposals/p:upgrade-19/test-lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-env node */
import { makeWalletUtils } from '@agoric/client-utils';

export const networkConfig = {
rpcAddrs: ['http://0.0.0.0:26657'],
chainName: 'agoriclocal',
};

/**
* Resolve after a delay in milliseconds.
*
* @param {number} ms
* @returns {Promise<void>}
*/
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));

export const walletUtils = await makeWalletUtils(
{ delay, fetch },
networkConfig,
);
Loading

0 comments on commit 890ad0b

Please sign in to comment.