-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(vat-upgrade): upgrade agoricNames, test old values are preserved #10616
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 => | ||
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.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please take a look at this file and let me know the test coverage (including the skipped one) here makes sense and is enough? @Chris-Hibbert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this only tests reading via
vstorage
. I'd like to ensure that objects (issuers, brands, etc.) retrieved from it after upgrade are still valid unbroken objects. I presume this can be done from inside a proposal.Is there anything here that tests
onUpdate
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we check the vstorage but the way
nameHub
works is that when a hub is written new data, ALL of its entries are published to vstorage. See;agoric-sdk/packages/vats/src/nameHub.js
Lines 113 to 122 in e596a01
So what we do is;
agoricNames
via a core-evalagoricNames
publish ALL their entries to vstorage along with the new dataMy plan for making sure the objects are unbroken is to go over the contracts that use
agoricNames
and make sure they still function as expected. For example, in order to open a vault there needs to be a valid instance object inpublished.agoricNames.instance
forVaultFactory
.Test named
check we can add new chains
appends a new chain topublished.agoricNames.chain
andpublished.agoricNames.chainConnection
. Both of these paths have theironUpdate
callback registered here:agoric-sdk/packages/orchestration/src/proposals/init-chain-info.js
Lines 46 to 67 in e596a01
The fact that we are able to append and observe new chain info after an upgrade shows that
onUpdate
callback above works.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good.
Great!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like 2195ace disables
init-chain-info.js
. So made this commit 47c9309 to test ephemeralonUpdate
calls.