cosmos-sdk/x/genutil/migration/v052/migrate.go
son trinh 4aeb053925
refactor(genutil): Use sdk types genesis validator (#21678)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Matt Kocubinski <mkocubinski@gmail.com>
2024-10-09 05:18:05 +00:00

174 lines
4.7 KiB
Go

package migrate
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"time"
cmtjson "github.com/cometbft/cometbft/libs/json"
cmttypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/client"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
)
type legacyAppGenesis struct {
AppName string `json:"app_name"`
AppVersion string `json:"app_version"`
GenesisTime time.Time `json:"genesis_time"`
ChainID string `json:"chain_id"`
InitialHeight int64 `json:"initial_height"`
AppHash []byte `json:"app_hash"`
AppState json.RawMessage `json:"app_state,omitempty"`
Consensus *legacyConsensusGenesis `json:"consensus,omitempty"`
}
type legacyConsensusGenesis struct {
Validators []cmttypes.GenesisValidator `json:"validators,omitempty"`
Params *cmttypes.ConsensusParams `json:"params,omitempty"`
}
func MigrateGenesisFile(oldGenFile string) (*types.AppGenesis, error) {
file, err := os.Open(filepath.Clean(oldGenFile))
if err != nil {
return nil, err
}
defer file.Close()
appGenesis, err := migrateGenesisValidator(file)
if err != nil {
return nil, fmt.Errorf("failed to read genesis from file %s: %w", oldGenFile, err)
}
return appGenesis, nil
}
// migrateGenesisValidator migrate current genesis file genesis validator to match of the
// new genesis validator type.
func migrateGenesisValidator(r io.Reader) (*types.AppGenesis, error) {
var newAg types.AppGenesis
var ag legacyAppGenesis
var err error
if rs, ok := r.(io.ReadSeeker); ok {
err = json.NewDecoder(rs).Decode(&ag)
if err == nil {
vals, err := convertValidators(ag.Consensus.Validators)
if err != nil {
return nil, err
}
newAg = types.AppGenesis{
AppName: ag.AppName,
AppVersion: ag.AppVersion,
GenesisTime: ag.GenesisTime,
ChainID: ag.ChainID,
InitialHeight: ag.InitialHeight,
AppHash: ag.AppHash,
AppState: ag.AppState,
Consensus: &types.ConsensusGenesis{
Validators: vals,
Params: ag.Consensus.Params,
},
}
return &newAg, nil
}
err = fmt.Errorf("error unmarshalling legacy AppGenesis: %w", err)
if _, serr := rs.Seek(0, io.SeekStart); serr != nil {
err = errors.Join(err, fmt.Errorf("error seeking back to the front: %w", serr))
return nil, err
}
}
jsonBlob, ioerr := io.ReadAll(r)
if ioerr != nil {
err = errors.Join(err, fmt.Errorf("failed to read file completely: %w", ioerr))
return nil, err
}
// fallback to comet genesis parsing
var ctmGenesis cmttypes.GenesisDoc
if uerr := cmtjson.Unmarshal(jsonBlob, &ctmGenesis); uerr != nil {
err = errors.Join(err, fmt.Errorf("failed fallback to CometBFT GenDoc: %w", uerr))
return nil, err
}
vals, err := convertValidators(ctmGenesis.Validators)
if err != nil {
return nil, err
}
newAg = types.AppGenesis{
AppName: version.AppName,
GenesisTime: ctmGenesis.GenesisTime,
ChainID: ctmGenesis.ChainID,
InitialHeight: ctmGenesis.InitialHeight,
AppHash: ctmGenesis.AppHash,
AppState: ctmGenesis.AppState,
Consensus: &types.ConsensusGenesis{
Validators: vals,
Params: ctmGenesis.ConsensusParams,
},
}
return &newAg, nil
}
func convertValidators(cmtVals []cmttypes.GenesisValidator) ([]sdk.GenesisValidator, error) {
vals := make([]sdk.GenesisValidator, len(cmtVals))
for i, cmtVal := range cmtVals {
pk, err := cryptocodec.FromCmtPubKeyInterface(cmtVal.PubKey)
if err != nil {
return nil, err
}
jsonPk, err := cryptocodec.PubKeyFromProto(pk)
if err != nil {
return nil, err
}
vals[i] = sdk.GenesisValidator{
Address: cmtVal.Address.Bytes(),
PubKey: jsonPk,
Power: cmtVal.Power,
Name: cmtVal.Name,
}
}
return vals, nil
}
// CometBFT Genesis Handling for JSON,
// this is necessary for json unmarshaling of legacyConsensusGenesis
func (cs *legacyConsensusGenesis) MarshalJSON() ([]byte, error) {
type Alias legacyConsensusGenesis
return cmtjson.Marshal(&Alias{
Validators: cs.Validators,
Params: cs.Params,
})
}
func (cs *legacyConsensusGenesis) UnmarshalJSON(b []byte) error {
type Alias legacyConsensusGenesis
result := Alias{}
if err := cmtjson.Unmarshal(b, &result); err != nil {
return err
}
cs.Params = result.Params
cs.Validators = result.Validators
return nil
}
// since we only need migrate the consensus validators content so there is no
// exported state migration.
func Migrate(appState types.AppMap, _ client.Context) (types.AppMap, error) {
return appState, nil
}