Skip to content

Commit

Permalink
chore: review feedback improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanchriswhite committed Jan 31, 2025
1 parent 46c87be commit 178ded8
Show file tree
Hide file tree
Showing 9 changed files with 1,032 additions and 693 deletions.
842 changes: 433 additions & 409 deletions api/poktroll/migration/legacy.pulsar.go

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions cmd/poktrolld/cmd/migrate/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package migrate

import sdkerrors "cosmossdk.io/errors"

const codespace = "poktrolld/migrate"

var (
// ErrInvalidUsage usage is returned when the CLI arguments are invalid.
ErrInvalidUsage = sdkerrors.Register(codespace, 1100, "invalid usage")
// ErrMorseExportState is returned with the JSON generated from `pocket util export-genesis-for-reset` is invalid.
ErrMorseExportState = sdkerrors.Register(codespace, 1101, "morse export state")
// ErrMorseStateTransform is returned upon general failure when transforming the MorseExportState into the MorseAccountState.
ErrMorseStateTransform = sdkerrors.Register(codespace, 1102, "morse state transform")
)
205 changes: 153 additions & 52 deletions cmd/poktrolld/cmd/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,124 @@ package migrate

import (
"fmt"
"io"
"os"

cosmosmath "cosmossdk.io/math"
cmtjson "github.com/cometbft/cometbft/libs/json"
"github.com/spf13/cobra"

"github.com/pokt-network/poktroll/app/volatile"
"github.com/pokt-network/poktroll/pkg/polylog"
"github.com/pokt-network/poktroll/pkg/polylog/polyzero"
migrationtypes "github.com/pokt-network/poktroll/x/migration/types"
)

var collectMorseAccountsCmd = &cobra.Command{
Use: "collect-morse-accounts [morse-state-path] [morse-accounts-path]",
Args: cobra.ExactArgs(2),
Short: "Collect all account balances and corresponding stakes from the JSON file at [morse-state-path] and outputs them as JSON to [morse-accounts-path]",
Long: `Collects the account balances and corresponding stakes from the MorseStateExport JSON file at morse-state-path
var (
flagDebugAccountsPerLog int
flagLogLevel string
flagLogOutput string
logger polylog.Logger

collectMorseAccountsCmd = &cobra.Command{
Use: "collect-morse-accounts [morse-state-export-path] [morse-account-state-path]",
Args: cobra.ExactArgs(2),
Short: "Collect all account balances and corresponding stakes from the JSON file at [morse-state-export-path] and outputs them as JSON to [morse-account-state-path]",
Long: `Collects the account balances and corresponding stakes from the MorseStateExport JSON file at morse-state-path
and outputs them as a MorseAccountState JSON to morse-accounts-path for use with
Shannon's MsgUploadMorseState. The Morse state export is generated via the Morse CLI:
pocket util export-genesis-for-reset [height] [new-chain-id] > morse-state-export.json`,
RunE: runCollectMorseAccounts,
}
PreRunE: func(cmd *cobra.Command, args []string) error {
var (
logOutput io.Writer
err error
)
logLevel := polyzero.ParseLevel(flagLogLevel)
if flagLogOutput == "-" {
logOutput = os.Stderr
} else {
logOutput, err = os.Open(flagLogOutput)
if err != nil {
return err
}
}

logger = polyzero.NewLogger(
polyzero.WithLevel(logLevel),
polyzero.WithOutput(logOutput),
).With("cmd", "migrate")
return nil
},
RunE: runCollectMorseAccounts,
}
)

func MigrateCmd() *cobra.Command {
cmd := &cobra.Command{
migrateCmd := &cobra.Command{
Use: "migrate",
Short: "Migration commands",
}
cmd.AddCommand(collectMorseAccountsCmd)
migrateCmd.AddCommand(collectMorseAccountsCmd)
migrateCmd.PersistentFlags().StringVar(&flagLogLevel, "log-level", "info", "The logging level (debug|info|warn|error)")
migrateCmd.PersistentFlags().StringVar(&flagLogOutput, "log-output", "-", "The logging output (file path); defaults to stdout")

collectMorseAccountsCmd.Flags().IntVar(&flagDebugAccountsPerLog, "debug-accounts-per-log", 0, "The number of accounts to log per debug message")

return cmd
return migrateCmd
}

// runCollectedMorseAccounts is run by the `poktrolld migrate collect-morse-accounts` command.
func runCollectMorseAccounts(cmd *cobra.Command, args []string) error {
inputPath := args[0]
outputPath := args[1]
func runCollectMorseAccounts(_ *cobra.Command, args []string) error {
// DEV_NOTE: No need to check args length due to cobra.ExactArgs(2).
morseStateExportPath := args[0]
morseAccountStatePath := args[1]

return collectMorseAccounts(inputPath, outputPath)
}
logger.Info().
Str("morse_state_export_path", morseStateExportPath).
Str("morse_account_state_path", morseAccountStatePath).
Msg("collecting Morse accounts...")

// collectMorseAccounts transforms the JSON serialized MorseStateExport at
// inputStatePath into a JSON serialized MorseAccountState at outputStatePath.
func collectMorseAccounts(inputStatePath, outputStatePath string) error {
if err := validatePathIsFile(inputStatePath); err != nil {
morseWorkspace, err := collectMorseAccounts(morseStateExportPath, morseAccountStatePath)
if err != nil {
return err
}

inputStateJSON, err := os.ReadFile(inputStatePath)
return morseWorkspace.infoLogComplete()
}

// collectMorseAccounts reads and transforms the JSON serialized MorseStateExport
// at morseStateExportPath into a JSON serialized MorseAccountState, and then writes
// it to morseAccountStatePath.
func collectMorseAccounts(morseStateExportPath, morseAccountStatePath string) (*morseImportWorkspace, error) {
if err := validatePathIsFile(morseStateExportPath); err != nil {
return nil, err
}

inputStateJSON, err := os.ReadFile(morseStateExportPath)
if err != nil {
return err
return nil, err
}

inputState := new(migrationtypes.MorseStateExport)
if err = cmtjson.Unmarshal(inputStateJSON, inputState); err != nil {
return err
return nil, err
}

morseWorkspace := newMorseImportWorkspace()
if err := transformMorseState(inputState, morseWorkspace); err != nil {

Check failure on line 109 in cmd/poktrolld/cmd/migrate/migrate.go

View workflow job for this annotation

GitHub Actions / go-test

shadow: declaration of "err" shadows declaration at line 98 (govet)
return nil, err
}

outputStateJSON, err := transformMorseState(inputState)
outputStateJSONBz, err := cmtjson.Marshal(morseWorkspace.accountState)
if err != nil {
return err
return nil, err
}

if err = os.WriteFile(outputStatePath, outputStateJSON, 0644); err != nil {
return err
if err = os.WriteFile(morseAccountStatePath, outputStateJSONBz, 0644); err != nil {
return nil, err
}

return nil
return morseWorkspace, nil
}

// validatePathIsFile returns an error if the given path does not exist or is not a file.
Expand All @@ -78,70 +130,115 @@ func validatePathIsFile(path string) error {
}

if info.IsDir() {
return fmt.Errorf("[morse-JSON-input-path] cannot be a directory")
return ErrInvalidUsage.Wrapf("[morse-JSON-input-path] cannot be a directory: %s", path)
}

return nil
}

// transformMorseState consolidates the Morse account balance, application stake,
// and supplier stake for each account as an entry in the resulting MorseAccountState.
func transformMorseState(inputState *migrationtypes.MorseStateExport) ([]byte, error) {
morseWorkspace := &morseImportWorkspace{
addressToIdx: make(map[string]uint64),
accounts: make([]*migrationtypes.MorseAccount, 0),
}

func transformMorseState(
inputState *migrationtypes.MorseStateExport,
morseWorkspace *morseImportWorkspace,
) error {
// Iterate over accounts and copy the balances.
logger.Info().Msg("collecting account balances...")
if err := collectInputAccountBalances(inputState, morseWorkspace); err != nil {
return nil, err
return err
}

// Iterate over applications and add the stakes to the corresponding account balances.
logger.Info().Msg("collecting application stakes...")
if err := collectInputApplicationStakes(inputState, morseWorkspace); err != nil {
return nil, err
return err
}

// Iterate over suppliers and add the stakes to the corresponding account balances.
logger.Info().Msg("collecting supplier stakes...")
err := collectInputSupplierStakes(inputState, morseWorkspace)
if err != nil {
return nil, err
return err
}

morseAccountState := &migrationtypes.MorseAccountState{Accounts: morseWorkspace.accounts}
return cmtjson.Marshal(morseAccountState)
morseWorkspace.accountState = &migrationtypes.MorseAccountState{Accounts: morseWorkspace.accounts}
return nil
}

// collectInputAccountBalances iterates over the accounts in the inputState and
// adds the balances to the corresponding account balances in the morseWorkspace.
func collectInputAccountBalances(inputState *migrationtypes.MorseStateExport, morseWorkspace *morseImportWorkspace) error {
for _, exportAccount := range inputState.AppState.Auth.Accounts {
for exportAccountIdx, exportAccount := range inputState.AppState.Auth.Accounts {
if shouldDebugLogProgress(exportAccountIdx) {
morseWorkspace.debugLogProgress(exportAccountIdx)
}

// DEV_NOTE: Ignore module accounts.
if exportAccount.Type != "posmint/Account" {
logger.Warn().
Str("type", exportAccount.Type).
Str("address", exportAccount.Value.Address.String()).
Str("coins", fmt.Sprintf("%s", exportAccount.Value.Coins)).
Msg("ignoring non-EOA account")
continue
}

addr := exportAccount.Value.Address.String()
morseWorkspace.ensureAccount(addr, exportAccount)
if _, _, err := morseWorkspace.ensureAccount(addr, exportAccount); err != nil {
return err
}

coins := exportAccount.Value.Coins
if len(coins) == 0 {
return nil
}

// DEV_NOTE: SHOULD ONLY be one denom (upokt).
if len(coins) != 1 {
return ErrMorseExportState.Wrapf(
"account %q has %d token denominations, expected upokt only: %s",
addr, len(coins), coins,
)
}

coin := coins[0]
if coin.Denom != volatile.DenomuPOKT {
return fmt.Errorf("unsupported denom %q", coin.Denom)
return ErrMorseExportState.Wrapf("unsupported denom %q", coin.Denom)
}

if err := morseWorkspace.addUpokt(addr, coin.Amount); err != nil {
return err
return fmt.Errorf(
"adding morse account balance (%s) to account balance of address %q: %w",
coin, addr, err,
)
}
}
return nil
}

// shouldDebugLogProgress returns true if the given exportAccountIdx should be logged
// via debugLogProgress.
func shouldDebugLogProgress(exportAccountIdx int) bool {
return flagDebugAccountsPerLog > 0 &&
exportAccountIdx%flagDebugAccountsPerLog == 0
}

// debugLogProgress logs the total balances, app stakes, and supplier stakes of
// all accounts that have been processed.
func debugLogProgress(exportAccountIdx int, morseWorkspace *morseImportWorkspace) {

Check failure on line 227 in cmd/poktrolld/cmd/migrate/migrate.go

View workflow job for this annotation

GitHub Actions / go-test

func `debugLogProgress` is unused (unused)
totalBalance := morseWorkspace.totalBalance()
totalAppStake := morseWorkspace.totalAppStake()
totalSupplierStake := morseWorkspace.totalSupplierStake()
grandTotal := totalBalance.Add(totalAppStake).Add(totalSupplierStake)

logger.Debug().
Int("account_idx", exportAccountIdx).
Str("total_balance", totalBalance.String()).
Str("total_app_stake", totalAppStake.String()).
Str("total_supplier_stake", totalSupplierStake.String()).
Str("grand_total", grandTotal.String()).
Msg("processing accounts...")
}

// collectInputApplicationStakes iterates over the applications in the inputState and
// adds the stake to the corresponding account balances in the morseWorkspace.
func collectInputApplicationStakes(inputState *migrationtypes.MorseStateExport, morseWorkspace *morseImportWorkspace) error {
Expand All @@ -150,17 +247,19 @@ func collectInputApplicationStakes(inputState *migrationtypes.MorseStateExport,

// DEV_NOTE: An account SHOULD exist for each actor.
if !morseWorkspace.hasAccount(addr) {
// TODO_IN_THIS_COMMIT: consolidate error types...
return fmt.Errorf("account %q not found", addr)
return ErrMorseExportState.Wrapf("account not found corresponding to application with address %q", addr)
}

appStakeAmtUpokt, ok := cosmosmath.NewIntFromString(exportApplication.StakedTokens)
if !ok {
return fmt.Errorf("failed to parse application stake amount %q", exportApplication.StakedTokens)
return ErrMorseExportState.Wrapf("failed to parse application stake amount %q", exportApplication.StakedTokens)
}

if err := morseWorkspace.addUpokt(addr, appStakeAmtUpokt); err != nil {
return err
return fmt.Errorf(
"adding application stake amount to account balance of address %q: %w",
addr, err,
)
}
}
return nil
Expand All @@ -174,17 +273,19 @@ func collectInputSupplierStakes(inputState *migrationtypes.MorseStateExport, mor

// DEV_NOTE: An account SHOULD exist for each actor.
if !morseWorkspace.hasAccount(addr) {
// TODO_IN_THIS_COMMIT: consolidate error types...
return fmt.Errorf("account %q not found", addr)
return ErrMorseExportState.Wrapf("account not found corresponding to supplier with address %q", addr)
}

supplierStakeAmtUpokt, ok := cosmosmath.NewIntFromString(exportSupplier.StakedTokens)
if !ok {
return fmt.Errorf("failed to parse supplier stake amount %q", exportSupplier.StakedTokens)
return ErrMorseExportState.Wrapf("failed to parse supplier stake amount %q", exportSupplier.StakedTokens)
}

if err := morseWorkspace.addUpokt(addr, supplierStakeAmtUpokt); err != nil {
return err
return fmt.Errorf(
"adding supplier stake amount to account balance of address %q: %w",
addr, err,
)
}
}
return nil
Expand Down
Loading

0 comments on commit 178ded8

Please sign in to comment.