diff --git a/cmd/kava/cmd/root.go b/cmd/kava/cmd/root.go index e52193ae..8c2979aa 100644 --- a/cmd/kava/cmd/root.go +++ b/cmd/kava/cmd/root.go @@ -21,6 +21,7 @@ import ( "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app/params" kavaclient "github.com/kava-labs/kava/client" + "github.com/kava-labs/kava/migrate" ) // NewRootCmd creates a new root command for the kava blockchain. @@ -79,8 +80,8 @@ func addSubCmds(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, de genutilcli.InitCmd(app.ModuleBasics, defaultNodeHome), ), genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, defaultNodeHome), - // migrate.MigrateGenesisCmd(), - // migrate.AssertInvariantsCmd(encodingConfig), + migrate.MigrateGenesisCmd(), + migrate.AssertInvariantsCmd(encodingConfig), genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, defaultNodeHome), genutilcli.ValidateGenesisCmd(app.ModuleBasics), AddGenesisAccountCmd(defaultNodeHome), diff --git a/migrate/cmd.go b/migrate/cmd.go index 8b90ec46..ea9c5e75 100644 --- a/migrate/cmd.go +++ b/migrate/cmd.go @@ -96,9 +96,8 @@ func AssertInvariantsCmd(config params.EncodingConfig) *cobra.Command { func validateGenDoc(importGenesisFile string) (*tmtypes.GenesisDoc, error) { genDoc, err := tmtypes.GenesisDocFromFile(importGenesisFile) if err != nil { - return nil, fmt.Errorf("%s. Make sure that"+ - " you have correctly migrated all Tendermint consensus params, please see the"+ - " chain migration guide at https://docs.cosmos.network/master/migrations/chain-upgrade-guide-040.html for more info", + return nil, fmt.Errorf( + "%s. Make sure that you have correctly migrated all Tendermint consensus params.", err.Error(), ) } diff --git a/migrate/doc.go b/migrate/doc.go index ac687206..4576a263 100644 --- a/migrate/doc.go +++ b/migrate/doc.go @@ -6,10 +6,10 @@ migrated to the new structure of the newer versions. There are two types of migration: - **genesis migration** a script converts an exported genesis file from the old software to a new genesis file for the new software -- **live upgrade** a handler in the upgrade module converts data in the database itself from the old version to the new +- **in-place upgrade** a handler in the upgrade module converts data in the database itself from the old version to the new Genesis migration starts a whole new blockchain (with new chain-id) for the new software version. -Live upgrade keeps the blockchain (and chain-id) the same for the new software version. +In-Place upgrade keeps the blockchain (and chain-id) the same for the new software version. We only support migrations between mainnet kava releases. We only support migrations from the previous mainnet kava version to the current. We don't support migrating between two old versions, use the old software version for this. @@ -25,16 +25,5 @@ On each release we can delete the previous releases migration and old GenesisSta eg kava-3 migrates `auth.GenesisState` from kava-2 to `auth.GenesisState` from kava-3, but for kava-4 we don't need to keep around kava-2's `auth.GenesisState` type. -This folder contains old types from several sdk modules because they needed custom migrations for kava-3. -The sdk version for kava-2 was a master commit 18de63. - -Live Upgrade -The process is: -- submit upgrade proposal on old chain -- old chain halts -- people download new version and restart their validators -- on start the new upgrade handler runs -- use copypasted old keeper and types to read from db, convert to current types and write with current keeper - */ package migrate diff --git a/migrate/v0_17/kava.go b/migrate/v0_17/kava.go index 2788a8ef..1e7aada6 100644 --- a/migrate/v0_17/kava.go +++ b/migrate/v0_17/kava.go @@ -17,6 +17,8 @@ import ( v016auction "github.com/kava-labs/kava/x/auction/legacy/v0_16" v017auction "github.com/kava-labs/kava/x/auction/legacy/v0_17" auctiontypes "github.com/kava-labs/kava/x/auction/types" + v017bep3 "github.com/kava-labs/kava/x/bep3/legacy/v0_17" + bep3types "github.com/kava-labs/kava/x/bep3/types" incentivetypes "github.com/kava-labs/kava/x/incentive/types" savingstypes "github.com/kava-labs/kava/x/savings/types" ) @@ -88,4 +90,14 @@ func migrateAppState(appState genutiltypes.AppMap, clientCtx client.Context) { // x/savings savingsState := savingstypes.DefaultGenesisState() appState[savingstypes.ModuleName] = codec.MustMarshalJSON(&savingsState) + + // x/bep3 + if appState[bep3types.ModuleName] != nil { + var v16GenState bep3types.GenesisState + codec.MustUnmarshalJSON(appState[bep3types.ModuleName], &v16GenState) + + migratedState := v017bep3.Migrate(v16GenState) + + appState[bep3types.ModuleName] = codec.MustMarshalJSON(migratedState) + } } diff --git a/migrate/v0_17/testdata/genesis-v16.json b/migrate/v0_17/testdata/genesis-v16.json index 1b5980d9..a6a198bc 100644 --- a/migrate/v0_17/testdata/genesis-v16.json +++ b/migrate/v0_17/testdata/genesis-v16.json @@ -1145,7 +1145,7 @@ "denom": "btcb" } ], - "closed_block": "1", + "closed_block": "838115", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", "expire_height": "838627", @@ -1164,7 +1164,7 @@ "denom": "bnb" } ], - "closed_block": "1", + "closed_block": "1712118", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", "expire_height": "1736797", @@ -1186,7 +1186,7 @@ "closed_block": "787122", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", - "expire_height": "1", + "expire_height": "811799", "random_number_hash": "BFB7CC82DA0E0C8556AC37843F5AB136B9A7A066054368F5948944282B414D83", "recipient": "kava1eufgf0w9d7hf5mgtek4zr2upkxag9stmzx6unl", "recipient_other_chain": "bnb10zq89008gmedc6rrwzdfukjk94swynd7dl97w8", @@ -1205,7 +1205,7 @@ "closed_block": "787122", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", - "expire_height": "1", + "expire_height": "811799", "random_number_hash": "BFB7CC82DA0E0C8556AC37843F5AB136B9A7A066054368F5948944282B414D83", "recipient": "kava1hh4x3a4suu5zyaeauvmv7ypf7w9llwlfufjmuu", "recipient_other_chain": "bnb1vl3wn4x8kqajg2j9wxa5y5amgzdxchutkxr6at", @@ -1224,7 +1224,7 @@ "closed_block": "0", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", - "expire_height": "24687", + "expire_height": "1730589", "random_number_hash": "A74EA1AB58D312FDF1E872D18583CACCF294E639DDA4F303939E9ADCEC081D93", "recipient": "kava14qsmvzprqvhwmgql9fr0u3zv9n2qla8zhnm5pc", "recipient_other_chain": "bnb1lhk5ndlgf5wz55t8k35cqj6h9l3m4l5ek2w7q6", @@ -1243,13 +1243,13 @@ "closed_block": "0", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", - "expire_height": "1", + "expire_height": "1740000", "random_number_hash": "39E9ADCEC081D93A74EA1A83CACCF294E639DDA4F3039B58D312FDF1E872D185", "recipient": "kava1d2u28azje7rhqyjtxc2ex8q0cxxpw7dfm7ltq5", "recipient_other_chain": "bnb1xz3xqf4p2ygrw9lhp5g5df4ep4nd20vsywnmpr", "sender": "kava14qsmvzprqvhwmgql9fr0u3zv9n2qla8zhnm5pc", "sender_other_chain": "bnb1lhk5ndlgf5wz55t8k35cqj6h9l3m4l5ek2w7q6", - "status": "SWAP_STATUS_EXPIRED", + "status": "SWAP_STATUS_OPEN", "timestamp": "1641934114" } ], diff --git a/migrate/v0_17/testdata/genesis-v17.json b/migrate/v0_17/testdata/genesis-v17.json index 760df8b2..82e1a45b 100644 --- a/migrate/v0_17/testdata/genesis-v17.json +++ b/migrate/v0_17/testdata/genesis-v17.json @@ -465,7 +465,12 @@ }, "atomic_swaps": [ { - "amount": [{ "amount": "1999955998", "denom": "btcb" }], + "amount": [ + { + "amount": "1999955998", + "denom": "btcb" + } + ], "closed_block": "1", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", @@ -479,7 +484,12 @@ "timestamp": "1636034914" }, { - "amount": [{ "amount": "19000000000", "denom": "bnb" }], + "amount": [ + { + "amount": "19000000000", + "denom": "bnb" + } + ], "closed_block": "1", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", @@ -493,7 +503,12 @@ "timestamp": "1641976566" }, { - "amount": [{ "amount": "999595462080", "denom": "busd" }], + "amount": [ + { + "amount": "999595462080", + "denom": "busd" + } + ], "closed_block": "787122", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", @@ -507,7 +522,12 @@ "timestamp": "1635694492" }, { - "amount": [{ "amount": "999595462080", "denom": "busd" }], + "amount": [ + { + "amount": "999595462080", + "denom": "busd" + } + ], "closed_block": "787122", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", @@ -521,7 +541,12 @@ "timestamp": "1635694492" }, { - "amount": [{ "amount": "1000000", "denom": "btcb" }], + "amount": [ + { + "amount": "1000000", + "denom": "btcb" + } + ], "closed_block": "0", "cross_chain": true, "direction": "SWAP_DIRECTION_OUTGOING", @@ -535,7 +560,12 @@ "timestamp": "1641934114" }, { - "amount": [{ "amount": "1000000", "denom": "btcb" }], + "amount": [ + { + "amount": "1000000", + "denom": "btcb" + } + ], "closed_block": "0", "cross_chain": true, "direction": "SWAP_DIRECTION_INCOMING", diff --git a/x/bep3/legacy/v0_15/types.go b/x/bep3/legacy/v0_15/types.go deleted file mode 100644 index a87748a4..00000000 --- a/x/bep3/legacy/v0_15/types.go +++ /dev/null @@ -1,187 +0,0 @@ -package v0_15 - -import ( - "encoding/json" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - tmbytes "github.com/tendermint/tendermint/libs/bytes" -) - -const ( - // ModuleName is the name of the module - ModuleName = "bep3" -) - -// GenesisState - all bep3 state that must be provided at genesis -type GenesisState struct { - Params Params `json:"params" yaml:"params"` - AtomicSwaps AtomicSwaps `json:"atomic_swaps" yaml:"atomic_swaps"` - Supplies AssetSupplies `json:"supplies" yaml:"supplies"` - PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"` -} - -// Params governance parameters for bep3 module -type Params struct { - AssetParams AssetParams `json:"asset_params" yaml:"asset_params"` -} - -// AssetParams array of AssetParam -type AssetParams []AssetParam - -// AssetParam parameters that must be specified for each bep3 asset -type AssetParam struct { - Denom string `json:"denom" yaml:"denom"` // name of the asset - CoinID int `json:"coin_id" yaml:"coin_id"` // SLIP-0044 registered coin type - see https://github.com/satoshilabs/slips/blob/master/slip-0044.md - SupplyLimit SupplyLimit `json:"supply_limit" yaml:"supply_limit"` // asset supply limit - Active bool `json:"active" yaml:"active"` // denotes if asset is available or paused - DeputyAddress sdk.AccAddress `json:"deputy_address" yaml:"deputy_address"` // the address of the relayer process - FixedFee sdk.Int `json:"fixed_fee" yaml:"fixed_fee"` // the fixed fee charged by the relayer process for outgoing swaps - MinSwapAmount sdk.Int `json:"min_swap_amount" yaml:"min_swap_amount"` // Minimum swap amount - MaxSwapAmount sdk.Int `json:"max_swap_amount" yaml:"max_swap_amount"` // Maximum swap amount - MinBlockLock uint64 `json:"min_block_lock" yaml:"min_block_lock"` // Minimum swap block lock - MaxBlockLock uint64 `json:"max_block_lock" yaml:"max_block_lock"` // Maximum swap block lock -} - -// SupplyLimit parameters that control the absolute and time-based limits for an assets's supply -type SupplyLimit struct { - Limit sdk.Int `json:"limit" yaml:"limit"` // the absolute supply limit for an asset - TimeLimited bool `json:"time_limited" yaml:"time_limited"` // boolean for if the supply is also limited by time - TimePeriod time.Duration `json:"time_period" yaml:"time_period"` // the duration for which the supply time limit applies - TimeBasedLimit sdk.Int `json:"time_based_limit" yaml:"time_based_limit"` // the supply limit for an asset for each time period -} - -// AtomicSwaps is a slice of AtomicSwap -type AtomicSwaps []AtomicSwap - -// AtomicSwap contains the information for an atomic swap -type AtomicSwap struct { - Amount sdk.Coins `json:"amount" yaml:"amount"` - RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"` - ExpireHeight uint64 `json:"expire_height" yaml:"expire_height"` - Timestamp int64 `json:"timestamp" yaml:"timestamp"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"` - SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"` - RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"` - ClosedBlock int64 `json:"closed_block" yaml:"closed_block"` - Status SwapStatus `json:"status" yaml:"status"` - CrossChain bool `json:"cross_chain" yaml:"cross_chain"` - Direction SwapDirection `json:"direction" yaml:"direction"` -} - -// SwapStatus is the status of an AtomicSwap -type SwapStatus byte - -// swap statuses -const ( - NULL SwapStatus = 0x00 - Open SwapStatus = 0x01 - Completed SwapStatus = 0x02 - Expired SwapStatus = 0x03 -) - -// String returns the string representation of a SwapStatus -func (status SwapStatus) String() string { - switch status { - case Open: - return "Open" - case Completed: - return "Completed" - case Expired: - return "Expired" - default: - return "NULL" - } -} - -// NewSwapStatusFromString converts string to SwapStatus type -func NewSwapStatusFromString(str string) SwapStatus { - switch str { - case "Open", "open": - return Open - case "Completed", "completed": - return Completed - case "Expired", "expired": - return Expired - default: - return NULL - } -} - -// MarshalJSON marshals the SwapStatus -func (status SwapStatus) MarshalJSON() ([]byte, error) { - return json.Marshal(status.String()) -} - -// UnmarshalJSON unmarshals the SwapStatus -func (status *SwapStatus) UnmarshalJSON(data []byte) error { - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - *status = NewSwapStatusFromString(s) - return nil -} - -// SwapDirection is the direction of an AtomicSwap -type SwapDirection byte - -const ( - INVALID SwapDirection = 0x00 - Incoming SwapDirection = 0x01 - Outgoing SwapDirection = 0x02 -) - -// String returns the string representation of a SwapDirection -func (direction SwapDirection) String() string { - switch direction { - case Incoming: - return "Incoming" - case Outgoing: - return "Outgoing" - default: - return "INVALID" - } -} - -// NewSwapDirectionFromString converts string to SwapDirection type -func NewSwapDirectionFromString(str string) SwapDirection { - switch str { - case "Incoming", "incoming", "inc", "I", "i": - return Incoming - case "Outgoing", "outgoing", "out", "O", "o": - return Outgoing - default: - return INVALID - } -} - -// MarshalJSON marshals the SwapDirection -func (direction SwapDirection) MarshalJSON() ([]byte, error) { - return json.Marshal(direction.String()) -} - -// UnmarshalJSON unmarshals the SwapDirection -func (direction *SwapDirection) UnmarshalJSON(data []byte) error { - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - *direction = NewSwapDirectionFromString(s) - return nil -} - -// AssetSupplies is a slice of AssetSupply -type AssetSupplies []AssetSupply - -// AssetSupply contains information about an asset's supply -type AssetSupply struct { - IncomingSupply sdk.Coin `json:"incoming_supply" yaml:"incoming_supply"` - OutgoingSupply sdk.Coin `json:"outgoing_supply" yaml:"outgoing_supply"` - CurrentSupply sdk.Coin `json:"current_supply" yaml:"current_supply"` - TimeLimitedCurrentSupply sdk.Coin `json:"time_limited_current_supply" yaml:"time_limited_current_supply"` - TimeElapsed time.Duration `json:"time_elapsed" yaml:"time_elapsed"` -} diff --git a/x/bep3/legacy/v0_16/migrate.go b/x/bep3/legacy/v0_16/migrate.go deleted file mode 100644 index 61dc1d10..00000000 --- a/x/bep3/legacy/v0_16/migrate.go +++ /dev/null @@ -1,142 +0,0 @@ -package v0_16 - -import ( - "fmt" - - v015bep3 "github.com/kava-labs/kava/x/bep3/legacy/v0_15" - v016bep3 "github.com/kava-labs/kava/x/bep3/types" -) - -func migrateAssetParam(param v015bep3.AssetParam) v016bep3.AssetParam { - return v016bep3.AssetParam{ - Denom: param.Denom, - CoinID: int64(param.CoinID), - SupplyLimit: v016bep3.SupplyLimit{ - Limit: param.SupplyLimit.Limit, - TimeLimited: param.SupplyLimit.TimeLimited, - TimePeriod: param.SupplyLimit.TimePeriod, - TimeBasedLimit: param.SupplyLimit.TimeBasedLimit, - }, - Active: param.Active, - DeputyAddress: param.DeputyAddress, - FixedFee: param.FixedFee, - MinSwapAmount: param.MinSwapAmount, - MaxSwapAmount: param.MaxSwapAmount, - MinBlockLock: param.MinBlockLock, - MaxBlockLock: param.MaxBlockLock, - } -} - -func migrateParams(v015params v015bep3.Params) v016bep3.Params { - assetParams := make(v016bep3.AssetParams, len(v015params.AssetParams)) - for i, assetParam := range v015params.AssetParams { - assetParams[i] = migrateAssetParam(assetParam) - } - return v016bep3.Params{AssetParams: assetParams} -} - -func migrateSwapStatus(status v015bep3.SwapStatus) v016bep3.SwapStatus { - switch status { - case v015bep3.NULL: - return v016bep3.SWAP_STATUS_UNSPECIFIED - case v015bep3.Open: - return v016bep3.SWAP_STATUS_OPEN - case v015bep3.Completed: - return v016bep3.SWAP_STATUS_COMPLETED - case v015bep3.Expired: - return v016bep3.SWAP_STATUS_EXPIRED - default: - panic(fmt.Errorf("'%d' is not a valid swap status", status)) - } -} - -func migrateSwapDirection(direction v015bep3.SwapDirection) v016bep3.SwapDirection { - switch direction { - case v015bep3.INVALID: - return v016bep3.SWAP_DIRECTION_UNSPECIFIED - case v015bep3.Incoming: - return v016bep3.SWAP_DIRECTION_INCOMING - case v015bep3.Outgoing: - return v016bep3.SWAP_DIRECTION_OUTGOING - default: - panic(fmt.Errorf("'%d' is not a valid swap direction", direction)) - } -} - -func migrateAtomicSwaps(oldSwaps v015bep3.AtomicSwaps) v016bep3.AtomicSwaps { - newSwaps := make(v016bep3.AtomicSwaps, len(oldSwaps)) - for i, oldSwap := range oldSwaps { - swap := v016bep3.AtomicSwap{ - Amount: oldSwap.Amount, - RandomNumberHash: oldSwap.RandomNumberHash, - ExpireHeight: oldSwap.ExpireHeight, - Timestamp: oldSwap.Timestamp, - Sender: oldSwap.Sender, - Recipient: oldSwap.Recipient, - SenderOtherChain: oldSwap.SenderOtherChain, - RecipientOtherChain: oldSwap.RecipientOtherChain, - ClosedBlock: oldSwap.ClosedBlock, - Status: migrateSwapStatus(oldSwap.Status), - CrossChain: oldSwap.CrossChain, - Direction: migrateSwapDirection(oldSwap.Direction), - } - swap = resetSwapForZeroHeight(swap) - newSwaps[i] = swap - } - return newSwaps -} - -// resetSwapForZeroHeight updates swap expiry/close heights to work when the chain height is reset to zero. -func resetSwapForZeroHeight(swap v016bep3.AtomicSwap) v016bep3.AtomicSwap { - switch status := swap.Status; status { - case v016bep3.SWAP_STATUS_COMPLETED: - // Reset closed block to one so completed swaps are not held in long term storage too long. - swap.ClosedBlock = 1 - case v016bep3.SWAP_STATUS_OPEN: - switch dir := swap.Direction; dir { - case v016bep3.SWAP_DIRECTION_INCOMING: - // Open incoming swaps can be expired safely. They haven't been claimed yet, so the outgoing swap on bnb will just timeout. - // The chain downtime cannot be accurately predicted, so it's easier to expire than to recalculate a correct expire height. - swap.ExpireHeight = 1 - swap.Status = v016bep3.SWAP_STATUS_EXPIRED - case v016bep3.SWAP_DIRECTION_OUTGOING: - // Open outgoing swaps should be extended to allow enough time to claim after the chain launches. - // They cannot be expired as there could be an open/claimed bnb swap. - swap.ExpireHeight = 1 + 24686 // default timeout used when sending swaps from kava - case v016bep3.SWAP_DIRECTION_UNSPECIFIED: - default: - panic(fmt.Sprintf("unknown bep3 swap direction '%s'", dir)) - } - case v016bep3.SWAP_STATUS_EXPIRED: - // Once a swap is marked expired the expire height is ignored. However reset to 1 to be sure. - swap.ExpireHeight = 1 - case v016bep3.SWAP_STATUS_UNSPECIFIED: - default: - panic(fmt.Sprintf("unknown bep3 swap status '%s'", status)) - } - - return swap -} - -func migrateSupplies(oldSupplies v015bep3.AssetSupplies) v016bep3.AssetSupplies { - newSupplies := make(v016bep3.AssetSupplies, len(oldSupplies)) - for i, supply := range oldSupplies { - newSupplies[i] = v016bep3.AssetSupply{ - IncomingSupply: supply.IncomingSupply, - OutgoingSupply: supply.OutgoingSupply, - CurrentSupply: supply.CurrentSupply, - TimeLimitedCurrentSupply: supply.TimeLimitedCurrentSupply, - TimeElapsed: supply.TimeElapsed, - } - } - return newSupplies -} - -func Migrate(oldState v015bep3.GenesisState) *v016bep3.GenesisState { - return &v016bep3.GenesisState{ - PreviousBlockTime: oldState.PreviousBlockTime, - Params: migrateParams(oldState.Params), - AtomicSwaps: migrateAtomicSwaps(oldState.AtomicSwaps), - Supplies: migrateSupplies(oldState.Supplies), - } -} diff --git a/x/bep3/legacy/v0_16/migrate_test.go b/x/bep3/legacy/v0_16/migrate_test.go deleted file mode 100644 index a9551e14..00000000 --- a/x/bep3/legacy/v0_16/migrate_test.go +++ /dev/null @@ -1,275 +0,0 @@ -package v0_16 - -import ( - "io/ioutil" - "path/filepath" - "testing" - "time" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - "github.com/tendermint/tendermint/libs/bytes" - - app "github.com/kava-labs/kava/app" - v015bep3 "github.com/kava-labs/kava/x/bep3/legacy/v0_15" - v016bep3 "github.com/kava-labs/kava/x/bep3/types" -) - -type migrateTestSuite struct { - suite.Suite - - addresses []sdk.AccAddress - v15genstate v015bep3.GenesisState - cdc codec.Codec - legacyCdc *codec.LegacyAmino -} - -func (s *migrateTestSuite) SetupTest() { - app.SetSDKConfig() - - s.v15genstate = v015bep3.GenesisState{ - PreviousBlockTime: time.Date(2021, 4, 8, 15, 0, 0, 0, time.UTC), - Params: v015bep3.Params{}, - Supplies: v015bep3.AssetSupplies{}, - AtomicSwaps: v015bep3.AtomicSwaps{}, - } - - config := app.MakeEncodingConfig() - s.cdc = config.Marshaler - - legacyCodec := codec.NewLegacyAmino() - s.legacyCdc = legacyCodec - - _, accAddresses := app.GeneratePrivKeyAddressPairs(10) - s.addresses = accAddresses -} - -func (s *migrateTestSuite) TestMigrate_JSON() { - // Migrate v15 bep3 to v16 - file := filepath.Join("testdata", "v15-bep3.json") - data, err := ioutil.ReadFile(file) - s.Require().NoError(err) - err = s.legacyCdc.UnmarshalJSON(data, &s.v15genstate) - s.Require().NoError(err) - genstate := Migrate(s.v15genstate) - - // Compare expect v16 bep3 json with migrated json - actual := s.cdc.MustMarshalJSON(genstate) - file = filepath.Join("testdata", "v16-bep3.json") - expected, err := ioutil.ReadFile(file) - s.Require().NoError(err) - s.Require().JSONEq(string(expected), string(actual)) -} - -func (s *migrateTestSuite) TestMigrate_Swaps() { - type oldSwap struct { - ExpireHeight uint64 - CloseBlock int64 - Status v015bep3.SwapStatus - Direction v015bep3.SwapDirection - } - type newSwap struct { - ExpireHeight uint64 - CloseBlock int64 - Status v016bep3.SwapStatus - Direction v016bep3.SwapDirection - } - testcases := []struct { - name string - oldSwap oldSwap - newSwap newSwap - }{ - { - name: "invalid swap direction", - oldSwap: oldSwap{ - Direction: v015bep3.INVALID, - }, - newSwap: newSwap{ - Direction: v016bep3.SWAP_DIRECTION_UNSPECIFIED, - }, - }, - { - name: "invalid swap status", - oldSwap: oldSwap{ - Status: v015bep3.NULL, - }, - newSwap: newSwap{ - Status: v016bep3.SWAP_STATUS_UNSPECIFIED, - }, - }, - { - name: "incoming open swap", - oldSwap: oldSwap{ - // expire and close not set in open swaps - Status: v015bep3.Open, - Direction: v015bep3.Incoming, - }, - newSwap: newSwap{ - ExpireHeight: 1, - Status: v016bep3.SWAP_STATUS_EXPIRED, - Direction: v016bep3.SWAP_DIRECTION_INCOMING, - }, - }, - { - name: "outgoing open swap", - oldSwap: oldSwap{ - // expire and close not set in open swaps - Status: v015bep3.Open, - Direction: v015bep3.Outgoing, - }, - newSwap: newSwap{ - ExpireHeight: 24687, - Status: v016bep3.SWAP_STATUS_OPEN, - Direction: v016bep3.SWAP_DIRECTION_OUTGOING, - }, - }, - { - name: "completed swap", - oldSwap: oldSwap{ - ExpireHeight: 1000, - CloseBlock: 900, - Status: v015bep3.Completed, - Direction: v015bep3.Incoming, - }, - newSwap: newSwap{ - ExpireHeight: 1000, - CloseBlock: 1, - Status: v016bep3.SWAP_STATUS_COMPLETED, - Direction: v016bep3.SWAP_DIRECTION_INCOMING, - }, - }, - { - name: "expired swap", - oldSwap: oldSwap{ - ExpireHeight: 1000, - CloseBlock: 900, - Status: v015bep3.Expired, - Direction: v015bep3.Incoming, - }, - newSwap: newSwap{ - ExpireHeight: 1, - CloseBlock: 900, - Status: v016bep3.SWAP_STATUS_EXPIRED, - Direction: v016bep3.SWAP_DIRECTION_INCOMING, - }, - }, - } - - for _, tc := range testcases { - s.Run(tc.name, func() { - oldSwaps := v015bep3.AtomicSwaps{ - { - Amount: sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(12))), - RandomNumberHash: bytes.HexBytes{}, - ExpireHeight: tc.oldSwap.ExpireHeight, - Timestamp: 1110, - Sender: s.addresses[0], - Recipient: s.addresses[1], - RecipientOtherChain: s.addresses[0].String(), - SenderOtherChain: s.addresses[1].String(), - ClosedBlock: tc.oldSwap.CloseBlock, - Status: tc.oldSwap.Status, - CrossChain: true, - Direction: tc.oldSwap.Direction, - }, - } - expectedSwaps := v016bep3.AtomicSwaps{ - { - Amount: sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(12))), - RandomNumberHash: bytes.HexBytes{}, - ExpireHeight: tc.newSwap.ExpireHeight, - Timestamp: 1110, - Sender: s.addresses[0], - Recipient: s.addresses[1], - RecipientOtherChain: s.addresses[0].String(), - SenderOtherChain: s.addresses[1].String(), - ClosedBlock: tc.newSwap.CloseBlock, - Status: tc.newSwap.Status, - CrossChain: true, - Direction: tc.newSwap.Direction, - }, - } - s.v15genstate.AtomicSwaps = oldSwaps - genState := Migrate(s.v15genstate) - s.Require().Len(genState.AtomicSwaps, 1) - s.Equal(expectedSwaps, genState.AtomicSwaps) - }) - } -} - -func (s *migrateTestSuite) TestMigrate_Params() { - params := v015bep3.AssetParams{ - { - Denom: "bnb", - CoinID: int(714), - SupplyLimit: v015bep3.SupplyLimit{ - Limit: sdk.NewInt(350000000000000), - TimeLimited: false, - TimeBasedLimit: sdk.ZeroInt(), - TimePeriod: time.Hour, - }, - Active: true, - DeputyAddress: s.addresses[0], - FixedFee: sdk.NewInt(1000), - MinSwapAmount: sdk.OneInt(), - MaxSwapAmount: sdk.NewInt(1000000000000), - MinBlockLock: 220, - MaxBlockLock: 770, - }, - } - expectedParams := v016bep3.AssetParams{ - { - Denom: "bnb", - CoinID: int64(714), - SupplyLimit: v016bep3.SupplyLimit{ - Limit: sdk.NewInt(350000000000000), - TimeLimited: false, - TimeBasedLimit: sdk.ZeroInt(), - TimePeriod: time.Hour, - }, - Active: true, - DeputyAddress: s.addresses[0], - FixedFee: sdk.NewInt(1000), - MinSwapAmount: sdk.OneInt(), - MaxSwapAmount: sdk.NewInt(1000000000000), - MinBlockLock: 220, - MaxBlockLock: 770, - }, - } - - s.v15genstate.Params = v015bep3.Params{AssetParams: params} - genState := Migrate(s.v15genstate) - s.Require().Len(genState.Params.AssetParams, 1) - s.Require().Equal(v016bep3.Params{AssetParams: expectedParams}, genState.Params) -} - -func (s *migrateTestSuite) TestMigrate_Supplies() { - supplies := v015bep3.AssetSupplies{ - { - IncomingSupply: sdk.NewInt64Coin("bnb", 1000), - OutgoingSupply: sdk.NewInt64Coin("bnb", 1001), - CurrentSupply: sdk.NewInt64Coin("bnb", 1002), - TimeLimitedCurrentSupply: sdk.NewInt64Coin("bnb", 1003), - TimeElapsed: time.Hour, - }, - } - expectedSupplies := v016bep3.AssetSupplies{ - { - IncomingSupply: sdk.NewInt64Coin("bnb", 1000), - OutgoingSupply: sdk.NewInt64Coin("bnb", 1001), - CurrentSupply: sdk.NewInt64Coin("bnb", 1002), - TimeLimitedCurrentSupply: sdk.NewInt64Coin("bnb", 1003), - TimeElapsed: time.Hour, - }, - } - - s.v15genstate.Supplies = supplies - genState := Migrate(s.v15genstate) - s.Require().Len(genState.Supplies, 1) - s.Require().Equal(expectedSupplies, genState.Supplies) -} - -func TestMigrateTestSuite(t *testing.T) { - suite.Run(t, new(migrateTestSuite)) -} diff --git a/x/bep3/legacy/v0_17/migrate.go b/x/bep3/legacy/v0_17/migrate.go new file mode 100644 index 00000000..e830b7dd --- /dev/null +++ b/x/bep3/legacy/v0_17/migrate.go @@ -0,0 +1,57 @@ +package v0_16 + +import ( + "fmt" + + "github.com/kava-labs/kava/x/bep3/types" +) + +// resetSwapForZeroHeight updates swap expiry/close heights to work when the chain height is reset to zero. +func resetSwapForZeroHeight(swap types.AtomicSwap) types.AtomicSwap { + switch status := swap.Status; status { + case types.SWAP_STATUS_COMPLETED: + // Reset closed block to one so completed swaps are not held in long term storage too long. + swap.ClosedBlock = 1 + case types.SWAP_STATUS_OPEN: + switch dir := swap.Direction; dir { + case types.SWAP_DIRECTION_INCOMING: + // Open incoming swaps can be expired safely. They haven't been claimed yet, so the outgoing swap on bnb will just timeout. + // The chain downtime cannot be accurately predicted, so it's easier to expire than to recalculate a correct expire height. + swap.ExpireHeight = 1 + swap.Status = types.SWAP_STATUS_EXPIRED + case types.SWAP_DIRECTION_OUTGOING: + // Open outgoing swaps should be extended to allow enough time to claim after the chain launches. + // They cannot be expired as there could be an open/claimed bnb swap. + swap.ExpireHeight = 1 + 24686 // default timeout used when sending swaps from kava + case types.SWAP_DIRECTION_UNSPECIFIED: + default: + panic(fmt.Sprintf("unknown bep3 swap direction '%s'", dir)) + } + case types.SWAP_STATUS_EXPIRED: + // Once a swap is marked expired the expire height is ignored. However reset to 1 to be sure. + swap.ExpireHeight = 1 + case types.SWAP_STATUS_UNSPECIFIED: + default: + panic(fmt.Sprintf("unknown bep3 swap status '%s'", status)) + } + + return swap +} + +func resetSwapsForZeroHeight(oldSwaps types.AtomicSwaps) types.AtomicSwaps { + newSwaps := make(types.AtomicSwaps, len(oldSwaps)) + for i, oldSwap := range oldSwaps { + swap := resetSwapForZeroHeight(oldSwap) + newSwaps[i] = swap + } + return newSwaps +} + +func Migrate(oldState types.GenesisState) *types.GenesisState { + return &types.GenesisState{ + PreviousBlockTime: oldState.PreviousBlockTime, + Params: oldState.Params, + AtomicSwaps: resetSwapsForZeroHeight(oldState.AtomicSwaps), + Supplies: oldState.Supplies, + } +} diff --git a/x/bep3/legacy/v0_17/migrate_test.go b/x/bep3/legacy/v0_17/migrate_test.go new file mode 100644 index 00000000..790fec7c --- /dev/null +++ b/x/bep3/legacy/v0_17/migrate_test.go @@ -0,0 +1,174 @@ +package v0_16 + +import ( + "io/ioutil" + "path/filepath" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/libs/bytes" + + app "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/bep3/types" +) + +type migrateTestSuite struct { + suite.Suite + + addresses []sdk.AccAddress + v16genstate types.GenesisState + cdc codec.Codec +} + +func (s *migrateTestSuite) SetupTest() { + app.SetSDKConfig() + + s.v16genstate = types.GenesisState{ + PreviousBlockTime: time.Date(2021, 4, 8, 15, 0, 0, 0, time.UTC), + Params: types.Params{}, + Supplies: types.AssetSupplies{}, + AtomicSwaps: types.AtomicSwaps{}, + } + + config := app.MakeEncodingConfig() + s.cdc = config.Marshaler + + _, accAddresses := app.GeneratePrivKeyAddressPairs(10) + s.addresses = accAddresses +} + +func (s *migrateTestSuite) TestMigrate_JSON() { + // Migrate v16 bep3 to v17 + file := filepath.Join("testdata", "v16-bep3.json") + data, err := ioutil.ReadFile(file) + s.Require().NoError(err) + err = s.cdc.UnmarshalJSON(data, &s.v16genstate) + s.Require().NoError(err) + genstate := Migrate(s.v16genstate) + + // Compare expect v16 bep3 json with migrated json + actual := s.cdc.MustMarshalJSON(genstate) + file = filepath.Join("testdata", "v17-bep3.json") + expected, err := ioutil.ReadFile(file) + s.Require().NoError(err) + s.Require().JSONEq(string(expected), string(actual)) +} + +func (s *migrateTestSuite) TestMigrate_Swaps() { + type swap struct { + ExpireHeight uint64 + CloseBlock int64 + Status types.SwapStatus + Direction types.SwapDirection + } + testcases := []struct { + name string + oldSwap swap + newSwap swap + }{ + { + name: "incoming open swap", + oldSwap: swap{ + // expire and close not set in open swaps + Status: types.SWAP_STATUS_OPEN, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + newSwap: swap{ + ExpireHeight: 1, + Status: types.SWAP_STATUS_EXPIRED, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + }, + { + name: "outgoing open swap", + oldSwap: swap{ + // expire and close not set in open swaps + Status: types.SWAP_STATUS_OPEN, + Direction: types.SWAP_DIRECTION_OUTGOING, + }, + newSwap: swap{ + ExpireHeight: 24687, + Status: types.SWAP_STATUS_OPEN, + Direction: types.SWAP_DIRECTION_OUTGOING, + }, + }, + { + name: "completed swap", + oldSwap: swap{ + ExpireHeight: 1000, + CloseBlock: 900, + Status: types.SWAP_STATUS_COMPLETED, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + newSwap: swap{ + ExpireHeight: 1000, + CloseBlock: 1, + Status: types.SWAP_STATUS_COMPLETED, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + }, + { + name: "expired swap", + oldSwap: swap{ + ExpireHeight: 1000, + CloseBlock: 900, + Status: types.SWAP_STATUS_EXPIRED, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + newSwap: swap{ + ExpireHeight: 1, + CloseBlock: 900, + Status: types.SWAP_STATUS_EXPIRED, + Direction: types.SWAP_DIRECTION_INCOMING, + }, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + oldSwaps := types.AtomicSwaps{ + { + Amount: sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(12))), + RandomNumberHash: bytes.HexBytes{}, + ExpireHeight: tc.oldSwap.ExpireHeight, + Timestamp: 1110, + Sender: s.addresses[0], + Recipient: s.addresses[1], + RecipientOtherChain: s.addresses[0].String(), + SenderOtherChain: s.addresses[1].String(), + ClosedBlock: tc.oldSwap.CloseBlock, + Status: tc.oldSwap.Status, + CrossChain: true, + Direction: tc.oldSwap.Direction, + }, + } + expectedSwaps := types.AtomicSwaps{ + { + Amount: sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(12))), + RandomNumberHash: bytes.HexBytes{}, + ExpireHeight: tc.newSwap.ExpireHeight, + Timestamp: 1110, + Sender: s.addresses[0], + Recipient: s.addresses[1], + RecipientOtherChain: s.addresses[0].String(), + SenderOtherChain: s.addresses[1].String(), + ClosedBlock: tc.newSwap.CloseBlock, + Status: tc.newSwap.Status, + CrossChain: true, + Direction: tc.newSwap.Direction, + }, + } + s.v16genstate.AtomicSwaps = oldSwaps + genState := Migrate(s.v16genstate) + s.Require().Len(genState.AtomicSwaps, 1) + s.Equal(expectedSwaps, genState.AtomicSwaps) + }) + } +} + +func TestMigrateTestSuite(t *testing.T) { + suite.Run(t, new(migrateTestSuite)) +} diff --git a/x/bep3/legacy/v0_16/testdata/v15-bep3.json b/x/bep3/legacy/v0_17/testdata/v16-bep3.json similarity index 90% rename from x/bep3/legacy/v0_16/testdata/v15-bep3.json rename to x/bep3/legacy/v0_17/testdata/v16-bep3.json index 993df30e..1e040204 100644 --- a/x/bep3/legacy/v0_16/testdata/v15-bep3.json +++ b/x/bep3/legacy/v0_17/testdata/v16-bep3.json @@ -9,14 +9,14 @@ ], "closed_block": "838115", "cross_chain": true, - "direction": "Incoming", + "direction": "SWAP_DIRECTION_INCOMING", "expire_height": "838627", "random_number_hash": "6F1CF8F2E13A0C0F0A359F54E47E4E265D766B8E006D2F00BDF994ABDEF1E9E4", "recipient": "kava1fl2hs6y9vz986g5v52pdan9ga923n9mn5cxxkw", "recipient_other_chain": "bnb1xz3xqf4p2ygrw9lhp5g5df4ep4nd20vsywnmpr", "sender": "kava14qsmvzprqvhwmgql9fr0u3zv9n2qla8zhnm5pc", "sender_other_chain": "bnb19k9wuv2j7c7ck8tmc7kav0r0cnt3esmkrpf25x", - "status": "Completed", + "status": "SWAP_STATUS_COMPLETED", "timestamp": "1636034914" }, { @@ -28,14 +28,14 @@ ], "closed_block": "1712118", "cross_chain": true, - "direction": "Outgoing", + "direction": "SWAP_DIRECTION_OUTGOING", "expire_height": "1736797", "random_number_hash": "280EB832A37F2265CC82F3957CE603AAD57BAD7038B876A1F28953AFA29FA1C3", "recipient": "kava1r4v2zdhdalfj2ydazallqvrus9fkphmglhn6u6", "recipient_other_chain": "bnb18nsgj50zvc4uq93w4j0ltz5gaxhwv7aq4qnq0p", "sender": "kava1zw6gg4ztvly7zf25pa33mclav3spvj3ympxxna", "sender_other_chain": "bnb1jh7uv2rm6339yue8k4mj9406k3509kr4wt5nxn", - "status": "Completed", + "status": "SWAP_STATUS_COMPLETED", "timestamp": "1641976566" }, { @@ -47,14 +47,14 @@ ], "closed_block": "787122", "cross_chain": true, - "direction": "Incoming", + "direction": "SWAP_DIRECTION_INCOMING", "expire_height": "811799", "random_number_hash": "BFB7CC82DA0E0C8556AC37843F5AB136B9A7A066054368F5948944282B414D83", "recipient": "kava1eufgf0w9d7hf5mgtek4zr2upkxag9stmzx6unl", "recipient_other_chain": "bnb10zq89008gmedc6rrwzdfukjk94swynd7dl97w8", "sender": "kava1hh4x3a4suu5zyaeauvmv7ypf7w9llwlfufjmuu", "sender_other_chain": "bnb1vl3wn4x8kqajg2j9wxa5y5amgzdxchutkxr6at", - "status": "Expired", + "status": "SWAP_STATUS_EXPIRED", "timestamp": "1635694492" }, { @@ -66,14 +66,14 @@ ], "closed_block": "787122", "cross_chain": true, - "direction": "Outgoing", + "direction": "SWAP_DIRECTION_OUTGOING", "expire_height": "811799", "random_number_hash": "BFB7CC82DA0E0C8556AC37843F5AB136B9A7A066054368F5948944282B414D83", "recipient": "kava1hh4x3a4suu5zyaeauvmv7ypf7w9llwlfufjmuu", "recipient_other_chain": "bnb1vl3wn4x8kqajg2j9wxa5y5amgzdxchutkxr6at", "sender": "kava1eufgf0w9d7hf5mgtek4zr2upkxag9stmzx6unl", "sender_other_chain": "bnb10zq89008gmedc6rrwzdfukjk94swynd7dl97w8", - "status": "Expired", + "status": "SWAP_STATUS_EXPIRED", "timestamp": "1635694492" }, { @@ -85,14 +85,14 @@ ], "closed_block": "0", "cross_chain": true, - "direction": "Outgoing", + "direction": "SWAP_DIRECTION_OUTGOING", "expire_height": "1730589", "random_number_hash": "A74EA1AB58D312FDF1E872D18583CACCF294E639DDA4F303939E9ADCEC081D93", "recipient": "kava14qsmvzprqvhwmgql9fr0u3zv9n2qla8zhnm5pc", "recipient_other_chain": "bnb1lhk5ndlgf5wz55t8k35cqj6h9l3m4l5ek2w7q6", "sender": "kava1d2u28azje7rhqyjtxc2ex8q0cxxpw7dfm7ltq5", "sender_other_chain": "bnb1xz3xqf4p2ygrw9lhp5g5df4ep4nd20vsywnmpr", - "status": "Open", + "status": "SWAP_STATUS_OPEN", "timestamp": "1641934114" }, { @@ -104,14 +104,14 @@ ], "closed_block": "0", "cross_chain": true, - "direction": "Incoming", + "direction": "SWAP_DIRECTION_INCOMING", "expire_height": "1740000", "random_number_hash": "39E9ADCEC081D93A74EA1A83CACCF294E639DDA4F3039B58D312FDF1E872D185", "recipient": "kava1d2u28azje7rhqyjtxc2ex8q0cxxpw7dfm7ltq5", "recipient_other_chain": "bnb1xz3xqf4p2ygrw9lhp5g5df4ep4nd20vsywnmpr", "sender": "kava14qsmvzprqvhwmgql9fr0u3zv9n2qla8zhnm5pc", "sender_other_chain": "bnb1lhk5ndlgf5wz55t8k35cqj6h9l3m4l5ek2w7q6", - "status": "Open", + "status": "SWAP_STATUS_OPEN", "timestamp": "1641934114" } ], @@ -131,7 +131,7 @@ "limit": "100000000000", "time_based_limit": "0", "time_limited": false, - "time_period": "0" + "time_period": "0s" } }, { @@ -148,7 +148,7 @@ "limit": "2000000000000000", "time_based_limit": "0", "time_limited": false, - "time_period": "0" + "time_period": "0s" } }, { @@ -165,7 +165,7 @@ "limit": "100000000000000", "time_based_limit": "0", "time_limited": false, - "time_period": "0" + "time_period": "0s" } }, { @@ -182,7 +182,7 @@ "limit": "2000000000000000", "time_based_limit": "0", "time_limited": false, - "time_period": "0" + "time_period": "0s" } } ] @@ -202,7 +202,7 @@ "amount": "0", "denom": "bnb" }, - "time_elapsed": "0", + "time_elapsed": "0s", "time_limited_current_supply": { "amount": "0", "denom": "bnb" diff --git a/x/bep3/legacy/v0_16/testdata/v16-bep3.json b/x/bep3/legacy/v0_17/testdata/v17-bep3.json similarity index 100% rename from x/bep3/legacy/v0_16/testdata/v16-bep3.json rename to x/bep3/legacy/v0_17/testdata/v17-bep3.json