Skip to content

Commit

Permalink
Restore a3p tests (#9557)
Browse files Browse the repository at this point in the history
closes: #9553

## Description
Restores tests deleted in #9481 and fixes a bug in localchain introduced since

### Security Considerations
None

### Scaling Considerations
None

### Documentation Considerations
None

### Testing Considerations
Restoring integration tests

### Upgrade Considerations
Needed for upgrade 16
  • Loading branch information
mergify[bot] committed Jun 22, 2024
2 parents a4f86eb + b5cf8bd commit c65915e
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 9 deletions.
33 changes: 33 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/localchain.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import test from 'ava';

import { agd, evalBundles, waitForBlock } from '@agoric/synthetic-chain';

const SUBMISSION_DIR = 'localchaintest-submission';

const readPublished = async path => {
const { value } = await agd.query(
'vstorage',
'data',
'--output',
'json',
`published.${path}`,
);
if (value === '') {
return undefined;
}
const obj = JSON.parse(value);
return obj.values[0];
};

// The testing assertions are in the submission that runs in the core-eval.
// The test here runs that and confirms the eval made it through all the assertions.
test(`localchain passes tests`, async t => {
await evalBundles(SUBMISSION_DIR);

const nodePath = 'test.localchain';
const nodeValue = JSON.stringify({ success: true });

await waitForBlock(2); // enough time for core eval to execute ?

t.is(await readPublished(nodePath), nodeValue);
});
2 changes: 2 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"coreProposals": []
},
"sdk-generate": [
"vats/probe-zcf-bundle.js probe-submission",
"vats/test-localchain.js localchaintest-submission",
"vats/upgrade-bank.js upgrade-bank",
"vats/upgrade-provisionPool.js upgrade-provisionPool",
"testing/add-LEMONS.js add-LEMONS",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import test from 'ava';
import { getDetailsMatchingVats } from './vatDetails.js';

test('new auction vat', async t => {
const details = await getDetailsMatchingVats('auctioneer');
// This query matches both the auction and its governor, so 2*2
t.is(Object.keys(details).length, 4);
});
27 changes: 27 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/probeZcfBundleCap.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import test from 'ava';

import {
evalBundles,
getIncarnation,
getVatDetails,
} from '@agoric/synthetic-chain';

const SUBMISSION_DIR = 'probe-submission';

test('upgrade Zoe to verify ZcfBundleCap endures', async t => {
await null;
t.assert((await getIncarnation('zoe')) === 1, 'zoe incarnation must be one');

// Before the test, the Wallet Factory should be using the legacy ZCF
const detailsBefore = await getVatDetails('walletFactory');
t.true(detailsBefore.incarnation >= 2, 'wf incarnation must be >= 2');

await evalBundles(SUBMISSION_DIR);

const detailsAfter = await getVatDetails('walletFactory');
t.is(
detailsAfter.incarnation,
detailsBefore.incarnation + 2,
'wf incarnation must increase by 2',
);
});
51 changes: 51 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/provisioning.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @ts-check

import test from 'ava';
import { readFile, writeFile } from 'node:fs/promises';

import {
getIncarnation,
getUser,
evalBundles,
waitForBlock,
agoric,
} from '@agoric/synthetic-chain';

const SUBMISSION_DIR = 'provisioning-test-submission';

/**
* @param {string} fileName base file name without .tjs extension
* @param {Record<string, string>} replacements
*/
const replaceTemplateValuesInFile = async (fileName, replacements) => {
let script = await readFile(`${fileName}.tjs`, 'utf-8');
for (const [template, value] of Object.entries(replacements)) {
script = script.replaceAll(`{{${template}}}`, value);
}
await writeFile(`${fileName}.js`, script);
};

test.serial(`provisioning vat was upgraded`, async t => {
const incarnation = await getIncarnation('provisioning');

t.is(incarnation, 1);
});

test.serial(`send invitation via namesByAddress`, async t => {
const addr = await getUser('gov1');

await replaceTemplateValuesInFile(`${SUBMISSION_DIR}/send-script`, {
ADDRESS: addr,
});

await evalBundles(SUBMISSION_DIR);

await waitForBlock(2); // enough time for invitation to arrive?
const update = await agoric.follow('-lF', `:published.wallet.${addr}`);
t.is(update.updated, 'balance');
t.notDeepEqual(update.currentAmount.value, []);
t.log('balance value', update.currentAmount.value);
t.log('balance brand', update.currentAmount.brand);
// XXX agoric follow returns brands as strings
t.regex(update.currentAmount.brand, /Invitation/);
});
134 changes: 134 additions & 0 deletions a3p-integration/proposals/a:upgrade-next/upgradeVaults.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import test from 'ava';

import {
agops,
ATOM_DENOM,
getISTBalance,
getVatDetails,
openVault,
USER1ADDR,
} from '@agoric/synthetic-chain';

import {
addOraclesForBrand,
bankSend,
BID_OFFER_ID,
checkForOracle,
createBid,
getLiveOffers,
getPriceQuote,
pushPrices,
} from './agd-tools.js';
import { getDetailsMatchingVats } from './vatDetails.js';

const checkPriceFeedVatsUpdated = async t => {
const atomDetails = await getVatDetails('ATOM-USD_price_feed');
// both the original and the new ATOM vault are incarnation 0
t.is(atomDetails.incarnation, 0);
const stAtomDetails = await getVatDetails('stATOM');
t.is(stAtomDetails.incarnation, 0);
const stOsmoDetails = await getVatDetails('stOSMO');
t.is(stOsmoDetails.incarnation, 0);
const stTiaDetails = await getVatDetails('stTIA');
t.is(stTiaDetails.incarnation, 0);
await Promise.all([
checkForOracle(t, 'ATOM'),
checkForOracle(t, 'stATOM'),
checkForOracle(t, 'stTIA'),
checkForOracle(t, 'stOSMO'),
checkForOracle(t, 'stkATOM'),
]);
};

const oraclesByBrand = new Map();

const tryPushPrices = async t => {
// There are no old prices for the other currencies.
const atomOutPre = await getPriceQuote('ATOM');
t.is(atomOutPre, '+12010000');

t.log('adding oracle for each brand');
await addOraclesForBrand('ATOM', oraclesByBrand);
await addOraclesForBrand('stATOM', oraclesByBrand);
await addOraclesForBrand('stTIA', oraclesByBrand);
await addOraclesForBrand('stOSMO', oraclesByBrand);
await addOraclesForBrand('stkATOM', oraclesByBrand);

t.log('pushing new prices');
await pushPrices(11.2, 'ATOM', oraclesByBrand);
await pushPrices(11.3, 'stTIA', oraclesByBrand);
await pushPrices(11.4, 'stATOM', oraclesByBrand);
await pushPrices(11.5, 'stOSMO', oraclesByBrand);
await pushPrices(11.6, 'stkATOM', oraclesByBrand);

t.log('awaiting new quotes');
const atomOut = await getPriceQuote('ATOM');
t.is(atomOut, '+11200000');
const tiaOut = await getPriceQuote('stTIA');
t.is(tiaOut, '+11300000');
const stAtomOut = await getPriceQuote('stATOM');
t.is(stAtomOut, '+11400000');
const osmoOut = await getPriceQuote('stOSMO');
t.is(osmoOut, '+11500000');
const stkAtomOut = await getPriceQuote('stkATOM');
t.is(stkAtomOut, '+11600000');
};

const createNewBid = async t => {
await createBid('20', USER1ADDR, BID_OFFER_ID);
const liveOffer = await getLiveOffers(USER1ADDR);
t.true(liveOffer[0].includes(BID_OFFER_ID));
};

const openMarginalVault = async t => {
let user1IST = await getISTBalance(USER1ADDR);
await bankSend(USER1ADDR, `20000000${ATOM_DENOM}`);
const currentVaults = await agops.vaults('list', '--from', USER1ADDR);

t.log('opening a vault');
await openVault(USER1ADDR, 5, 10);
user1IST += 5;
const istBalanceAfterVaultOpen = await getISTBalance(USER1ADDR);
t.is(istBalanceAfterVaultOpen, user1IST);

const activeVaultsAfter = await agops.vaults('list', '--from', USER1ADDR);
t.log(currentVaults, activeVaultsAfter);
t.true(
activeVaultsAfter.length > currentVaults.length,
`vaults count should increase, ${activeVaultsAfter.length}, ${currentVaults.length}`,
);
};

const triggerAuction = async t => {
await pushPrices(5.2, 'ATOM', oraclesByBrand);

const atomOut = await getPriceQuote('ATOM');
t.is(atomOut, '+5200000');
};

const makeNewAuctionVat = async t => {
const details = await getDetailsMatchingVats('auctioneer');
// This query matches both the auction and its governor, so double the count
t.true(Object.keys(details).length > 2);
};

// test.serial() isn't guaranteed to run tests in order, so we run the intended tests here
test('liquidation post upgrade', async t => {
t.log('starting upgrade vaults test');
await checkPriceFeedVatsUpdated(t);

t.log('starting pushPrices');
await tryPushPrices(t);

t.log('create a new Bid for the auction');
await createNewBid(t);

t.log('open a marginal vault');
await openMarginalVault(t);

t.log('trigger Auction');
await triggerAuction(t);

t.log('make new auction');
await makeNewAuctionVat(t);
});
23 changes: 14 additions & 9 deletions packages/vats/src/localchain.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AmountShape, BrandShape, PaymentShape } from '@agoric/ertp';
import { Shape as NetworkShape } from '@agoric/network';

const { Fail } = assert;
const { Vow$ } = NetworkShape;

/**
* @import {TypedJson, ResponseTo, JsonSafe} from '@agoric/cosmic-proto';
Expand Down Expand Up @@ -45,15 +46,17 @@ const { Fail } = assert;
*/

export const LocalChainAccountI = M.interface('LocalChainAccount', {
getAddress: M.callWhen().returns(M.string()),
getBalance: M.callWhen(BrandShape).returns(AmountShape),
getAddress: M.callWhen().returns(Vow$(M.string())),
getBalance: M.callWhen(BrandShape).returns(Vow$(AmountShape)),
deposit: M.callWhen(PaymentShape)
.optional(M.pattern())
.returns(NetworkShape.Vow$(AmountShape)),
withdraw: M.callWhen(AmountShape).returns(PaymentShape),
executeTx: M.callWhen(M.arrayOf(M.record())).returns(M.arrayOf(M.record())),
.returns(Vow$(AmountShape)),
withdraw: M.callWhen(AmountShape).returns(Vow$(PaymentShape)),
executeTx: M.callWhen(M.arrayOf(M.record())).returns(
Vow$(M.arrayOf(M.record())),
),
monitorTransfers: M.callWhen(M.remotable('TransferTap')).returns(
M.remotable('TargetRegistration'),
Vow$(M.remotable('TargetRegistration')),
),
});

Expand Down Expand Up @@ -192,9 +195,11 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
/** @typedef {LocalChainAccountKit['account']} LocalChainAccount */

export const LocalChainI = M.interface('LocalChain', {
makeAccount: M.callWhen().returns(M.remotable('LocalChainAccount')),
query: M.callWhen(M.record()).returns(M.record()),
queryMany: M.callWhen(M.arrayOf(M.record())).returns(M.arrayOf(M.record())),
makeAccount: M.callWhen().returns(Vow$(M.remotable('LocalChainAccount'))),
query: M.callWhen(M.record()).returns(Vow$(M.record())),
queryMany: M.callWhen(M.arrayOf(M.record())).returns(
Vow$(M.arrayOf(M.record())),
),
});

/**
Expand Down

0 comments on commit c65915e

Please sign in to comment.