-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(vat-upgrade): upgrade agoricNames, test old values are preserved (
#10616) closes: #10408 ## Description As stated in #8158, we need to be able to upgrade any vat we want and make sure the system keeps working. This PR focuses on upgrading `vat-agoricNames`. ### Security Considerations I consider `vat-agoricNames` as a critical vat as it's the source trust for object identities. So it's crucial it keeps working after the upgrade. It's important to point out that if there were any keywords reserved before the upgrade, they will be lost after the upgrade as the reservations stored in ephemera. If this is important, we might consider re-reserving in the core eval. ### Scaling Considerations None. ### Documentation Considerations Don't think it's necessary as the functionality of `nameHub` is left untouched. ### Testing Considerations If we decide to re-reserve some keywords, we will need to add a test that verifies the core eval has indeed reserved those keywords. Please see below for the test plan I followed: https://github.com/Agoric/agoric-sdk/blob/1e4bebac1e3ee6df48dbe58e3e5bdf0e9e37cca2/a3p-integration/proposals/p%3Aupgrade-19/agoricNames.test.js#L3-L46 #### EDIT 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. ### Upgrade Considerations This PR itself upgrade `vat-agoricNames` and comes with a3p tests to verify the upgrade goes through and `agoricNames` keep working.
- Loading branch information
Showing
19 changed files
with
2,212 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
replaceFeeDistributor/ | ||
testUpgradedBoard/ | ||
addUsdLemons/ | ||
addUsdOlives/ | ||
upgradeProvisionPool/ | ||
upgradeAgoricNames/ | ||
publishTestInfo/ |
236 changes: 236 additions & 0 deletions
236
a3p-integration/proposals/p:upgrade-19/agoricNames.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
/* eslint-env node */ | ||
|
||
/** | ||
* @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. 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. | ||
* 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. | ||
* 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 | ||
* | ||
* | ||
* 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 | ||
* | ||
* 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 | ||
* | ||
*/ | ||
|
||
import '@endo/init'; | ||
import test from 'ava'; | ||
import { | ||
agoric, | ||
ATOM_DENOM, | ||
evalBundles, | ||
getIncarnation, | ||
GOV1ADDR, | ||
openVault, | ||
} from '@agoric/synthetic-chain'; | ||
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 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( | ||
() => 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( | ||
{ fetch }, | ||
{ rpcAddrs: ['http://localhost:26657'], chainName: 'agoriclocal' }, | ||
); | ||
|
||
t.context = { | ||
vstorageKit, | ||
}; | ||
}); | ||
|
||
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); | ||
|
||
const incarnation = await getIncarnation('agoricNames'); | ||
t.is(incarnation, 1, 'incorrect incarnation'); | ||
}); | ||
|
||
test.serial('check all existing values are preserved', async t => { | ||
// @ts-expect-error casting | ||
const { vstorageKit } = t.context; | ||
const agoricNamesChildren = [ | ||
'brand', | ||
'installation', | ||
'instance', | ||
'issuer', | ||
'oracleBrand', | ||
'vbankAsset', | ||
]; | ||
|
||
const getAgoricNames = () => | ||
Promise.all( | ||
agoricNamesChildren.map(async child => { | ||
const content = await vstorageKit.readLatestHead( | ||
`published.agoricNames.${child}`, | ||
); | ||
return [child, Object.fromEntries(content)]; | ||
}), | ||
).then(rawAgoricNames => Object.fromEntries(rawAgoricNames)); | ||
|
||
const agoricNamesBefore = await getAgoricNames(); | ||
console.log('AGORIC_NAMES_BEFORE', agoricNamesBefore); | ||
|
||
await evalBundles(WRITE_AGORIC_NAMES_DIR); | ||
|
||
const agoricNamesAfter = await getAgoricNames(); | ||
t.like(agoricNamesAfter, agoricNamesBefore); | ||
|
||
agoricNamesChildren.forEach(child => | ||
Check warning on line 158 in a3p-integration/proposals/p:upgrade-19/agoricNames.test.js GitHub Actions / lint-rest
|
||
assert( | ||
agoricNamesAfter[child][`test${child}`], | ||
'we should be able to add new value', | ||
), | ||
); | ||
}); | ||
|
||
test.serial('check testInfo still works', async t => { | ||
// @ts-expect-error casting | ||
const { vstorageKit } = t.context; | ||
await evalBundles(WRITE_TEST_INFO_DIR); | ||
|
||
const testInfo = await vstorageKit.readLatestHead( | ||
'published.agoricNames.testInfo', | ||
); | ||
t.deepEqual(Object.fromEntries(testInfo), { | ||
agoric: { | ||
isAwesome: 'yes', | ||
tech: ['HardenedJs', 'Orchestration', 'Async_Execution'], | ||
}, | ||
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 = { | ||
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('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.`, | ||
); | ||
}); |
7 changes: 7 additions & 0 deletions
7
...oposals/p:upgrade-19/agoricNamesCoreEvals/depositUsdOlives/deposit-usd-olives-permit.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"consume": { | ||
"contractKits": true, | ||
"namesByAddressAdmin": true, | ||
"agoricNames": true | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
...ration/proposals/p:upgrade-19/agoricNamesCoreEvals/depositUsdOlives/deposit-usd-olives.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
5 changes: 5 additions & 0 deletions
5
...als/p:upgrade-19/agoricNamesCoreEvals/writeToAgoricNames/write-to-agoricNames-permit.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"consume": { | ||
"agoricNamesAdmin": true | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...on/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToAgoricNames/write-to-agoricNames.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// @ts-nocheck | ||
/* eslint-disable no-undef */ | ||
const writeToAgoricNames = async powers => { | ||
const { | ||
consume: { agoricNamesAdmin }, | ||
} = powers; | ||
|
||
console.log('writing to agoricNames...'); | ||
const agoricNamesChildren = [ | ||
'brand', | ||
'installation', | ||
'instance', | ||
'issuer', | ||
'oracleBrand', | ||
'vbankAsset', | ||
]; | ||
|
||
await Promise.all( | ||
agoricNamesChildren.map(async (child, index) => | ||
E(E(agoricNamesAdmin).lookupAdmin(child)).update( | ||
`test${child}`, | ||
Far(`test${child}`, { getBoardId: () => `board${index}` }), | ||
), | ||
), | ||
); | ||
|
||
console.log('DONE'); | ||
}; | ||
|
||
writeToAgoricNames; |
5 changes: 5 additions & 0 deletions
5
...proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo-permit.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"consume": { | ||
"agoricNamesAdmin": true | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...egration/proposals/p:upgrade-19/agoricNamesCoreEvals/writeToTestInfo/write-to-testInfo.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.