Skip to content

Commit

Permalink
feat: make software upgrade coreProposals conditional on upgrade plan…
Browse files Browse the repository at this point in the history
… name (tentative #9575)
  • Loading branch information
mhofman committed Jun 26, 2024
2 parents b164347 + 34684e5 commit 78d7794
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 114 deletions.
2 changes: 1 addition & 1 deletion a3p-integration/proposals/a:upgrade-16/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"agoricProposal": {
"releaseNotes": false,
"sdkImageTag": "unreleased",
"planName": "agoric-upgrade-16",
"planName": "agoric-upgrade-16-a3p-integration",
"upgradeInfo": {
"coreProposals": []
},
Expand Down
82 changes: 2 additions & 80 deletions golang/cosmos/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ import (

appante "github.com/Agoric/agoric-sdk/golang/cosmos/ante"
agorictypes "github.com/Agoric/agoric-sdk/golang/cosmos/types"

// conv "github.com/Agoric/agoric-sdk/golang/cosmos/types/conv"
"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
"github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset"
swingsetclient "github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/client"
Expand Down Expand Up @@ -907,86 +909,6 @@ func NewAgoricApp(
return app
}

var upgradeNamesOfThisVersion = map[string]bool{
"agoric-upgrade-16": true,
"agorictest-upgrade-16": true,
}

func isFirstTimeUpgradeOfThisVersion(app *GaiaApp, ctx sdk.Context) bool {
for name := range upgradeNamesOfThisVersion {
if app.UpgradeKeeper.GetDoneHeight(ctx, name) != 0 {
return false
}
}
return true
}

// upgrade16Handler performs standard upgrade actions plus custom actions for upgrade-16.
func upgrade16Handler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) {
return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
app.CheckControllerInited(false)

CoreProposalSteps := []vm.CoreProposalStep{}

// These CoreProposalSteps are not idempotent and should only be executed
// as part of the first upgrade using this handler on any given chain.
if isFirstTimeUpgradeOfThisVersion(app, ctx) {
// Each CoreProposalStep runs sequentially, and can be constructed from
// one or more modules executing in parallel within the step.
CoreProposalSteps = []vm.CoreProposalStep{
// Upgrade Zoe + ZCF
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/replace-zoe.js"),
// Revive KREAd characters
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/revive-kread.js"),

// upgrade the provisioning vat
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/replace-provisioning.js"),
// Enable low-level Orchestration.
vm.CoreProposalStepForModules(
"@agoric/builders/scripts/vats/init-network.js",
"@agoric/builders/scripts/vats/init-localchain.js",
"@agoric/builders/scripts/vats/init-transfer.js",
),
// Add new vats for price feeds. The existing ones will be retired shortly.
vm.CoreProposalStepForModules(
"@agoric/builders/scripts/vats/updateAtomPriceFeed.js",
"@agoric/builders/scripts/vats/updateStAtomPriceFeed.js",
"@agoric/builders/scripts/vats/updateStOsmoPriceFeed.js",
"@agoric/builders/scripts/vats/updateStTiaPriceFeed.js",
"@agoric/builders/scripts/vats/updateStkAtomPriceFeed.js",
),
// Add new auction contract. The old one will be retired shortly.
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/add-auction.js"),
// upgrade vaultFactory.
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/upgradeVaults.js"),
}
}

app.upgradeDetails = &upgradeDetails{
// Record the plan to send to SwingSet
Plan: plan,
// Core proposals that should run during the upgrade block
// These will be merged with any coreProposals specified in the
// upgradeInfo field of the upgrade plan ran as subsequent steps
CoreProposals: vm.CoreProposalsFromSteps(CoreProposalSteps...),
}

// Always run module migrations
mvm, err := app.mm.RunMigrations(ctx, app.configurator, fromVm)
if err != nil {
return mvm, err
}

m := swingsetkeeper.NewMigrator(app.SwingSetKeeper)
err = m.MigrateParams(ctx)
if err != nil {
return mvm, err
}

return mvm, nil
}
}

// normalizeModuleAccount ensures that the given account is a module account,
// initializing or updating it if necessary. The account name must be listed in maccPerms.
func normalizeModuleAccount(ctx sdk.Context, ak authkeeper.AccountKeeper, name string) {
Expand Down
212 changes: 212 additions & 0 deletions golang/cosmos/app/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package gaia

import (
"encoding/json"
"fmt"
"strings"
"text/template"

"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
swingsetkeeper "github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

var upgradeNamesOfThisVersion = map[string]bool{
"agoric-upgrade-16-basic": true, // no-frills
"agoric-upgrade-16-a3p-integration": true,
"agoric-upgrade-16-main": true,
"agoric-upgrade-16-devnet": true,
}

func isFirstTimeUpgradeOfThisVersion(app *GaiaApp, ctx sdk.Context) bool {
for name := range upgradeNamesOfThisVersion {
if app.UpgradeKeeper.GetDoneHeight(ctx, name) != 0 {
return false
}
}
return true
}

// upgradePriceFeedCoreProposalSteps returns the core proposal steps for the
// price feed upgrade and associated changes to scaledPriceAuthority and
// vaultManager.
func upgradePriceFeedCoreProposalSteps(upgradeName string) ([]vm.CoreProposalStep, error) {
isThisUpgrade := func(expectedUpgradeName string) bool {
return upgradeName == expectedUpgradeName
}

t := template.Must(template.New("").Parse(`{
"module": "@agoric/builders/scripts/vats/priceFeedSupport.js",
"entrypoint": {{.entrypointJson}},
"args": [{
"AGORIC_INSTANCE_NAME": {{.instanceNameJson}},
"ORACLE_ADDRESSES": {{.oracleAddressesJson}},
"IN_BRAND_LOOKUP": {{.inBrandLookupJson}},
"IN_BRAND_DECIMALS": 6,
"OUT_BRAND_LOOKUP": ["agoricNames", "oracleBrand", "USD"],
"OUT_BRAND_DECIMALS": 4
}]
}`))

var oracleAddresses []string

var entrypoint string
switch {
case isThisUpgrade("agoric-upgrade-16-a3p-integration"):
entrypoint = "deprecatedPriceFeedProposalBuilder"
case isThisUpgrade("agoric-upgrade-16-main"):
oracleAddresses = []string{
"agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78", // DSRV
"agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p", // Stakin
"agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8", // 01node
"agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr", // Simply Staking
"agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj", // P2P
}
entrypoint = "strictPriceFeedProposalBuilder"
case isThisUpgrade("agoric-upgrade-16-devnet"):
oracleAddresses = []string{
"agoric1lw4e4aas9q84tq0q92j85rwjjjapf8dmnllnft", // DSRV
"agoric1zj6vrrrjq4gsyr9lw7dplv4vyejg3p8j2urm82", // Stakin
"agoric1ra0g6crtsy6r3qnpu7ruvm7qd4wjnznyzg5nu4", // 01node
"agoric1qj07c7vfk3knqdral0sej7fa6eavkdn8vd8etf", // Simply Staking
"agoric10vjkvkmpp9e356xeh6qqlhrny2htyzp8hf88fk", // P2P
}
entrypoint = "strictPriceFeedProposalBuilder"

// No price feed upgrade for this version.
case isThisUpgrade("agoric-upgrade-16-basic"):
}

if entrypoint == "" {
return []vm.CoreProposalStep{}, nil
}

entrypointJson, err := json.Marshal(entrypoint)
if err != nil {
return nil, err
}

var inBrandNames []string
switch {
case isThisUpgrade("agoric-upgrade-16-a3p-integration"), isThisUpgrade("agoric-upgrade-16-main"):
inBrandNames = []string{
"ATOM",
"stATOM",
"stOSMO",
"stTIA",
"stkATOM",
}
case isThisUpgrade("agoric-upgrade-16-devnet"):
inBrandNames = []string{
"ATOM",
"stTIA",
"stkATOM",
}
}

oracleAddressesJson, err := json.Marshal(oracleAddresses)
if err != nil {
return nil, err
}

proposals := make(vm.CoreProposalStep, 0, len(inBrandNames))
for _, inBrandName := range inBrandNames {
instanceName := inBrandName + "-USD price feed"
instanceNameJson, err := json.Marshal(instanceName)
if err != nil {
return nil, err
}
inBrandLookup := []string{"agoricNames", "oracleBrand", inBrandName}
inBrandLookupJson, err := json.Marshal(inBrandLookup)
if err != nil {
return nil, err
}

var result strings.Builder
err = t.Execute(&result, map[string]any{
"entrypointJson": string(entrypointJson),
"inBrandLookupJson": string(inBrandLookupJson),
"instanceNameJson": string(instanceNameJson),
"oracleAddressesJson": string(oracleAddressesJson),
})
if err != nil {
return nil, err
}

jsonStr := result.String()
jsonBz := []byte(jsonStr)
if !json.Valid(jsonBz) {
return nil, fmt.Errorf("invalid JSON: %s", jsonStr)
}
proposals = append(proposals, vm.ArbitraryCoreProposal{Json: jsonBz})
}
return []vm.CoreProposalStep{
// Add new vats for price feeds. The existing ones will be retired shortly.
vm.CoreProposalStepForModules(proposals...),
// Add new auction contract. The old one will be retired shortly.
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/add-auction.js"),
// upgrade vaultFactory.
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/upgradeVaults.js"),
}, nil
}

// upgrade16Handler performs standard upgrade actions plus custom actions for upgrade-16.
func upgrade16Handler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) {
return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
app.CheckControllerInited(false)

CoreProposalSteps := []vm.CoreProposalStep{}

// These CoreProposalSteps are not idempotent and should only be executed
// as part of the first upgrade using this handler on any given chain.
if isFirstTimeUpgradeOfThisVersion(app, ctx) {
// Each CoreProposalStep runs sequentially, and can be constructed from
// one or more modules executing in parallel within the step.
CoreProposalSteps = []vm.CoreProposalStep{
// Upgrade Zoe + ZCF
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/replace-zoe.js"),
// Revive KREAd characters
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/revive-kread.js"),

// upgrade the provisioning vat
vm.CoreProposalStepForModules("@agoric/builders/scripts/vats/replace-provisioning.js"),
// Enable low-level Orchestration.
vm.CoreProposalStepForModules(
"@agoric/builders/scripts/vats/init-network.js",
"@agoric/builders/scripts/vats/init-localchain.js",
"@agoric/builders/scripts/vats/init-transfer.js",
),
}
priceFeedSteps, err := upgradePriceFeedCoreProposalSteps(targetUpgrade)
if err != nil {
return nil, err
}
CoreProposalSteps = append(CoreProposalSteps, priceFeedSteps...)
}

app.upgradeDetails = &upgradeDetails{
// Record the plan to send to SwingSet
Plan: plan,
// Core proposals that should run during the upgrade block
// These will be merged with any coreProposals specified in the
// upgradeInfo field of the upgrade plan ran as subsequent steps
CoreProposals: vm.CoreProposalsFromSteps(CoreProposalSteps...),
}

// Always run module migrations
mvm, err := app.mm.RunMigrations(ctx, app.configurator, fromVm)
if err != nil {
return mvm, err
}

m := swingsetkeeper.NewMigrator(app.SwingSetKeeper)
err = m.MigrateParams(ctx)
if err != nil {
return mvm, err
}

return mvm, nil
}
}
24 changes: 22 additions & 2 deletions golang/cosmos/vm/core_proposals.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package vm

import (
"encoding/json"
"fmt"
)

// CoreProposalStep is a set of core proposal configs which are executed
// concurrently
type CoreProposalStep []Jsonable
Expand All @@ -11,12 +16,27 @@ type CoreProposals struct {
Steps []CoreProposalStep `json:"steps"`
}

type ArbitraryCoreProposal struct {
Json json.RawMessage
}

func NewArbitraryCoreProposal(jsonStr string) *ArbitraryCoreProposal {
return &ArbitraryCoreProposal{Json: []byte(jsonStr)}
}

// CoreProposalStepForModules generates a single core proposal step from
// the given modules, which will be executed concurrently during that step
func CoreProposalStepForModules(modules ...string) CoreProposalStep {
func CoreProposalStepForModules(modules ...Jsonable) CoreProposalStep {
step := make([]Jsonable, len(modules))
for i := range modules {
step[i] = modules[i]
switch m := modules[i].(type) {
case ArbitraryCoreProposal:
step[i] = m.Json
case string:
step[i] = m
default:
panic(fmt.Errorf("unexpected step type %T", m))
}
}
return step
}
Expand Down
Loading

0 comments on commit 78d7794

Please sign in to comment.