diff --git a/config/config.go b/config/config.go index 3dd93f49..60972f0a 100644 --- a/config/config.go +++ b/config/config.go @@ -48,6 +48,9 @@ type Config struct { Networks config.Networks `mapstructure:"networks"` Wallet Wallet `mapstructure:"wallets"` AddressBook AddressBook `mapstructure:"address_book"` + + // LastMigration is the last migration version. + LastMigration int `mapstructure:"last_migration"` } // Directory returns the path to the used configuration directory. @@ -175,8 +178,16 @@ func (cfg *Config) Save() error { func (cfg *Config) Migrate() (bool, error) { var changes bool + // Versioned migrations. + verChanges, err := cfg.migrateVersions() + if err != nil { + return false, err + } + changes = changes || verChanges + // Networks. - changes = changes || cfg.migrateNetworks() + netChanges := cfg.migrateNetworks() + changes = changes || netChanges // Wallets. walletChanges, err := cfg.Wallet.Migrate() diff --git a/config/default.go b/config/default.go index e99ea9bb..42f8c572 100644 --- a/config/default.go +++ b/config/default.go @@ -6,7 +6,8 @@ import ( // Default is the default config that should be used in case no configuration file exists. var Default = Config{ - Networks: config.DefaultNetworks, + Networks: config.DefaultNetworks, + LastMigration: latestMigrationVersion, } // OldNetwork contains information about an old version of a known network configuration. diff --git a/config/migrate.go b/config/migrate.go new file mode 100644 index 00000000..bb4dcf2a --- /dev/null +++ b/config/migrate.go @@ -0,0 +1,117 @@ +package config + +import ( + "fmt" + + "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config" +) + +// latestMigrationVersion is the target migration version. All migrations from prior versions will +// be executed to reach this target version. +const latestMigrationVersion = 1 + +// migrationFunc is a configuration migration function. +// +// It should return true if any changes have been applied as part of the migration. +type migrationFunc func(*Config) (bool, error) + +var migrations = map[int]migrationFunc{ + 0: migrateFromV0, +} + +// migrateFromV0 performs the following migrations: +// +// - Any old Pontus-X ParaTimes on Testnet are removed. +// - New Pontus-X ParaTimes on Testnet are added. +func migrateFromV0(cfg *Config) (bool, error) { + const testnetChainContext = "0b91b8e4e44b2003a7c5e23ddadb5e14ef5345c0ebcb3ddcae07fa2f244cab76" + pontusx := map[string]*config.ParaTime{ + "pontusx_dev": { + Description: "Pontus-X Devnet", + ID: "0000000000000000000000000000000000000000000000004febe52eb412b421", + Denominations: map[string]*config.DenominationInfo{ + config.NativeDenominationKey: { + Symbol: "EUROe", + Decimals: 18, + }, + // The consensus layer denomination when deposited into the runtime. + "TEST": { + Symbol: "TEST", + Decimals: 18, + }, + }, + ConsensusDenomination: "TEST", + }, + "pontusx_test": { + Description: "Pontus-X Testnet", + ID: "00000000000000000000000000000000000000000000000004a6f9071c007069", + Denominations: map[string]*config.DenominationInfo{ + config.NativeDenominationKey: { + Symbol: "EUROe", + Decimals: 18, + }, + // The consensus layer denomination when deposited into the runtime. + "TEST": { + Symbol: "TEST", + Decimals: 18, + }, + }, + ConsensusDenomination: "TEST", + }, + } + + for _, net := range cfg.Networks.All { + if net.ChainContext != testnetChainContext { + continue + } + + // Delete old Pontus-X ParaTimes and fix the defaults. + for ptName, pt := range net.ParaTimes.All { + for newPtName, newPt := range pontusx { + if pt.ID != newPt.ID { + continue + } + + delete(net.ParaTimes.All, ptName) + if net.ParaTimes.Default == ptName { + net.ParaTimes.Default = newPtName + } + } + } + + // Add new Pontus-X ParaTimes. + for ptName, pt := range pontusx { + ptCopy := *pt + net.ParaTimes.All[ptName] = &ptCopy + } + } + return true, nil +} + +// migrateVersions applies migrations for all versions up to the latestMigrationVersion. +func (cfg *Config) migrateVersions() (bool, error) { + var changes bool + for v := cfg.LastMigration; v < latestMigrationVersion; v++ { + fn, ok := migrations[v] + if !ok { + return false, fmt.Errorf("missing migration from version %d", v) + } + + ch, err := fn(cfg) + if err != nil { + return false, fmt.Errorf("failed to apply migration from version %d: %w", v, err) + } + changes = changes || ch + cfg.LastMigration = v + 1 + } + return changes, nil +} + +func init() { + // Make sure that it is possible to migrate from zero to the latest migration version. + for v := 0; v < latestMigrationVersion; v++ { + if _, ok := migrations[v]; !ok { + panic(fmt.Errorf("missing migration from version %d", v)) + } + } +} diff --git a/examples/paratime-remove/00-list.out b/examples/paratime-remove/00-list.out index 49c3f664..d31bd479 100644 --- a/examples/paratime-remove/00-list.out +++ b/examples/paratime-remove/00-list.out @@ -1,10 +1,12 @@ -NETWORK PARATIME ID DENOMINATION(S) -mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) -mainnet emerald (*) 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) -mainnet sapphire 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) -testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) -testnet emerald (*) 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) - TEST[18] -testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) -testnet sapphire2 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6d TEST[18] (*) +NETWORK PARATIME ID DENOMINATION(S) +mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) +mainnet emerald (*) 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) +mainnet sapphire 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) +testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) +testnet emerald (*) 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EUROe[18] (*) + TEST[18] +testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) +testnet sapphire2 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6d TEST[18] (*) diff --git a/examples/paratime-remove/02-list.out b/examples/paratime-remove/02-list.out index 9c08cb7e..ce4d67e1 100644 --- a/examples/paratime-remove/02-list.out +++ b/examples/paratime-remove/02-list.out @@ -1,9 +1,11 @@ -NETWORK PARATIME ID DENOMINATION(S) -mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) -mainnet emerald (*) 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) -mainnet sapphire 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) -testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) -testnet emerald (*) 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) - TEST[18] -testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) +NETWORK PARATIME ID DENOMINATION(S) +mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) +mainnet emerald (*) 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) +mainnet sapphire 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) +testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) +testnet emerald (*) 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EUROe[18] (*) + TEST[18] +testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) diff --git a/examples/paratime/00-list.out b/examples/paratime/00-list.out index 38e45f9e..d493a5ce 100644 --- a/examples/paratime/00-list.out +++ b/examples/paratime/00-list.out @@ -4,6 +4,8 @@ mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc00 mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EUROe[18] (*) TEST[18] testnet sapphire (*) 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) diff --git a/examples/paratime/02-list.out b/examples/paratime/02-list.out index b3276036..a13b7640 100644 --- a/examples/paratime/02-list.out +++ b/examples/paratime/02-list.out @@ -4,6 +4,8 @@ mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc00 mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) testnet cipher (*) 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EUROe[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EUROe[18] (*) TEST[18] testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) diff --git a/go.mod b/go.mod index d20978b2..197bce9e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991920 github.com/oasisprotocol/oasis-core/go v0.2300.11 - github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.2 + github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.3 github.com/olekukonko/tablewriter v0.0.5 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 @@ -112,7 +112,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/skeema/knownhosts v1.2.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect @@ -135,7 +135,7 @@ require ( golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect - google.golang.org/grpc v1.62.1 // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/grpc/security/advancedtls v0.0.0-20221004221323-12db695f1648 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index e912ca7b..d8caf9cd 100644 --- a/go.sum +++ b/go.sum @@ -424,8 +424,8 @@ github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991 github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991920/go.mod h1:MKr/giwakLyCCjSWh0W9Pbaf7rDD1K96Wr57OhNoUK0= github.com/oasisprotocol/oasis-core/go v0.2300.11 h1:YBkBSyLDMDWv3yoYEJ8WUPuumqFJsMNZWb71MXCKLmk= github.com/oasisprotocol/oasis-core/go v0.2300.11/go.mod h1:6BzLqNrFtX85fbEeNeq7oGOS/mF/z1EjIYSe739jOzQ= -github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.2 h1:8BJVdKJrjGHdkswR9Zu+fGH1swJjGd63fhGsARZn+nc= -github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.2/go.mod h1:4cbLgDDrRS2wiqqqj3mWxGKezfMEqiyOhtfESjjqBYU= +github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.3 h1:O4rO7rJmNa2mh+ne7FsAp73XNXTB2Bbhnexvt4y+wew= +github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.8.3/go.mod h1:1ONQX/UyefGLTTx+pxMrirNLIh4WrLqtpYQV9Re0+MU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -483,8 +483,8 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= @@ -856,8 +856,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/examples v0.0.0-20201112215255-90f1b3ee835b h1:NuxyvVZoDfHZwYW9LD4GJiF5/nhiSyP4/InTrvw9Ibk= google.golang.org/grpc/examples v0.0.0-20201112215255-90f1b3ee835b/go.mod h1:IBqQ7wSUJ2Ep09a8rMWFsg4fmI2r38zwsq8a0GgxXpM= google.golang.org/grpc/security/advancedtls v0.0.0-20221004221323-12db695f1648 h1:6QzP+WLZE/9OvbE6nfd8MVjgjyypxtXMVE00LjsJHqQ=