Skip to content

Commit

Permalink
wrap collect-gentxs
Browse files Browse the repository at this point in the history
  • Loading branch information
anhductn2001 committed Apr 23, 2024
1 parent 200895e commit 5ae9dc3
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 1 deletion.
284 changes: 284 additions & 0 deletions cmd/rollappd/cmd/collect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism
"sort"
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
cfg "github.com/tendermint/tendermint/config"
)

const flagGenTxDir = "gentx-dir"

type printInfo struct {
Moniker string `json:"moniker" yaml:"moniker"`
ChainID string `json:"chain_id" yaml:"chain_id"`
NodeID string `json:"node_id" yaml:"node_id"`
GenTxsDir string `json:"gentxs_dir" yaml:"gentxs_dir"`
AppMessage json.RawMessage `json:"app_message" yaml:"app_message"`
}

func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, appMessage json.RawMessage) printInfo {
return printInfo{
Moniker: moniker,
ChainID: chainID,
NodeID: nodeID,
GenTxsDir: genTxsDir,
AppMessage: appMessage,
}
}

func displayInfo(info printInfo) error {
out, err := json.MarshalIndent(info, "", " ")
if err != nil {
return err
}

_, err = fmt.Fprintf(os.Stderr, "%s\n", sdk.MustSortJSON(out))

return err
}

// CollectGenTxsCmd - return the cobra command to collect genesis transactions
func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "collect-gentxs",
Short: "Collect genesis txs and output a genesis.json file",
RunE: func(cmd *cobra.Command, _ []string) error {
serverCtx := server.GetServerContextFromCmd(cmd)
config := serverCtx.Config

clientCtx := client.GetClientContextFromCmd(cmd)
cdc := clientCtx.Codec

config.SetRoot(clientCtx.HomeDir)

nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(config)
if err != nil {
return errors.Wrap(err, "failed to initialize node validator files")
}

genDoc, err := GenesisDocFromFile(config.GenesisFile())
if err != nil {
return errors.Wrap(err, "failed to read genesis doc from file")
}

genTxDir, _ := cmd.Flags().GetString(flagGenTxDir)
genTxsDir := genTxDir
if genTxsDir == "" {
genTxsDir = filepath.Join(config.RootDir, "config", "gentx")
}

toPrint := newPrintInfo(config.Moniker, genDoc["chain_id"].(string), nodeID, genTxsDir, json.RawMessage(""))
initCfg := types.NewInitConfig(genDoc["chain_id"].(string), genTxsDir, nodeID, valPubKey)

appMessage, err := GenAppStateFromConfig(cdc,
clientCtx.TxConfig,
config, initCfg, genDoc, genBalIterator)
if err != nil {
return errors.Wrap(err, "failed to get genesis app state from config")
}

toPrint.AppMessage = appMessage

return displayInfo(toPrint)
},
}

cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flagGenTxDir, "", "override default \"gentx\" directory from which collect and execute genesis transactions; default [--home]/config/gentx/")

return cmd
}

// GenAppStateFromConfig gets the genesis app state from the config
func GenAppStateFromConfig(cdc codec.JSONCodec, txEncodingConfig client.TxEncodingConfig,
config *cfg.Config, initCfg types.InitConfig, genDoc map[string]interface{}, genBalIterator types.GenesisBalancesIterator,
) (appState json.RawMessage, err error) {
// process genesis transactions, else create default genesis.json
appGenTxs, persistentPeers, err := CollectTxs(
cdc, txEncodingConfig.TxJSONDecoder(), config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator,
)
if err != nil {
return appState, err
}

config.P2P.PersistentPeers = persistentPeers
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)

// if there are no gen txs to be processed, return the default empty state
if len(appGenTxs) == 0 {
return appState, errors.New("there must be at least one genesis tx")
}

var appGenesisState map[string]json.RawMessage

bz, err := json.Marshal(genDoc["app_state"])
if err != nil {
return appState, err
}

err = json.Unmarshal(bz, &appGenesisState)
if err != nil {
return appState, err
}

appGenesisState, err = genutil.SetGenTxsInAppGenesisState(cdc, txEncodingConfig.TxJSONEncoder(), appGenesisState, appGenTxs)
if err != nil {
return appState, err
}

appState, err = json.MarshalIndent(appGenesisState, "", " ")
if err != nil {
return appState, err
}

genDoc["app_state"] = appState
genDocBytes, err := json.MarshalIndent(genDoc, "", " ")
if err != nil {
return appState, err
}
err = os.WriteFile(config.GenesisFile(), genDocBytes, 0o644)
if err != nil {
return appState, err
}

return appState, err
}

// CollectTxs processes and validates application's genesis Txs and returns
// the list of appGenTxs, and persistent peers required to generate genesis.json.
func CollectTxs(cdc codec.JSONCodec, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string,
genDoc map[string]interface{}, genBalIterator types.GenesisBalancesIterator,
) (appGenTxs []sdk.Tx, persistentPeers string, err error) {
// prepare a map of all balances in genesis state to then validate
// against the validators addresses
var appState map[string]json.RawMessage
bz, err := json.Marshal(genDoc["app_state"])
if err != nil {
return appGenTxs, persistentPeers, err
}

if err := json.Unmarshal(bz, &appState); err != nil {
return appGenTxs, persistentPeers, err
}

var fos []os.DirEntry
fos, err = os.ReadDir(genTxsDir)
if err != nil {
return appGenTxs, persistentPeers, err
}

balancesMap := make(map[string]bankexported.GenesisBalance)

genBalIterator.IterateGenesisBalances(
cdc, appState,
func(balance bankexported.GenesisBalance) (stop bool) {
balancesMap[balance.GetAddress().String()] = balance
return false
},
)

// addresses and IPs (and port) validator server info
var addressesIPs []string

for _, fo := range fos {
if fo.IsDir() {
continue
}
if !strings.HasSuffix(fo.Name(), ".json") {
continue
}

// get the genTx
jsonRawTx, err := os.ReadFile(filepath.Join(genTxsDir, fo.Name()))
if err != nil {
return appGenTxs, persistentPeers, err
}

genTx, err := types.ValidateAndGetGenTx(jsonRawTx, txJSONDecoder)
if err != nil {
return appGenTxs, persistentPeers, err
}

appGenTxs = append(appGenTxs, genTx)

// the memo flag is used to store
// the ip and node-id, for example this may be:
// "[email protected]:26656"

memoTx, ok := genTx.(sdk.TxWithMemo)
if !ok {
return appGenTxs, persistentPeers, fmt.Errorf("expected TxWithMemo, got %T", genTx)
}
nodeAddrIP := memoTx.GetMemo()
if len(nodeAddrIP) == 0 {
return appGenTxs, persistentPeers, fmt.Errorf("failed to find node's address and IP in %s", fo.Name())
}

// genesis transactions must be single-message
msgs := genTx.GetMsgs()

// TODO abstract out staking message validation back to staking
msg := msgs[0].(*stakingtypes.MsgCreateValidator)

// validate delegator and validator addresses and funds against the accounts in the state
delAddr := msg.DelegatorAddress
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddress)
if err != nil {
return appGenTxs, persistentPeers, err
}

delBal, delOk := balancesMap[delAddr]
if !delOk {
_, file, no, ok := runtime.Caller(1)
if ok {
fmt.Printf("CollectTxs-1, called from %s#%d\n", file, no)
}

return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", delAddr, balancesMap)
}

_, valOk := balancesMap[sdk.AccAddress(valAddr).String()]
if !valOk {
_, file, no, ok := runtime.Caller(1)
if ok {
fmt.Printf("CollectTxs-2, called from %s#%d - %s\n", file, no, sdk.AccAddress(msg.ValidatorAddress).String())
}
return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", valAddr, balancesMap)
}

if delBal.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) {
return appGenTxs, persistentPeers, fmt.Errorf(
"insufficient fund for delegation %v: %v < %v",
delBal.GetAddress().String(), delBal.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount,
)
}

// exclude itself from persistent peers
if msg.Description.Moniker != moniker {
addressesIPs = append(addressesIPs, nodeAddrIP)
}
}

sort.Strings(addressesIPs)
persistentPeers = strings.Join(addressesIPs, ",")

return appGenTxs, persistentPeers, nil
}
2 changes: 1 addition & 1 deletion cmd/rollappd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func initRootCmd(

rootCmd.AddCommand(
initCmd,
genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
genutilcli.MigrateGenesisCmd(),
genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),

Expand Down

0 comments on commit 5ae9dc3

Please sign in to comment.