Skip to content

Commit

Permalink
upgrade scaledPriceAuthorities (#9382)
Browse files Browse the repository at this point in the history
refs: #8400
refs: #8498
closes: #9371

## Description

#8400 reported that the priceFeed vats hold onto old quotes in their
recoverySet, preventing them from being collected. #9283 applied the
fixes to master. These fixes address the growth in priceFeed vats and
Zoe, but scaledPriceAuthorities were still growing. This resolves that
problem by upgrading scaledPriceAuthority contracts to not use their
recoverySets.

<details>
  <summary><b>Expand</b> for performance graphs</summary>
  
<img width="809" alt="image"
src="https://github.com/Agoric/agoric-sdk/assets/13372636/889bb283-89c8-434f-8a67-efa56d0382ad">

Kernel allocation is in blue, and the scale is on the left. It varies
from 48862 to 49743, with a small amount of long-term growth.The other
active vats (v9=Zoe, v29=ATOM-USD_priceFeed, v43=wallet,
72=ATOM-USD_priceFeed, 74=auctioneer) use the scale on the right, with
Zoe varying tightly around 3600, and the others low and stable.

scaledPriceAuthority-ATOM doesn't have enough variation to be worth
graphing.

</details>

### Security Considerations

Upgrade existing contracts. No new vulnerabilities.

### Scaling Considerations

This addresses the largest known category of growth on the chain.

### Documentation Considerations

Add some documentation on creating proposals.

### Testing Considerations

Tested in A3P. We should exercise all the clients of priceFeeds in our
test environments.

### Upgrade Considerations

This PR includes a proposal that will upgrade all vats with
`scaledPriceAuthority` in their label. That should work on or test
chains as well as MainNet. These changes should be included in the next
release.
  • Loading branch information
mergify[bot] committed May 24, 2024
2 parents cc2bf0b + 04ba2b5 commit 0270908
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 16 deletions.
2 changes: 2 additions & 0 deletions golang/cosmos/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,8 @@ func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Conte
vm.CoreProposalStepForModules( "@agoric/builders/scripts/vats/add-auction.js"),
// upgrade vaultFactory.
vm.CoreProposalStepForModules( "@agoric/builders/scripts/vats/upgradeVaults.js"),
// upgrade scaledPriceAuthorities.
vm.CoreProposalStepForModules( "@agoric/builders/scripts/vats/upgradeScaledPriceAuthorities.js"),
}
}

Expand Down
9 changes: 3 additions & 6 deletions packages/ERTP/src/issuerKit.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,9 @@ export const upgradeIssuerKit = (
) {
Fail`Cannot (yet?) upgrade from 'noRecoverySets' to 'hasRecoverySets'`;
}
if (
oldRecoverySetsState === 'hasRecoverySets' &&
recoverySetsOption === 'noRecoverySets'
) {
Fail`Cannot (yet?) upgrade from 'hasRecoverySets' to 'noRecoverySets'`;
}
// Extant sets are not currently deleted. If the new option is
// 'noRecoverySets', they won't be used but extant ones will remain. Future
// upgrades may make it possible to delete elements from them.
const recoverySetsState = recoverySetsOption || oldRecoverySetsState;
return setupIssuerKit(
issuerRecord,
Expand Down
25 changes: 25 additions & 0 deletions packages/builders/scripts/vats/upgradeScaledPriceAuthorities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { makeHelpers } from '@agoric/deploy-script-support';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */
export const defaultProposalBuilder = async ({ publishRef, install }) =>
harden({
sourceSpec:
'@agoric/inter-protocol/src/proposals/upgrade-scaledPriceAuthorities.js',
getManifestCall: [
'getManifestForUpgradeScaledPriceAuthorities',
{
scaledPARef: publishRef(
install('@agoric/zoe/src/contracts/scaledPriceAuthority.js'),
),
},
],
});

export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);

await writeCoreProposal(
'upgradeScaledPriceAuthorities',
defaultProposalBuilder,
);
};
35 changes: 28 additions & 7 deletions packages/deploy-script-support/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,35 @@ To install code on chain or in the a3p-integration environment, you'll have to
generate a proposal, and write a script to build the core proposal. The
proposals have limited access to bootstrap powers, described by their manifests.

There are collections of proposals in .../vats/src/proposals,
smart-wallet/src/proposals, orchestration/src/proposals, pegasus/src/proposals.

The overall format is a proposalBuilder script (There are several in
.../builders/scripts/vats/) which has a default export that passes resources to
the proposal. The resources include bundled source code and string-value
parameters. The ProposalBuilder specifies (as an import string) the proposal
it uses, identifies the "manifest", (which associates permissions to access
powers in the bootstrap space with functions to be called), and builds bundles
of source code needed by the proposal.

`.../builders/scripts/vats/upgradeVaults.js` is a canonical example. It says the
proposal to run is '@agoric/inter-protocol/src/proposals/upgrade-vaults.js',
lists the manifest there as `'getManifestForUpgradeVaults'`, and directs the
creation of a bundle from
'@agoric/inter-protocol/src/vaultFactory/vaultFactory.js', which will be made
available to the proposal as `vaultsRef` in options.

`upgrade-vaults.js` defines `getManifestForUpgradeVaults()`, which returns a
`manifest` that says `upgradeVaults()` should be executed, and specifies what
powers it should have access to.

### Proposal

The proposal is called with `(powers, options)` available. The manifest
detailing the powers that will be used is usually in the same file, and
conventionally provided by a function named `getManifestForFoo`. The manifest
needs to have a unique name, since it will be referenced by name from the script.
The usual format is
needs to have a unique name, since it will be referenced by name from the
script. The usual format is
```js
export const foo = async (
{
Expand All @@ -24,6 +45,7 @@ export const foo = async (
},
options,
) => {
const { fooRef } = options;
// do the things using powers and options
};

Expand All @@ -44,14 +66,13 @@ export const getManifestForFoo = (powers, options) => {
`options` allows the proposal to be provided with arbitray other powerful
objects.
### Script
### proposalBuilder Script
The script describes how to build the core proposal. For
`agoric-3-proposals` and uploading to the chain, the script must be named in the
`CoreProposalSteps` section in
[`app.go`](https://github.com/Agoric/agoric-sdk/blob/b13743a2cccf0cb63a412b54384435596d4e81ea/golang/cosmos/app/app.go#L881),
and its `defaultProposalBuilder` will be invoked
directly.
and its `defaultProposalBuilder` will be invoked directly.
Script files should export `defaultProposalBuilder` and a `default` function
that invokes `writeCoreProposal` one or more times to generate sets of files
Expand Down Expand Up @@ -79,8 +100,8 @@ export default async (homeP, endowments) => {

The first element of `getManifestCall` is interpreted as the name of a proposal.
The second element of `getManifestCall` produces the `options` argument passed
to the proposal. (`foo` in the example above). A common thing to want to pass in
options is a reference to code to be installed on-chain. The `fooRef` example
to the proposal. (`fooRef` in the example above). A common thing to want to pass
in options is a reference to code to be installed on-chain. The `fooRef` example
above shows how. `publishRef(install(<path>))` is built from sources in the
sdk, and passed as a `bundleRef`, which contains a `bundleID` suitable for
passing to Zoe (for contracts) or `vatAdminService` (for non-contract vat code).
Expand Down
5 changes: 2 additions & 3 deletions packages/inter-protocol/src/proposals/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Proposals

These are code snippets that go into propoals to the BLDer DAO to start the Inter Protocol.
These scripts are referenced by proposals to the BLDer DAO to run on the chain.

One of the latest is `startPSM.js` so best to model after that. The style in `econ-behaviors.js` will be refactored to be like startPSM.
See the documentation in .../deploy-script-support/README.md

[syntax of the manifests](../../packages/vats/src/core/manifest.js)
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { makeTracer } from '@agoric/internal';
import { E } from '@endo/far';

const trace = makeTracer('upgradeScaledPA', true);

/**
* @param {ChainBootstrapSpace} powers
* @param {{ options: { scaledPARef: { bundleID: string } } }} options
*/
export const upgradeScaledPriceAuthorities = async (
{
consume: {
agoricNamesAdmin,
contractKits: contractKitsP,
instancePrivateArgs: instancePrivateArgsP,
zoe,
},
},
{ options },
) => {
trace('start');
const { scaledPARef } = options;
await null;

const bundleID = scaledPARef.bundleID;
if (scaledPARef && bundleID) {
await E.when(
E(zoe).installBundleID(bundleID),
installation =>
E(E(agoricNamesAdmin).lookupAdmin('installation')).update(
'scaledPriceAuthority',
installation,
),
err =>
console.error(
`🚨 failed to update scaledPriceAuthority installation`,
err,
),
);
}

const [contractKits, instancePrivateArgs] = await Promise.all([
contractKitsP,
instancePrivateArgsP,
]);
/** @type {StartedInstanceKit<any>[]} */
const scaledPAKitEntries = Array.from(contractKits.values()).filter(
kit => kit.label && kit.label.match(/scaledPriceAuthority/),
);

for (const kitEntry of scaledPAKitEntries) {
const { instance } = kitEntry;
const privateArgs = instancePrivateArgs.get(instance);
trace('upgrade scaledPriceAuthority', kitEntry.label);
await E(kitEntry.adminFacet).upgradeContract(bundleID, privateArgs);
}
};

const t = 'upgradeScaledPriceAuthority';
export const getManifestForUpgradeScaledPriceAuthorities = async (
_ign,
upgradeSPAOptions,
) => ({
manifest: {
[upgradeScaledPriceAuthorities.name]: {
consume: {
agoricNamesAdmin: t,
contractKits: t,
instancePrivateArgs: t,
zoe: t,
},
instance: {
produce: t,
},
},
},
options: { ...upgradeSPAOptions },
});

0 comments on commit 0270908

Please sign in to comment.