diff --git a/.eslintrc.cjs b/.eslintrc.cjs index a5a24ebb5597..730431574277 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -119,5 +119,13 @@ module.exports = { project: false, }, }, + { + files: ['packages/**/upgrade-test-scripts/**/*.*js'], + rules: { + // NOTE: This rule is enabled for the repository in general. We turn it + // off for test code for now. + '@jessie.js/safe-await-separator': 'off', + }, + }, ], }; diff --git a/packages/deployment/upgrade-test/Dockerfile b/packages/deployment/upgrade-test/Dockerfile index 6ef270a54e37..ed8eb49b1313 100644 --- a/packages/deployment/upgrade-test/Dockerfile +++ b/packages/deployment/upgrade-test/Dockerfile @@ -60,10 +60,10 @@ ARG DEST_IMAGE #this is agoric-upgrade-10 / vaults FROM ghcr.io/agoric/agoric-sdk:35 as agoric-upgrade-10 ARG BOOTSTRAP_MODE -ENV THIS_NAME=agoric-upgrade-10 BOOTSTRAP_MODE=${BOOTSTRAP_MODE} +ENV THIS_NAME=agoric-upgrade-10 USE_JS=1 BOOTSTRAP_MODE=${BOOTSTRAP_MODE} WORKDIR /usr/src/agoric-sdk/ -COPY ./bash_entrypoint.sh ./env_setup.sh ./start_to_to.sh ./upgrade-test-scripts/ +COPY ./bash_entrypoint.sh ./env_setup.sh ./start_to_to.sh ./package.json ./*.mjs ./upgrade-test-scripts/ COPY ./${THIS_NAME} ./upgrade-test-scripts/${THIS_NAME}/ COPY --from=agoric-upgrade-9 /root/.agoric /root/.agoric RUN chmod +x ./upgrade-test-scripts/*.sh diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/.keep b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/.keep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.mjs new file mode 100644 index 000000000000..2d0c654da287 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.mjs @@ -0,0 +1,342 @@ +import { promises as fs } from 'fs'; +import assert from 'assert'; + +import { + waitForBlock, + provisionSmartWallet, + getUser, + executeOffer, +} from './upgradeHelpers.mjs'; +import { + agd, + agoric, + agops, + agopsLocation, + executeCommand, +} from '../cliHelper.mjs'; +import { + HOME, + ATOM_DENOM, + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, +} from '../constants.mjs'; + +const govAccounts = [GOV1ADDR, GOV2ADDR, GOV3ADDR]; + +const acceptEC = async () => { + console.log('ACTIONS Tickling the wallets so they are revived'); + + let voter = 0; + for (const account of govAccounts) { + console.log(`${account}: 1: Accepting EC Committee`); + + try { + const params = ['ec', 'committee', '--send-from', account]; + await executeCommand(agopsLocation, params, { + timeout: 30000, + }); + } catch (error) { + console.warn(error.message); + } + + await waitForBlock(3); + + console.log(`${account}: 2: Accepting EC Committee`); + + try { + await agops.ec('committee', '--send-from', account, '--voter', voter); + } catch (error) { + console.warn(error.message); + } + + voter += 1; + + await waitForBlock(3); + + console.log(`${account}: Accepting EC Charter`); + + try { + await agops.ec('charter', '--send-from', account); + } catch (error) { + console.warn(error.message); + } + } +}; + +const acceptOracles = oracles => { + const promiseArray = []; + + for (const oracle of oracles) { + console.log(`${oracle.address}: Accept oracle invitations`); + promiseArray.push( + executeOffer( + oracle.address, + agops.oracle('accept', '--offerId', oracle.id), + ), + ); + } + + return Promise.all(promiseArray); +}; + +const proposeNewAuctionParams = async ( + address, + startFequency, + clockStep, + priceLockPeriod, +) => { + const charterAcceptOfferId = await agops.ec( + 'find-continuing-id', + '--for', + `${'charter\\ member\\ invitation'}`, + '--from', + address, + ); + + return executeOffer( + address, + agops.auctioneer( + 'proposeParamChange', + '--charterAcceptOfferId', + charterAcceptOfferId, + '--start-frequency', + startFequency, + '--clock-step', + clockStep, + '--price-lock-period', + priceLockPeriod, + ), + ); +}; + +const voteForNewParams = (accounts, position) => { + return Promise.all( + accounts.map(account => + agops.ec('vote', '--forPosition', position, '--send-from', account), + ), + ); +}; + +const paramChangeOfferGeneration = async ( + previousOfferId, + voteDur, + debtLimit, +) => { + const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 } + const voteDurSec = BigInt(voteDur); + const debtLimitValue = BigInt(debtLimit) * ISTunit; + const toSec = ms => BigInt(Math.round(ms / 1000)); + + const id = `propose-${Date.now()}`; + const deadline = toSec(Date.now()) + voteDurSec; + + const zip = (xs, ys) => xs.map((x, i) => [x, ys[i]]); + const fromSmallCapsEntries = txt => { + const { body, slots } = JSON.parse(txt); + const theEntries = zip(JSON.parse(body.slice(1)), slots).map( + ([[name, ref], boardID]) => { + const iface = ref.replace(/^\$\d+\./, ''); + return [name, { iface, boardID }]; + }, + ); + return Object.fromEntries(theEntries); + }; + + const slots = []; // XXX global mutable state + const smallCaps = { + Nat: n => `+${n}`, + // XXX mutates obj + ref: obj => { + if (obj.ix) return obj.ix; + const ix = slots.length; + slots.push(obj.boardID); + obj.ix = `$${ix}.Alleged: ${obj.iface}`; + return obj.ix; + }, + }; + + const instance = fromSmallCapsEntries( + await agoric.follow('-lF', ':published.agoricNames.instance', '-o', 'text'), + ); + assert(instance.VaultFactory); + + const brand = fromSmallCapsEntries( + await agoric.follow('-lF', ':published.agoricNames.brand', '-o', 'text'), + ); + assert(brand.IST); + assert(brand.ATOM); + + const body = { + method: 'executeOffer', + offer: { + id, + invitationSpec: { + invitationMakerName: 'VoteOnParamChange', + previousOffer: previousOfferId, + source: 'continuing', + }, + offerArgs: { + deadline: smallCaps.Nat(deadline), + instance: smallCaps.ref(instance.VaultFactory), + params: { + DebtLimit: { + brand: smallCaps.ref(brand.IST), + value: smallCaps.Nat(debtLimitValue), + }, + }, + path: { + paramPath: { + key: { + collateralBrand: smallCaps.ref(brand.ATOM), + }, + }, + }, + }, + proposal: {}, + }, + }; + + const capData = { body: `#${JSON.stringify(body)}`, slots }; + return JSON.stringify(capData); +}; + +export const provisionWallet = async user => { + const userKeyData = await agd.keys('add', user, '--keyring-backend=test'); + await fs.writeFile(`${HOME}/.agoric/${user}.key`, userKeyData.mnemonic); + + const userAddress = await getUser(user); + + await provisionSmartWallet( + userAddress, + `20000000ubld,100000000${ATOM_DENOM}`, + ); + await waitForBlock(); +}; + +export const implementNewAuctionParams = async ( + address, + oracles, + startFequency, + clockStep, + priceLockPeriod, +) => { + await acceptEC(); + await waitForBlock(3); + + await acceptOracles(oracles); + + await proposeNewAuctionParams( + address, + startFequency, + clockStep, + priceLockPeriod, + ); + + console.log('ACTIONS voting for new auction params'); + await voteForNewParams(govAccounts, 0); + + console.log('ACTIONS wait for the vote deadline to pass'); + await new Promise(r => setTimeout(r, 65000)); +}; + +export const proposeNewDebtCeiling = async address => { + const charterAcceptOfferId = await agops.ec( + 'find-continuing-id', + '--for', + `${'charter\\ member\\ invitation'}`, + '--from', + address, + ); + + return executeOffer( + address, + paramChangeOfferGeneration(charterAcceptOfferId, 30, 123000000), + ); +}; + +export const raiseDebtCeiling = async address => { + console.log('ACTIONS Raising debt limit'); + + await proposeNewDebtCeiling(address); + await voteForNewParams(govAccounts, 0); + + console.log('ACTIONS wait for the vote to pass'); + await new Promise(r => setTimeout(r, 65000)); +}; + +export const openVault = (address, mint, collateral) => { + return executeOffer( + address, + agops.vaults('open', '--wantMinted', mint, '--giveCollateral', collateral), + ); +}; + +export const adjustVault = (address, vaultId, vaultParams) => { + let params = [ + 'adjust', + '--vaultId', + vaultId, + '--from', + address, + ' --keyring-backend=test', + ]; + + if ('wantCollateral' in vaultParams) { + params = [...params, '--wantCollateral', vaultParams.wantCollateral]; + } + + if ('wantMinted' in vaultParams) { + params = [...params, '--wantMinted', vaultParams.wantMinted]; + } + + if ('giveCollateral' in vaultParams) { + params = [...params, '--giveCollateral', vaultParams.giveCollateral]; + } + + if ('giveMinted' in vaultParams) { + params = [...params, '--giveMinted', vaultParams.giveMinted]; + } + + return executeOffer(address, agops.vaults(...params)); +}; + +export const closeVault = (address, vaultId, mint) => { + return executeOffer( + address, + agops.vaults( + 'close', + '--vaultId', + vaultId, + '--giveMinted', + mint, + '--from', + address, + '--keyring-backend=test', + ), + ); +}; + +export const pushPrice = (oracles, price = 10.0) => { + console.log(`ACTIONS pushPrice ${price}`); + const promiseArray = []; + + for (const oracle of oracles) { + console.log(`Pushing Price from oracle ${oracle.address}`); + + promiseArray.push( + executeOffer( + oracle.address, + agops.oracle( + 'pushPriceRound', + '--price', + price, + '--oracleAdminAcceptOfferId', + oracle.id, + ), + ), + ); + } + + return Promise.all(promiseArray); +}; diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.sh deleted file mode 100644 index cc53553a99ba..000000000000 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/bin/bash - -. ./upgrade-test-scripts/env_setup.sh - -# Enable debugging -set -x - -# For development: -# TARGET=agoric-upgrade-10 make local_sdk build_test run -# agoric wallet show --from $GOV1ADDR -waitForBlock 20 - -# user1 has no mailbox provisioned; later we test that this was discarded -submitDeliverInbound user1 - -# provision a new user wallet - -agd keys add user2 --keyring-backend=test 2>&1 | tee "$HOME/.agoric/user2.out" -cat "$HOME/.agoric/user2.out" | tail -n1 | tee "$HOME/.agoric/user2.key" -export USER2ADDR=$($binary keys show user2 -a --keyring-backend="test" 2> /dev/null) -provisionSmartWallet $USER2ADDR "20000000ubld,100000000${ATOM_DENOM}" -waitForBlock - -test_not_val "$(agd q vstorage data published.wallet.$USER2ADDR -o json | jq -r .value)" "" "ensure user2 provisioned" - -echo "ACTIONS Tickling the wallets so they are revived" -# Until they are revived, the invitations can't be deposited. So the first action can't be to accept an invitation (because it won't be there). -govaccounts=("$GOV1ADDR" "$GOV2ADDR" "$GOV3ADDR") -cm=0 -for i in "${govaccounts[@]}"; do - for run in {1..2}; do - echo "$i: $run: Accepting EC Committee" - if [[ "$run" == "1" ]]; then - timeout 3 yarn run --silent agops ec committee --send-from "$i" || true - else - agops ec committee --send-from "$i" --voter "$cm" - cm=$((cm + 1)) - fi - waitForBlock 3 - done - echo "$i: Accepting EC Charter" - agops ec charter --send-from "$i" -done - -waitForBlock 3 - -oracles=("$GOV1ADDR" "$GOV2ADDR") -for i in "${oracles[@]}"; do - echo "$i: Accept oracle invitations" - ORACLE_OFFER=$(mktemp -t agops.XXX) - OFFER_ID="$(newOfferId)" - agops oracle accept --offerId "$OFFER_ID" >|"$ORACLE_OFFER" - agoric wallet print --file "$ORACLE_OFFER" - agops perf satisfaction --from "$i" --executeOffer "$ORACLE_OFFER" --keyring-backend=test - echo "${i}_ORACLE=$OFFER_ID" >>"$HOME/.agoric/envs" -done - -echo ACTIONS Sourcing environment -source "$HOME/.agoric/envs" - -echo ACTIONS proposing new auction params -START_FREQUENCY=600 #StartFrequency: 600s (auction runs every 10m) -CLOCK_STEP=20 #ClockStep: 20s (ensures auction completes in time) -PRICE_LOCK_PERIOD=300 - -FASTER_AUCTIONS_OFFER=$(mktemp -t agops.XXX) -agops auctioneer proposeParamChange --charterAcceptOfferId "$(agops ec find-continuing-id --for "charter member invitation" --from "$GOV1ADDR")" --start-frequency $START_FREQUENCY --clock-step $CLOCK_STEP --price-lock-period $PRICE_LOCK_PERIOD >|"$FASTER_AUCTIONS_OFFER" -agoric wallet print --file "$FASTER_AUCTIONS_OFFER" -agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$FASTER_AUCTIONS_OFFER" --keyring-backend=test - -echo ACTIONS voting for new auction params -govaccounts=("$GOV1ADDR" "$GOV2ADDR" "$GOV3ADDR") -for i in "${govaccounts[@]}"; do - agops ec vote --forPosition 0 --send-from "$i" -done - -echo ACTIONS wait for the vote deadline to pass -sleep 65 - -echo ACTIONS ensuring params were changed -test_val "$(agoric follow -l -F :published.auction.governance -o jsonlines | jq -r .current.ClockStep.value.relValue)" "$CLOCK_STEP" -test_val "$(agoric follow -l -F :published.auction.governance -o jsonlines | jq -r .current.StartFrequency.value.relValue)" "$START_FREQUENCY" - -##### -echo ACTIONS Raising debt limit -DEBT_LIMIT_OFFER=$(mktemp -t agops.XXX) -previous="$(agops ec find-continuing-id --for "charter member invitation" --from "$GOV1ADDR")" -node ./upgrade-test-scripts/agoric-upgrade-10/param-change-offer-gen.mjs $previous 30 123000000 >|"$DEBT_LIMIT_OFFER" -agoric wallet print --file "$DEBT_LIMIT_OFFER" -agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$DEBT_LIMIT_OFFER" --keyring-backend=test - -# wait for question to post. XXX right way is to check deadline of .latestQuestion -waitForBlock 3 - -govaccounts=("$GOV1ADDR" "$GOV2ADDR" "$GOV3ADDR") -for i in "${govaccounts[@]}"; do - agops ec vote --forPosition 0 --send-from "$i" -done - -echo ACTIONS wait for the vote to pass -sleep 65 - -echo ACTIONS ensure params were changed -test_val "$(agoric follow -l -F :published.vaultFactory.managers.manager0.governance -o jsonlines | jq -r .current.DebtLimit.value.value)" "123000000000000" - -pushPrice 12.01 - -## vaults -# attempt to open vaults under the minimum amount -for vid in {1..2}; do - OFFER=$(mktemp -t agops.XXX) - if [[ "$vid" == "2" ]]; then - amount=3.00 - collateral=5.0 - else - amount=2.00 - collateral=4.0 - fi - agops vaults open --wantMinted $amount --giveCollateral $collateral >|"$OFFER" - agoric wallet print --file "$OFFER" - agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test || true -done - -# we should still have no vaults -test_val "$(agops vaults list --from $GOV1ADDR)" "" "gov1 has no vaults" - -# open up some vaults -for vid in {1..2}; do - OFFER=$(mktemp -t agops.XXX) - if [[ "$vid" == "2" ]]; then - amount=6.00 - collateral=10.0 - else - amount=5.00 - collateral=9.0 - fi - agops vaults open --wantMinted $amount --giveCollateral $collateral >|"$OFFER" - agoric wallet print --file "$OFFER" - agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test -done - -# remove some collateral from the first vault -OFFER=$(mktemp -t agops.XXX) -agops vaults adjust --vaultId vault0 --wantCollateral 1.0 --from $GOV1ADDR --keyring-backend="test" >|"$OFFER" -agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# take some IST from the first vault, increasing debt -OFFER=$(mktemp -t agops.XXX) -agops vaults adjust --vaultId vault0 --wantMinted 1.0 --from $GOV1ADDR --keyring-backend="test" >|"$OFFER" -agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# close the second vault -OFFER=$(mktemp -t agops.XXX) -agops vaults close --vaultId vault1 --giveMinted 6.06 --from $GOV1ADDR --keyring-backend="test" >|"$OFFER" -agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# make sure the same works for user2 -OFFER=$(mktemp -t agops.XXX) -agops vaults open --wantMinted 7.00 --giveCollateral 11.0 >|"$OFFER" -agops perf satisfaction --from "$USER2ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# put some IST in -OFFER=$(mktemp -t agops.XXX) -agops vaults adjust --vaultId vault2 --giveMinted 1.5 --from $USER2ADDR --keyring-backend=test >|"$OFFER" -agops perf satisfaction --from "$USER2ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# add some collateral -OFFER=$(mktemp -t agops.XXX) -agops vaults adjust --vaultId vault2 --giveCollateral 2.0 --from $USER2ADDR --keyring-backend="test" >|"$OFFER" -agops perf satisfaction --from "$USER2ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# close out -OFFER=$(mktemp -t agops.XXX) -agops vaults close --vaultId vault2 --giveMinted 5.75 --from $USER2ADDR --keyring-backend="test" >|"$OFFER" -agops perf satisfaction --from "$USER2ADDR" --executeOffer "$OFFER" --keyring-backend=test - -# replicate state-sync of node -# this will cause the swing-store to prune some data -# we will save the pruned artifact for later -killAgd -EXPORT_DIR=$(mktemp -t -d swing-store-export-upgrade-10-XXX) -make_swing_store_snapshot $EXPORT_DIR || fail "Couldn't make swing-store snapshot" -test_val "$(compare_swing_store_export_data $EXPORT_DIR)" "match" "swing-store export data" -EXPORT_DIR_ALL_ARTIFACTS=$(mktemp -t -d swing-store-export-upgrade-10-all-artifacts-XXX) -make_swing_store_snapshot $EXPORT_DIR_ALL_ARTIFACTS --export-mode archival || fail "Couldn't make swing-store snapshot for historical artifacts" -restore_swing_store_snapshot $EXPORT_DIR || fail "Couldn't restore swing-store snapshot" -( - cd $EXPORT_DIR_ALL_ARTIFACTS - mkdir $HOME/.agoric/data/agoric/swing-store-historical-artifacts - for i in *; do - [ -f $EXPORT_DIR/$i ] && continue - mv $i $HOME/.agoric/data/agoric/swing-store-historical-artifacts/ - done -) -rm -rf $EXPORT_DIR -rm -rf $EXPORT_DIR_ALL_ARTIFACTS -startAgd - -# # TODO fully test bidding -# # TODO test liquidations -agops inter bid by-price --price 1 --give 1.0IST --from $GOV1ADDR --keyring-backend test diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.test.js b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.test.js new file mode 100644 index 000000000000..2fcec2ab6ed7 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/actions.test.js @@ -0,0 +1,108 @@ +import test from 'ava'; + +import { + waitForBlock, + submitDeliverInbound, + getUser, + newOfferId, +} from './upgradeHelpers.mjs'; +import { + provisionWallet, + implementNewAuctionParams, + raiseDebtCeiling, + openVault, + adjustVault, + closeVault, + pushPrice, +} from './actions.mjs'; +import { agd, agoric, agops } from '../cliHelper.mjs'; +import { GOV1ADDR, GOV2ADDR } from '../constants.mjs'; + +const START_FREQUENCY = 600; // StartFrequency: 600s (auction runs every 10m) +const CLOCK_STEP = 20; // ClockStep: 20s (ensures auction completes in time) +const PRICE_LOCK_PERIOD = 300; +const oraclesAddresses = [GOV1ADDR, GOV2ADDR]; + +test.before(async t => { + await waitForBlock(2); + await submitDeliverInbound('user1'); + + const oracles = []; + for (const oracle of oraclesAddresses) { + const offerId = await newOfferId(); + oracles.push({ address: oracle, id: offerId }); + } + + t.context.oracles = oracles; +}); + +test.serial('Ensure user2 provisioned', async t => { + await provisionWallet('user2'); + + const user2Address = await getUser('user2'); + const data = await agd.query( + 'vstorage', + 'data', + `published.wallet.${user2Address}`, + ); + + t.not(data.value, ''); +}); + +test.serial('Ensure auction params have changed', async t => { + await implementNewAuctionParams( + GOV1ADDR, + t.context.oracles, + START_FREQUENCY, + CLOCK_STEP, + PRICE_LOCK_PERIOD, + ); + + const govParams = await agoric.follow('-lF', ':published.auction.governance'); + t.is(govParams.current.ClockStep.value.relValue, CLOCK_STEP.toString()); + t.is( + govParams.current.StartFrequency.value.relValue, + START_FREQUENCY.toString(), + ); +}); + +test.serial('Ensure debt ceiling raised', async t => { + await raiseDebtCeiling(GOV1ADDR); + const params = await agoric.follow( + '-lF', + ':published.vaultFactory.managers.manager0.governance', + ); + t.is(params.current.DebtLimit.value.value, '123000000000000'); +}); + +test.serial('Update oracle prices', async t => { + await pushPrice(t.context.oracles, 12.01); + + t.pass(); +}); + +test.serial('Open Vaults', async t => { + const currentVaults = await agops.vaults('list', '--from', GOV1ADDR); + t.is(currentVaults.length, 0); + + const vaults = [ + { mint: 5.0, collateral: 9.0 }, + { mint: 6.0, collateral: 10.0 }, + ]; + + for (const vault of vaults) { + await openVault(GOV1ADDR, vault.mint, vault.collateral); + } + + await adjustVault(GOV1ADDR, 'vault0', { wantCollateral: 1.0 }); + await adjustVault(GOV1ADDR, 'vault0', { wantMinted: 1.0 }); + await closeVault(GOV1ADDR, 'vault1', 6.06); + + const user2 = await getUser('user2'); + await openVault(user2, 7, 11); + await adjustVault(user2, 'vault2', { giveMinted: 1.5 }); + await adjustVault(user2, 'vault2', { giveCollateral: 2.0 }); + await closeVault(user2, 'vault2', 5.75); + + t.pass(); +}); diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/env_setup.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/env_setup.sh deleted file mode 100644 index 22d6425887fc..000000000000 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/env_setup.sh +++ /dev/null @@ -1,156 +0,0 @@ -#!/bin/bash - -# agoric-upgrade-10 specific env here... -export USER2ADDR=$($binary keys show user2 -a --keyring-backend="test" 2> /dev/null) - -printKeys() { - echo "========== GOVERNANCE KEYS ==========" - echo "gov1: $GOV1ADDR" - cat ~/.agoric/gov1.key || true - echo "gov2: $GOV2ADDR" - cat ~/.agoric/gov2.key || true - echo "gov3: $GOV3ADDR" - cat ~/.agoric/gov3.key || true - echo "validator: $VALIDATORADDR" - cat ~/.agoric/validator.key || true - echo "user1: $USER1ADDR" - cat ~/.agoric/user1.key || true - echo "user2: $USER2ADDR" - cat ~/.agoric/user2.key || true - echo "========== GOVERNANCE KEYS ==========" -} - -pushPrice () { - echo ACTIONS pushPrice $1 - newPrice="${1:-10.00}" - for oracleNum in {1..2}; do - if [[ ! -e "$HOME/.agoric/lastOracle" ]]; then - echo "$GOV1ADDR" > "$HOME/.agoric/lastOracle" - fi - - lastOracle=$(cat "$HOME/.agoric/lastOracle") - nextOracle="$GOV1ADDR" - if [[ "$lastOracle" == "$GOV1ADDR" ]]; then - nextOracle="$GOV2ADDR" - fi - echo "Pushing Price from oracle $nextOracle" - - oid="${nextOracle}_ORACLE" - offer=$(mktemp -t pushPrice.XXX) - agops oracle pushPriceRound --price "$newPrice" --oracleAdminAcceptOfferId "${!oid}" >|"$offer" - sleep 1 - timeout --preserve-status 15 yarn run --silent agops perf satisfaction --from $nextOracle --executeOffer "$offer" --keyring-backend test - if [ $? -ne 0 ]; then - echo "WARNING: pushPrice for $nextOracle failed!" - fi - echo "$nextOracle" > "$HOME/.agoric/lastOracle" - done -} - - -# variant of pushPrice() that figures out which oracle to send from -# WIP because it doesn't always work -pushPriceOnce () { - echo ACTIONS pushPrice $1 - newPrice="${1:-10.00}" - timeout 3 agoric follow -lF :published.priceFeed.ATOM-USD_price_feed.latestRound -ojson > "$HOME/.agoric/latestRound-ATOM.json" - - lastStartedBy=$(jq -r .startedBy "$HOME/.agoric/latestRound-ATOM.json" || echo null) - echo lastStartedBy $lastStartedBy - nextOracle="ERROR" - # cycle to next among oracles (first of the two governance accounts) - case $lastStartedBy in - "$GOV1ADDR") nextOracle=$GOV2ADDR;; - "$GOV2ADDR") nextOracle=$GOV1ADDR;; - *) - echo last price was pushed by a different account, using GOV1 - nextOracle=$GOV1ADDR - ;; - esac - echo nextOracle $nextOracle - - adminOfferId="${nextOracle}_ORACLE" - - echo "Pushing Price from oracle $nextOracle with offer $adminOfferId" - - offer=$(mktemp -t pushPrice.XXX) - agops oracle pushPriceRound --price "$newPrice" --oracleAdminAcceptOfferId "${adminOfferId}" >|"$offer" - cat "$offer" - sleep 1 - timeout --preserve-status 15 yarn run --silent agops perf satisfaction --from $nextOracle --executeOffer "$offer" --keyring-backend test - if [ $? -eq 0 ]; then - echo SUCCESS - else - echo "ERROR: pushPrice failed (using $nextOracle)" - fi -} - -# submit a DeliverInbound transaction -# -# see {agoric.swingset.MsgDeliverInbound} in swingset/msgs.proto -# https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/golang/cosmos/proto/agoric/swingset/msgs.proto#L23 -submitDeliverInbound() { - sender="${1:-user1}" - - # ag-solo is a client that sends DeliverInbound transactions using a golang client - # @see {connectToChain} in chain-cosmos-sdk.js - # runHelper - # https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/packages/solo/src/chain-cosmos-sdk.js - - # The payload is JSON.stringify([messages, highestAck]) - # https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/packages/solo/src/chain-cosmos-sdk.js#L625 - # for example, this json was captured from a running `agoric start local-solo` - json='[[[1,"1:0:deliver:ro+1:rp-44;#[\"getConfiguration\",[]]"]],0]' - - agd tx swingset deliver "${json}" \ - --chain-id="$CHAINID" -ojson --yes \ - --from="$sender" --keyring-backend=test -b block -} - -make_swing_store_snapshot() {( set -euo pipefail - EXPORT_DIR="$1" - shift - /usr/src/agoric-sdk/packages/cosmic-swingset/src/export-kernel-db.js --home "$HOME/.agoric" --export-dir "$EXPORT_DIR" --verbose --include-export-data "$@" - - EXPORT_MANIFEST_FILE="$EXPORT_DIR/export-manifest.json" - EXPORT_DATA_FILE="$EXPORT_DIR/$(cat "$EXPORT_MANIFEST_FILE" | jq -r .data)" - EXPORT_DATA_UNTRUSTED_FILE="${EXPORT_DATA_FILE%.*}-untrusted.jsonl" - EXPORT_HEIGHT=$(cat "$EXPORT_MANIFEST_FILE" | jq -r .blockHeight) - EXPORT_MANIFEST="$(cat $EXPORT_MANIFEST_FILE)" - - mv "$EXPORT_DATA_FILE" "$EXPORT_DATA_UNTRUSTED_FILE" - agd export --height $EXPORT_HEIGHT | jq -cr '.app_state.vstorage.data[] | if .path | startswith("swingStore.") then [.path[11:],.value] else empty end' > "$EXPORT_DATA_FILE" - - jq -n "$EXPORT_MANIFEST | .untrustedData=\"$(basename -- "$EXPORT_DATA_UNTRUSTED_FILE")\"" > "$EXPORT_MANIFEST_FILE" - - echo "Successful swing-store export for block $EXPORT_HEIGHT" -)} - -restore_swing_store_snapshot() {( set -euo pipefail - rm -f $HOME/.agoric/data/agoric/swingstore.sqlite - - /usr/src/agoric-sdk/packages/cosmic-swingset/src/import-kernel-db.js --home "$HOME/.agoric" --export-dir "$1" --verbose -)} - -compare_swing_store_export_data() { - EXPORT_DIR="$1" - EXPORT_MANIFEST_FILE="$EXPORT_DIR/export-manifest.json" - EXPORT_DATA_FILE="$(cat "$EXPORT_MANIFEST_FILE" | jq -r .data)" - EXPORT_DATA_UNTRUSTED_FILE="$(cat "$EXPORT_MANIFEST_FILE" | jq -r .untrustedData)" - - if [ -z "$EXPORT_DATA_FILE" ]; then - echo "missing-export-data" - return - fi - - if [ -z "$EXPORT_DATA_UNTRUSTED_FILE" ]; then - echo "missing-untrusted-export-data" - return - fi - - diff <(cat "$EXPORT_DIR/$EXPORT_DATA_FILE" | sort) <(cat "$EXPORT_DIR/$EXPORT_DATA_UNTRUSTED_FILE" | sort) >&2 && { - echo "match" - } || { - echo "mismatch" - } -} diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/legacy.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/legacy.sh new file mode 100755 index 000000000000..1fadfd4804f1 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/legacy.sh @@ -0,0 +1,85 @@ +#!/bin/bash +. /usr/src/agoric-sdk/upgrade-test-scripts/env_setup.sh + +make_swing_store_snapshot() {( set -euo pipefail + EXPORT_DIR="$1" + shift + /usr/src/agoric-sdk/packages/cosmic-swingset/src/export-kernel-db.js --home "$HOME/.agoric" --export-dir "$EXPORT_DIR" --verbose --include-export-data "$@" + + EXPORT_MANIFEST_FILE="$EXPORT_DIR/export-manifest.json" + EXPORT_DATA_FILE="$EXPORT_DIR/$(cat "$EXPORT_MANIFEST_FILE" | jq -r .data)" + EXPORT_DATA_UNTRUSTED_FILE="${EXPORT_DATA_FILE%.*}-untrusted.jsonl" + EXPORT_HEIGHT=$(cat "$EXPORT_MANIFEST_FILE" | jq -r .blockHeight) + EXPORT_MANIFEST="$(cat $EXPORT_MANIFEST_FILE)" + + mv "$EXPORT_DATA_FILE" "$EXPORT_DATA_UNTRUSTED_FILE" + agd export --height $EXPORT_HEIGHT | jq -cr '.app_state.vstorage.data[] | if .path | startswith("swingStore.") then [.path[11:],.value] else empty end' > "$EXPORT_DATA_FILE" + + jq -n "$EXPORT_MANIFEST | .untrustedData=\"$(basename -- "$EXPORT_DATA_UNTRUSTED_FILE")\"" > "$EXPORT_MANIFEST_FILE" + + echo "Successful swing-store export for block $EXPORT_HEIGHT" +)} + +restore_swing_store_snapshot() {( set -euo pipefail + rm -f $HOME/.agoric/data/agoric/swingstore.sqlite + + /usr/src/agoric-sdk/packages/cosmic-swingset/src/import-kernel-db.js --home "$HOME/.agoric" --export-dir "$1" --verbose +)} + +compare_swing_store_export_data() { + EXPORT_DIR="$1" + EXPORT_MANIFEST_FILE="$EXPORT_DIR/export-manifest.json" + EXPORT_DATA_FILE="$(cat "$EXPORT_MANIFEST_FILE" | jq -r .data)" + EXPORT_DATA_UNTRUSTED_FILE="$(cat "$EXPORT_MANIFEST_FILE" | jq -r .untrustedData)" + + if [ -z "$EXPORT_DATA_FILE" ]; then + echo "missing-export-data" + return + fi + + if [ -z "$EXPORT_DATA_UNTRUSTED_FILE" ]; then + echo "missing-untrusted-export-data" + return + fi + + diff <(cat "$EXPORT_DIR/$EXPORT_DATA_FILE" | sort) <(cat "$EXPORT_DIR/$EXPORT_DATA_UNTRUSTED_FILE" | sort) >&2 && { + echo "match" + } || { + echo "mismatch" + } +} + +# replicate state-sync of node +# this will cause the swing-store to prune some data +# we will save the pruned artifact for later +killAgd +EXPORT_DIR=$(mktemp -t -d swing-store-export-upgrade-10-XXX) +make_swing_store_snapshot $EXPORT_DIR || fail "Couldn't make swing-store snapshot" +# test_val "$(compare_swing_store_export_data $EXPORT_DIR)" "match" "swing-store export data" +EXPORT_DIR_ALL_ARTIFACTS=$(mktemp -t -d swing-store-export-upgrade-10-all-artifacts-XXX) +make_swing_store_snapshot $EXPORT_DIR_ALL_ARTIFACTS --export-mode archival || fail "Couldn't make swing-store snapshot for historical artifacts" +restore_swing_store_snapshot $EXPORT_DIR || fail "Couldn't restore swing-store snapshot" +( + cd $EXPORT_DIR_ALL_ARTIFACTS + mkdir $HOME/.agoric/data/agoric/swing-store-historical-artifacts + for i in *; do + [ -f $EXPORT_DIR/$i ] && continue + mv $i $HOME/.agoric/data/agoric/swing-store-historical-artifacts/ + done +) +rm -rf $EXPORT_DIR +rm -rf $EXPORT_DIR_ALL_ARTIFACTS + +startAgd +sleep 5 +killAgd + +EXPORT_DIR=$(mktemp -t -d swing-store-export-upgrade-10-XXX) +make_swing_store_snapshot $EXPORT_DIR || fail "Couldn't make swing-store snapshot" +test_val "$(compare_swing_store_export_data $EXPORT_DIR)" "mismatch" "swing-store broken state-sync" +rm -rf $EXPORT_DIR +startAgd + +# # TODO fully test bidding +# # TODO test liquidations +agops inter bid by-price --price 1 --give 1.0IST --from $GOV1ADDR --keyring-backend test \ No newline at end of file diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/param-change-offer-gen.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/param-change-offer-gen.mjs deleted file mode 100644 index a9e17895b6b7..000000000000 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/param-change-offer-gen.mjs +++ /dev/null @@ -1,104 +0,0 @@ -/* global process */ -import assert from 'assert'; -import { execFile } from 'child_process'; - -const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 } - -const [_node, _script, previousOffer, voteDur, debtLimit] = process.argv; -assert(previousOffer, 'previousOffer is required'); -assert(voteDur, 'voteDur is required'); -assert(debtLimit, 'debtLimit is required'); -const voteDurSec = BigInt(voteDur); -const debtLimitValue = BigInt(debtLimit) * ISTunit; - -const toSec = ms => BigInt(Math.round(ms / 1000)); - -const id = `propose-${Date.now()}`; -const deadline = toSec(Date.now()) + voteDurSec; - -// look up boardIDs for brands, instances in agoricNames - -// poor-man's zx -const $ = cmd => { - console.error(cmd); - const [file, ...args] = cmd.split(' '); - - return new Promise((resolve, reject) => { - execFile(file, args, { encoding: 'utf8' }, (err, out) => { - if (err) return reject(err); - resolve(out); - }); - }); -}; - -const zip = (xs, ys) => xs.map((x, i) => [x, ys[i]]); -const fromSmallCapsEntries = txt => { - const { body, slots } = JSON.parse(txt); - const theEntries = zip(JSON.parse(body.slice(1)), slots).map( - ([[name, ref], boardID]) => { - const iface = ref.replace(/^\$\d+\./, ''); - return [name, { iface, boardID }]; - }, - ); - return Object.fromEntries(theEntries); -}; - -const instance = fromSmallCapsEntries( - await $('agoric follow -lF :published.agoricNames.instance -o text'), -); -assert(instance.VaultFactory); - -const brand = fromSmallCapsEntries( - await $('agoric follow -lF :published.agoricNames.brand -o text'), -); -assert(brand.IST); -assert(brand.ATOM); - -const slots = []; // XXX global mutable state - -const smallCaps = { - Nat: n => `+${n}`, - // XXX mutates obj - ref: obj => { - if (obj.ix) return obj.ix; - const ix = slots.length; - slots.push(obj.boardID); - obj.ix = `$${ix}.Alleged: ${obj.iface}`; - return obj.ix; - }, -}; - -const body = { - method: 'executeOffer', - offer: { - id, - invitationSpec: { - invitationMakerName: 'VoteOnParamChange', - previousOffer, - source: 'continuing', - }, - offerArgs: { - deadline: smallCaps.Nat(deadline), - instance: smallCaps.ref(instance.VaultFactory), - params: { - DebtLimit: { - brand: smallCaps.ref(brand.IST), - value: smallCaps.Nat(debtLimitValue), - }, - }, - path: { - paramPath: { - key: { - collateralBrand: smallCaps.ref(brand.ATOM), - }, - }, - }, - }, - proposal: {}, - }, -}; - -const capData = { body: `#${JSON.stringify(body)}`, slots }; -const action = JSON.stringify(capData); - -console.log(action); diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/post.test.js b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/post.test.js new file mode 100644 index 000000000000..30ac69ca947e --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/post.test.js @@ -0,0 +1,70 @@ +import test from 'ava'; + +import { agd, agoric } from '../cliHelper.mjs'; +import { GOV1ADDR, GOV2ADDR, GOV3ADDR, USER1ADDR } from '../constants.mjs'; +import { calculateWalletState } from './upgradeHelpers.mjs'; + +test('DeliverInbound from un-provisioned account is discarded', async t => { + const result = await agd.query('swingset', 'mailbox', USER1ADDR); + const value = JSON.parse(result.value); + t.is(value.outbox.length, 0); +}); + +test('provision pool has right balance', async t => { + const result = await agd.query( + 'bank', + 'balances', + 'agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346', + ); + t.is(result.balances[0].amount, '18750000'); +}); + +test('Validate wallet state', async t => { + t.is(await calculateWalletState(USER1ADDR), 'upgraded'); + t.is(await calculateWalletState(GOV1ADDR), 'revived'); + t.is(await calculateWalletState(GOV2ADDR), 'revived'); + t.is(await calculateWalletState(GOV3ADDR), 'revived'); +}); + +test('Validate vaults', async t => { + const vaults = await agd.query( + 'vstorage', + 'children', + 'published.vaultFactory.managers.manager0.vaults', + ); + + t.is(vaults.children.length, 3); + + const metrics = await agoric.follow( + '-lF', + ':published.vaultFactory.managers.manager0.metrics', + ); + + t.is(metrics.numActiveVaults, 1); + t.is(metrics.totalDebt.value, '6030000'); + t.is(metrics.totalCollateral.value, '8000000'); + + const vault0 = await agoric.follow( + '-lF', + ':published.vaultFactory.managers.manager0.vaults.vault0', + ); + t.is(vault0.vaultState, 'active'); + t.is(vault0.locked.value, '8000000'); + t.is(vault0.debtSnapshot.debt.value, '6030000'); + + const vault1 = await agoric.follow( + '-lF', + ':published.vaultFactory.managers.manager0.vaults.vault1', + ); + t.is(vault1.vaultState, 'closed'); + t.is(vault1.locked.value, '0'); + t.is(vault1.debtSnapshot.debt.value, '0'); + + const vault2 = await agoric.follow( + '-lF', + ':published.vaultFactory.managers.manager0.vaults.vault2', + ); + t.is(vault2.vaultState, 'closed'); + t.is(vault2.locked.value, '0'); + t.is(vault2.debtSnapshot.debt.value, '0'); +}); diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre.test.js b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre.test.js new file mode 100644 index 000000000000..9ce5aed434fb --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre.test.js @@ -0,0 +1,216 @@ +import test from 'ava'; + +import { promises as fs } from 'fs'; + +import { waitForBlock, getUser } from './upgradeHelpers.mjs'; +import { agd, agoric, agops } from '../cliHelper.mjs'; + +import { + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, + BOOTSTRAP_MODE, + PSM_PAIR, +} from '../constants.mjs'; + +import { openVault } from './actions.mjs'; + +test.before(async () => { + console.log('Wait for upgrade to settle'); + + await waitForBlock(20); +}); + +test(`Ensure there's only uist`, async t => { + const result = await agd.query( + 'bank', + 'balances', + 'agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346', + ); + + t.is(result.balances.length, 1); + t.is(result.balances[0].denom, 'uist'); +}); + +test('Ensure gov1 provisioned', async t => { + const result = await agd.query( + 'vstorage', + 'data', + `published.wallet.${GOV1ADDR}`, + ); + + t.not(result.value.length, 0); +}); + +test('Ensure gov2 provisioned', async t => { + const result = await agd.query( + 'vstorage', + 'data', + `published.wallet.${GOV2ADDR}`, + ); + + t.not(result.value.length, 0); +}); + +test('Ensure gov3 provisioned', async t => { + const result = await agd.query( + 'vstorage', + 'data', + `published.wallet.${GOV3ADDR}`, + ); + + t.not(result.value.length, 0); +}); + +test('Ensure user2 not provisioned', async t => { + try { + await getUser('user2'); + t.fail(); + } catch (error) { + t.pass(); + } +}); + +test('Ensure no vaults exist', async t => { + const result = await agd.query( + 'vstorage', + 'data', + `published.vaultFactory.manager0.vaults.vault0`, + ); + + t.is(result.value, ''); +}); + +test(`Provision pool has right balance`, async t => { + const result = await agd.query( + 'bank', + 'balances', + 'agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346', + ); + + t.is(result.balances[0].amount, '19000000'); +}); + +test('Validate PSM denoms', async t => { + const psmISTChildren = await agd.query( + 'vstorage', + 'children', + 'published.psm.IST', + ); + + t.not(psmISTChildren.children.legnth, 0); + + let denoms = ['USDC_axl', 'DAI_axl', 'DAI_grv']; + if (BOOTSTRAP_MODE === 'main') { + denoms = [...denoms, 'USDC_grv', 'USDT_axl', 'USDT_grv']; + } else { + denoms = [...denoms, 'ToyUSD']; + } + + for (const denom of denoms) { + t.truthy(psmISTChildren.children.includes(denom)); + } +}); + +test('PSM gov params were preserved', async t => { + const toyUSDGovernance = await agoric.follow( + '-lF', + `:published.psm.${PSM_PAIR}.governance`, + ); + + const psmGovernanceData = await fs.readFile( + '/root/.agoric/psm_governance.json', + 'binary', + ); + + const psmGovernance = JSON.parse(psmGovernanceData); + + t.not(toyUSDGovernance.current.MintLimit.value.value, '0'); + t.is( + toyUSDGovernance.current.MintLimit.value.value, + psmGovernance.current.MintLimit.value.value, + ); + t.is(toyUSDGovernance.current.GiveMintedFee.value.numerator.value, '0'); + t.is( + toyUSDGovernance.current.GiveMintedFee.value.denominator.value, + psmGovernance.current.GiveMintedFee.value.denominator.value, + ); + t.is(toyUSDGovernance.current.WantMintedFee.value.numerator.value, '0'); + t.is( + toyUSDGovernance.current.WantMintedFee.value.denominator.value, + psmGovernance.current.WantMintedFee.value.denominator.value, + ); +}); + +test('PSM metric params were preserved', async t => { + const toyUSDMetrics = await agoric.follow( + '-lF', + `:published.psm.${PSM_PAIR}.metrics`, + ); + + const psmMetricsData = await fs.readFile( + '/root/.agoric/psm_metrics.json', + 'binary', + ); + + const psmMetrics = JSON.parse(psmMetricsData); + + t.is( + toyUSDMetrics.anchorPoolBalance.value, + psmMetrics.anchorPoolBalance.value, + ); + t.is(toyUSDMetrics.feePoolBalance.value, psmMetrics.feePoolBalance.value); + t.is( + toyUSDMetrics.mintedPoolBalance.value, + psmMetrics.mintedPoolBalance.value, + ); + t.is( + toyUSDMetrics.totalMintedProvided.value, + psmMetrics.totalMintedProvided.value, + ); +}); + +test('Provision pool metrics are retained across vaults upgrade', async t => { + const provisionPoolMetrics = await agoric.follow( + '-lF', + ':published.provisionPool.metrics', + ); + + const provisionPoolMetricsData = await fs.readFile( + '/root/.agoric/provision_pool_metrics.json', + 'binary', + ); + + const testProvisionPoolMetrics = JSON.parse(provisionPoolMetricsData); + + t.is( + provisionPoolMetrics.totalMintedConverted.value, + testProvisionPoolMetrics.totalMintedConverted.value, + ); + t.is( + provisionPoolMetrics.totalMintedProvided.value, + testProvisionPoolMetrics.totalMintedProvided.value, + ); + t.is( + provisionPoolMetrics.walletsProvisioned, + testProvisionPoolMetrics.walletsProvisioned, + ); +}); + +test('Pre Vault tests', async t => { + try { + await openVault(GOV1ADDR, 5, 9); + t.fail(); + } catch (error) { + t.truthy( + error.message.includes( + "'Error: maxDebtFor called before a collateral quote was available'", + ), + ); + } +}); + +test('Gov1 has no vaults', async t => { + const vaults = await agops.vaults('list', '--from', GOV1ADDR); + t.is(vaults.length, 0); +}); diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre_test.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre_test.sh deleted file mode 100644 index 7730fe7af67c..000000000000 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/pre_test.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -. ./upgrade-test-scripts/env_setup.sh - -echo Wait for upgrade to settle -waitForBlock 20 - -# ensure there's only uist -test_val "$(agd q bank balances agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 -o json | jq -r '.balances | length')" "1" -test_val "$(agd q bank balances agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 -o json | jq -r '.balances[0].denom')" "uist" - -# test wallets are provisioned -test_not_val "$(agd q vstorage data published.wallet.$GOV1ADDR -o json | jq -r .value)" "" "ensure gov1 provisioned" -test_not_val "$(agd q vstorage data published.wallet.$GOV2ADDR -o json | jq -r .value)" "" "ensure gov2 provisioned" -test_not_val "$(agd q vstorage data published.wallet.$GOV3ADDR -o json | jq -r .value)" "" "ensure gov3 provisioned" - -# test user2 not provisioned -test_val "$(agd q vstorage data published.wallet.$USER2ADDR -o json | jq -r .value)" "" "ensure user2 not provisioned" - -# test that we have no vaults -test_val "$(agd q vstorage data published.vaultFactory.manager0.vaults.vault0 -o json | jq -r .value)" "" "ensure no vaults exist" - -# provision pool has right balance -test_val "$(agd query bank balances agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 -o json | jq -r '.balances | first | .amount ')" "19000000" - -# we should have more denoms in governance -psmISTChildren="$(agd q vstorage children published.psm.IST -o jsonlines)" -test_not_val "$(echo "$psmISTChildren" | jq -r '.children | length')" "1" "more than one PSM denoms" - -# emerynet started with ToyUSD; gov proposals added USDC_axl, DAI_axl, DAI_grv -# main started with USDC, USDT x axl, grv and a gov proposal added DAI x axl, grv -if [[ "$BOOTSTRAP_MODE" == "test" ]]; then - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "ToyUSD")')" "" "ToyUSD in IST" -else - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "USDC_grv")')" "" "USDC_grv in IST" - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "USDT_axl")')" "" "USDT_axl in IST" - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "USDT_grv")')" "" "USDT_grv in IST" -fi - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "USDC_axl")')" "" "USDC_axl in IST" - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "DAI_axl")')" "" "DAI_axl in IST" - test_not_val "$(echo "$psmISTChildren" | jq -r '.children[] | select (. == "DAI_grv")')" "" "DAI_grv in IST" - -## testing state from pismoC was preserved post bulldozer upgrade - -# test that the PSM gov params were preserved -toyUSDGovernance="$(agoric follow -lF :published.psm.${PSM_PAIR}.governance -o jsonlines)" -test_not_val "$(echo "$toyUSDGovernance" | jq -r '.current.MintLimit.value.value')" "0" "PSM MintLimit non-zero" -test_val "$(echo "$toyUSDGovernance" | jq -r '.current.MintLimit.value.value')" "$(cat /root/.agoric/psm_governance.json | jq -r '.current.MintLimit.value.value')" "PSM MintLimit preserved" -test_val "$(echo "$toyUSDGovernance" | jq -r '.current.GiveMintedFee.value.numerator.value')" "0" "GiveMintedFee numerator == 0" -test_val "$(echo "$toyUSDGovernance" | jq -r '.current.GiveMintedFee.value.denominator.value')" "$(cat /root/.agoric/psm_governance.json | jq -r '.current.GiveMintedFee.value.denominator.value')" "GiveMintedFee denominator == 10000" -test_val "$(echo "$toyUSDGovernance" | jq -r '.current.WantMintedFee.value.numerator.value')" "0" "WantMintedFee numerator == 0" -test_val "$(echo "$toyUSDGovernance" | jq -r '.current.WantMintedFee.value.denominator.value')" "$(cat /root/.agoric/psm_governance.json | jq -r '.current.WantMintedFee.value.denominator.value')" "WantMintedFee denominator == 10000" - -toyUSDMetrics="$(agoric follow -lF :published.psm.${PSM_PAIR}.metrics -o jsonlines)" -test_val "$(echo "$toyUSDMetrics" | jq -r '.anchorPoolBalance.value')" "$(cat /root/.agoric/psm_metrics.json | jq -r '.anchorPoolBalance.value')" "anchorPoolBalance preserved" -test_val "$(echo "$toyUSDMetrics" | jq -r '.feePoolBalance.value')" "$(cat /root/.agoric/psm_metrics.json | jq -r '.feePoolBalance.value')" "feePoolBalance preserved" -test_val "$(echo "$toyUSDMetrics" | jq -r '.mintedPoolBalance.value')" "$(cat /root/.agoric/psm_metrics.json | jq -r '.mintedPoolBalance.value')" "mintedPoolBalance preserved" -test_val "$(echo "$toyUSDMetrics" | jq -r '.totalAnchorProvided.value')" "$(cat /root/.agoric/psm_metrics.json | jq -r '.totalAnchorProvided.value')" "totalAnchorProvided preserved" -test_val "$(echo "$toyUSDMetrics" | jq -r '.totalMintedProvided.value')" "$(cat /root/.agoric/psm_metrics.json | jq -r '.totalMintedProvided.value')" "totalMintedProvided preserved" - -# test that provision pool metrics are retained across vaults upgrade -provisionPoolMetrics="$(agoric follow -lF :published.provisionPool.metrics -o jsonlines)" -test_val "$(echo "$provisionPoolMetrics" | jq -r '.totalMintedConverted.value')" "$(cat /root/.agoric/provision_pool_metrics.json | jq -r '.totalMintedConverted.value')" "totalMintedConverted preserved" -test_val "$(echo "$provisionPoolMetrics" | jq -r '.totalMintedProvided.value')" "$(cat /root/.agoric/provision_pool_metrics.json | jq -r '.totalMintedProvided.value')" "totalMintedProvided preserved" -test_val "$(echo "$provisionPoolMetrics" | jq -r '.walletsProvisioned')" "$(cat /root/.agoric/provision_pool_metrics.json | jq -r '.walletsProvisioned')" "walletsProvisioned preserved" - -# vaults pre-tests - -# attempt to open a vault on main -# these should fail due to debt limit starting at 0 -if [[ "$BOOTSTRAP_MODE" == "main" ]]; then - test_val "$(agoric follow -lF :published.vaultFactory.managers.manager0.governance -o jsonlines | jq -r '.current.DebtLimit.value.value')" "0" "boostrap(main) DebtLimit starts at 0" - - OFFER=$(mktemp -t agops.XXX) - agops vaults open --wantMinted 5.00 --giveCollateral 9 >|"$OFFER" - agoric wallet print --file "$OFFER" - agops perf satisfaction --from "$GOV1ADDR" --executeOffer "$OFFER" --keyring-backend=test || true -fi - -test_val "$(agops vaults list --from $GOV1ADDR)" "" "gov1 has no vaults" diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/test.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/test.sh deleted file mode 100644 index 633716f5b4a1..000000000000 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/test.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -. ./upgrade-test-scripts/env_setup.sh - -# DeliverInbound from un-provisioned account is discarded -# Note: sending to a provisioned account resulted in an .outbox of -# [[1,"1:1:resolve:fulfill:rp+44:ro-20;#\"$0.Alleged: notifier\""]] -test_val $(agd query swingset mailbox $USER1ADDR -o json | jq '.value |fromjson |.outbox') '[]' "DeliverInbound (getConfiguration) is discarded" - -# provision pool has right balance -test_val $(agd query bank balances agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 -o json | jq -r '.balances | first | .amount ') "18750000" - -test_wallet_state "$USER1ADDR" upgraded "user1 wallet is upgraded" -test_wallet_state "$GOV1ADDR" revived "gov1 wallet is revived" -test_wallet_state "$GOV2ADDR" revived "gov2 wallet is revived" -test_wallet_state "$GOV3ADDR" revived "gov3 wallet is revived" - -test_val $(agd q vstorage children published.vaultFactory.managers.manager0.vaults -o json | jq -r '.children | length') 3 "we have three vaults" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.metrics -o jsonlines | jq -r '.numActiveVaults') 1 "only one vault is active" - -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.metrics -o jsonlines | jq -r '.totalDebt.value') "6030000" "totalDebt is correct" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.metrics -o jsonlines | jq -r '.totalCollateral.value') "8000000" "totalCollateral is correct" - -# gov1 vault0 -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault0 -o jsonlines | jq -r '.vaultState') "active" "vault0 is open" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault0 -o jsonlines | jq -r '.locked.value') "8000000" "vault0 contains 8 ATOM collateral" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault0 -o jsonlines | jq -r '.debtSnapshot.debt.value') "6030000" "vault0 debt is 6.03 IST" - -# gov1 vault1 -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault1 -o jsonlines | jq -r '.vaultState') "closed" "vault1 is closed" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault1 -o jsonlines | jq -r '.locked.value') "0" "vault1 contains no collateral" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault1 -o jsonlines | jq -r '.debtSnapshot.debt.value') "0" "vault1 has no debt" - -# user2 vault2 -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.vaultState') "closed" "vault2 is closed" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.locked.value') "0" "vault2 contains no collateral" -test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.debtSnapshot.debt.value') "0" "vault2 has no debt" - -# verify state-sync would be broken -killAgd -EXPORT_DIR=$(mktemp -t -d swing-store-export-upgrade-10-XXX) -make_swing_store_snapshot $EXPORT_DIR || fail "Couldn't make swing-store snapshot" -test_val "$(compare_swing_store_export_data $EXPORT_DIR)" "mismatch" "swing-store broken state-sync" -rm -rf $EXPORT_DIR -startAgd \ No newline at end of file diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/upgradeHelpers.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/upgradeHelpers.mjs new file mode 100644 index 000000000000..3768d5603ee8 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-10/upgradeHelpers.mjs @@ -0,0 +1,76 @@ +/* eslint-disable @jessie.js/safe-await-separator */ +import { $ } from 'execa'; + +import { + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, + VALIDATORADDR, + USER1ADDR, + CHAINID, + HOME, +} from '../constants.mjs'; + +import { agd, agops } from '../cliHelper.mjs'; + +export * from '../coreUpgradeHelpers.mjs'; + +export const getUser = async user => { + return agd.keys('show', user, '-a', '--keyring-backend=test'); +}; + +export const printKeys = async () => { + console.log('========== GOVERNANCE KEYS =========='); + + console.log(`gov1: ${GOV1ADDR}`); + const gov1Key = await $`cat /root/.agoric/gov1.key`; + console.log(gov1Key.stdout); + + console.log(`gov2: ${GOV2ADDR}`); + const gov2Key = await $`cat /root/.agoric/gov2.key`; + console.log(gov2Key.stdout); + + console.log(`gov3: ${GOV3ADDR}`); + const gov3Key = await $`cat /root/.agoric/gov3.key`; + console.log(gov3Key.stdout); + + console.log(`validator: ${VALIDATORADDR}`); + const validatorKey = await $`cat /root/.agoric/validator.key`; + console.log(validatorKey.stdout); + + console.log(`user1: ${USER1ADDR}`); + const user1Key = await $`cat /root/.agoric/user1.key`; + console.log(user1Key.stdout); + + const user2Address = await getUser('user2'); + + console.log(`user2: ${user2Address}`); + const user2Key = await $`cat /root/.agoric/user1.key`; + console.log(user2Key.stdout); +}; + +// submit a DeliverInbound transaction +// +// see {agoric.swingset.MsgDeliverInbound} in swingset/msgs.proto +// https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/golang/cosmos/proto/agoric/swingset/msgs.proto#L23 +export const submitDeliverInbound = async sender => { + // ag-solo is a client that sends DeliverInbound transactions using a golang client + // @see {connectToChain} in chain-cosmos-sdk.js + // runHelper + // https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/packages/solo/src/chain-cosmos-sdk.js + + // The payload is JSON.stringify([messages, highestAck]) + // https://github.com/Agoric/agoric-sdk/blob/5cc5ec8836dcd0c6e11b10799966b6e74601295d/packages/solo/src/chain-cosmos-sdk.js#L625 + // for example, this json was captured from a running `agoric start local-solo` + const json = `[[[1,"1:0:deliver:ro+1:rp-44;#[\\"getConfiguration\\",[]]"]],0]`; + await agd.tx( + 'swingset', + 'deliver', + `'${json}'`, + `--chain-id="${CHAINID}"`, + '--yes', + `--from="${sender}"`, + '--keyring-backend=test', + '-b block', + ); +}; diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/cliHelper.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/cliHelper.mjs new file mode 100644 index 000000000000..29d08401e01d --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/cliHelper.mjs @@ -0,0 +1,110 @@ +/* eslint-disable @jessie.js/safe-await-separator */ +import { $, execaCommand } from 'execa'; +import { BINARY } from './constants.mjs'; + +export const executeCommand = async (command, params, options = {}) => { + const { stdout } = await execaCommand( + `${command} ${params.join(' ')}`, + options, + ); + return stdout; +}; + +export const agd = { + query: async (...params) => { + const newParams = ['query', ...params, '-o json']; + const data = await executeCommand(BINARY, newParams); + return JSON.parse(data); + }, + tx: async (...params) => { + const newParams = ['tx', ...params, '-o json']; + const data = await executeCommand(BINARY, newParams, { shell: true }); + return JSON.parse(data); + }, + keys: async (...params) => { + let newParams = ['keys', ...params]; + let shouldParse = true; + + if (params.includes('show')) { + if (params.includes('-a') || params.includes('-address')) { + shouldParse = false; + } + } + + if (shouldParse) { + newParams = [...newParams, '--output json']; + } + + const data = await executeCommand(BINARY, newParams, { input: 'Y' }); + if (!shouldParse) { + return data; + } + + return JSON.parse(data); + }, + export: async (...params) => { + const newParams = ['export', ...params]; + const data = await executeCommand(BINARY, newParams); + return JSON.parse(data); + }, +}; + +export const agoric = { + follow: async (...params) => { + let newParams = ['follow', ...params]; + let parseJson = false; + + if (!params.includes('-o')) { + newParams = [...newParams, '-o json']; + parseJson = true; + } + const data = await executeCommand('agoric', newParams); + + if (parseJson) { + return JSON.parse(data); + } + + return data; + }, + wallet: async (...params) => { + const newParams = ['wallet', ...params]; + return executeCommand('agoric', newParams); + }, +}; + +export const { stdout: agopsLocation } = await $({ + shell: true, + cwd: '/usr/src/agoric-sdk', +})`yarn bin agops`; + +export const agops = { + vaults: async (...params) => { + const newParams = ['vaults', ...params]; + + const result = await executeCommand(agopsLocation, newParams); + + if (params[0] === 'list') { + if (result === '') return []; + + return result.split('\n'); + } + + return result; + }, + ec: async (...params) => { + const newParams = ['ec', ...params]; + return executeCommand(agopsLocation, newParams); + }, + oracle: async (...params) => { + const newParams = ['oracle', ...params]; + return executeCommand(agopsLocation, newParams); + }, + perf: async (...params) => { + const newParams = ['perf', ...params]; + return executeCommand(agopsLocation, newParams); + }, + auctioneer: async (...params) => { + const newParams = ['auctioneer', ...params]; + return executeCommand(agopsLocation, newParams); + }, +}; diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/constants.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/constants.mjs new file mode 100644 index 000000000000..1dc1d7cea272 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/constants.mjs @@ -0,0 +1,14 @@ +export const BINARY = process.env.binary; + +export const GOV1ADDR = process.env.GOV1ADDR; +export const GOV2ADDR = process.env.GOV2ADDR; +export const GOV3ADDR = process.env.GOV3ADDR; +export const USER1ADDR = process.env.USER1ADDR; +export const VALIDATORADDR = process.env.VALIDATORADDR; + +export const BOOTSTRAP_MODE = process.env.BOOTSTRAP_MODE; +export const PSM_PAIR = process.env.PSM_PAIR; +export const ATOM_DENOM = process.env.ATOM_DENOM; + +export const CHAINID = process.env.CHAINID; +export const HOME = process.env.HOME; diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/coreUpgradeHelpers.mjs b/packages/deployment/upgrade-test/upgrade-test-scripts/coreUpgradeHelpers.mjs new file mode 100644 index 000000000000..f85ebfdce34c --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/coreUpgradeHelpers.mjs @@ -0,0 +1,133 @@ +/* eslint-disable @jessie.js/safe-await-separator */ +import { $ } from 'execa'; +import { promises as fs } from 'fs'; +import { agd, agoric, agops } from './cliHelper.mjs'; +import { CHAINID } from './constants.mjs'; + +const waitForBootstrap = async () => { + const endpoint = 'localhost'; + while (true) { + const { stdout: json } = await $({ + reject: false, + })`curl -s --fail -m 15 ${`${endpoint}:26657/status`}`; + + if (json.length === 0) { + continue; + } + + const data = JSON.parse(json); + + if (data.jsonrpc !== '2.0') { + continue; + } + + const lastHeight = data.result.sync_info.latest_block_height; + + if (lastHeight !== '1') { + return lastHeight; + } + + await new Promise(r => setTimeout(r, 2000)); + } +}; + +export const waitForBlock = async (times = 1) => { + console.log(times); + let time = 0; + while (time < times) { + const block1 = await waitForBootstrap(); + while (true) { + const block2 = await waitForBootstrap(); + + if (block1 !== block2) { + console.log('block produced'); + break; + } + + await new Promise(r => setTimeout(r, 1000)); + } + time += 1; + } +}; + +export const provisionSmartWallet = async (address, amount) => { + console.log(`funding ${address}`); + await agd.tx( + 'bank', + 'send', + 'validator', + address, + amount, + '-y', + '--keyring-backend=test', + `--chain-id="${CHAINID}"`, + ); + await waitForBlock(); + + console.log(`provisioning ${address}`); + await agd.tx( + 'swingset', + 'provision-one', + 'my-wallet', + address, + 'SMART_WALLET', + '--keyring-backend=test', + '-y', + `--chain-id="${CHAINID}"`, + `--from="${address}"`, + ); + + await waitForBlock(2); + console.log(await agoric.wallet('show', `--from ${address}`)); +}; + +export const newOfferId = async () => { + const { stdout: date } = await $`date +${'%s%3M'}`; + await new Promise(r => setTimeout(r, 1000)); + + return date; +}; + +export const mkTemp = async (template, asDirectory = false) => { + const { stdout: data } = await $({ + shell: true, + })`mktemp -t ${template}`; + return data; +}; + +export const calculateWalletState = async addr => { + const result = await agoric.follow( + '-lF', + `:published.wallet.${addr}`, + '-o', + 'text', + ); + + const body = JSON.parse(result).body; + let state = body; + + if (body.includes('@qclass')) { + state = 'old'; + } else if (body.includes('#{}')) { + state = 'upgraded'; + } else if (body.includes('#')) { + state = 'revived'; + } + + return state; +}; + +export const executeOffer = async (address, offerPromise) => { + const offerPath = await mkTemp('agops.XXX'); + const offer = await offerPromise; + await fs.writeFile(offerPath, offer); + + await agops.perf( + 'satisfaction', + '--from', + address, + '--executeOffer', + offerPath, + '--keyring-backend=test', + ); +}; diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/env_setup.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/env_setup.sh old mode 100644 new mode 100755 diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/package.json b/packages/deployment/upgrade-test/upgrade-test-scripts/package.json new file mode 100644 index 000000000000..acfa7c6f8ad0 --- /dev/null +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/package.json @@ -0,0 +1,20 @@ +{ + "type": "module", + "devDependencies": { + "ava": "^5.3.1" + }, + "dependencies": { + "execa": "^7.2.0" + }, + "scripts": { + "upgrade-tests": "ava --serial agoric-upgrade*/**/pre.test.js agoric-upgrade*/**/actions.test.js agoric-upgrade*/**/post.test.js" + }, + "ava": { + "files": [ + "*/**/pre.test.js", + "*/**/actions.test.js", + "*/**/post.test.js" + ], + "timeout": "30m" + } +} diff --git a/packages/deployment/upgrade-test/upgrade-test-scripts/start_to_to.sh b/packages/deployment/upgrade-test/upgrade-test-scripts/start_to_to.sh index 2ba2d2a8e138..72ad19d0539b 100644 --- a/packages/deployment/upgrade-test/upgrade-test-scripts/start_to_to.sh +++ b/packages/deployment/upgrade-test/upgrade-test-scripts/start_to_to.sh @@ -17,9 +17,18 @@ fi startAgd if ! test -f "$HOME/.agoric/runActions-${THIS_NAME}"; then - runActions "pre_test" - runActions "actions" - runActions "test" + if [[ "${USE_JS}" == "1" ]]; then + pushd upgrade-test-scripts + yarn + yarn upgrade-tests || exit 1 + popd + runActions "legacy" + else + runActions "pre_test" + runActions "actions" + runActions "test" + fi + touch "$HOME/.agoric/runActions-${THIS_NAME}" fi