github.com/cosmos/cosmos-sdk@v0.50.10/x/genutil/collect.go (about)

     1  package genutil
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"sort"
    11  	"strings"
    12  
    13  	cfg "github.com/cometbft/cometbft/config"
    14  
    15  	"github.com/cosmos/cosmos-sdk/client"
    16  	"github.com/cosmos/cosmos-sdk/codec"
    17  	sdkruntime "github.com/cosmos/cosmos-sdk/runtime"
    18  	sdk "github.com/cosmos/cosmos-sdk/types"
    19  	bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported"
    20  	"github.com/cosmos/cosmos-sdk/x/genutil/types"
    21  	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
    22  )
    23  
    24  // GenAppStateFromConfig gets the genesis app state from the config
    25  func GenAppStateFromConfig(cdc codec.JSONCodec, txEncodingConfig client.TxEncodingConfig,
    26  	config *cfg.Config, initCfg types.InitConfig, genesis *types.AppGenesis, genBalIterator types.GenesisBalancesIterator,
    27  	validator types.MessageValidator, valAddrCodec sdkruntime.ValidatorAddressCodec,
    28  ) (appState json.RawMessage, err error) {
    29  	// process genesis transactions, else create default genesis.json
    30  	appGenTxs, persistentPeers, err := CollectTxs(
    31  		cdc, txEncodingConfig.TxJSONDecoder(), config.Moniker, initCfg.GenTxsDir, genesis, genBalIterator, validator, valAddrCodec)
    32  	if err != nil {
    33  		return appState, err
    34  	}
    35  
    36  	config.P2P.PersistentPeers = persistentPeers
    37  	cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
    38  
    39  	// if there are no gen txs to be processed, return the default empty state
    40  	if len(appGenTxs) == 0 {
    41  		return appState, errors.New("there must be at least one genesis tx")
    42  	}
    43  
    44  	// create the app state
    45  	appGenesisState, err := types.GenesisStateFromAppGenesis(genesis)
    46  	if err != nil {
    47  		return appState, err
    48  	}
    49  
    50  	appGenesisState, err = SetGenTxsInAppGenesisState(cdc, txEncodingConfig.TxJSONEncoder(), appGenesisState, appGenTxs)
    51  	if err != nil {
    52  		return appState, err
    53  	}
    54  
    55  	appState, err = json.MarshalIndent(appGenesisState, "", "  ")
    56  	if err != nil {
    57  		return appState, err
    58  	}
    59  
    60  	genesis.AppState = appState
    61  	err = ExportGenesisFile(genesis, config.GenesisFile())
    62  
    63  	return appState, err
    64  }
    65  
    66  // CollectTxs processes and validates application's genesis Txs and returns
    67  // the list of appGenTxs, and persistent peers required to generate genesis.json.
    68  func CollectTxs(cdc codec.JSONCodec, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string,
    69  	genesis *types.AppGenesis, genBalIterator types.GenesisBalancesIterator,
    70  	validator types.MessageValidator, valAddrCodec sdkruntime.ValidatorAddressCodec,
    71  ) (appGenTxs []sdk.Tx, persistentPeers string, err error) {
    72  	// prepare a map of all balances in genesis state to then validate
    73  	// against the validators addresses
    74  	var appState map[string]json.RawMessage
    75  	if err := json.Unmarshal(genesis.AppState, &appState); err != nil {
    76  		return appGenTxs, persistentPeers, err
    77  	}
    78  
    79  	var fos []os.DirEntry
    80  	fos, err = os.ReadDir(genTxsDir)
    81  	if err != nil {
    82  		return appGenTxs, persistentPeers, err
    83  	}
    84  
    85  	balancesMap := make(map[string]bankexported.GenesisBalance)
    86  
    87  	genBalIterator.IterateGenesisBalances(
    88  		cdc, appState,
    89  		func(balance bankexported.GenesisBalance) (stop bool) {
    90  			addr := balance.GetAddress()
    91  			balancesMap[addr] = balance
    92  			return false
    93  		},
    94  	)
    95  
    96  	// addresses and IPs (and port) validator server info
    97  	var addressesIPs []string
    98  
    99  	for _, fo := range fos {
   100  		if fo.IsDir() {
   101  			continue
   102  		}
   103  		if !strings.HasSuffix(fo.Name(), ".json") {
   104  			continue
   105  		}
   106  
   107  		// get the genTx
   108  		jsonRawTx, err := os.ReadFile(filepath.Join(genTxsDir, fo.Name()))
   109  		if err != nil {
   110  			return appGenTxs, persistentPeers, err
   111  		}
   112  
   113  		genTx, err := types.ValidateAndGetGenTx(jsonRawTx, txJSONDecoder, validator)
   114  		if err != nil {
   115  			return appGenTxs, persistentPeers, err
   116  		}
   117  
   118  		appGenTxs = append(appGenTxs, genTx)
   119  
   120  		// the memo flag is used to store
   121  		// the ip and node-id, for example this may be:
   122  		// "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656"
   123  
   124  		memoTx, ok := genTx.(sdk.TxWithMemo)
   125  		if !ok {
   126  			return appGenTxs, persistentPeers, fmt.Errorf("expected TxWithMemo, got %T", genTx)
   127  		}
   128  		nodeAddrIP := memoTx.GetMemo()
   129  
   130  		// genesis transactions must be single-message
   131  		msgs := genTx.GetMsgs()
   132  
   133  		// TODO abstract out staking message validation back to staking
   134  		msg := msgs[0].(*stakingtypes.MsgCreateValidator)
   135  
   136  		// validate validator addresses and funds against the accounts in the state
   137  		valAddr, err := valAddrCodec.StringToBytes(msg.ValidatorAddress)
   138  		if err != nil {
   139  			return appGenTxs, persistentPeers, err
   140  		}
   141  
   142  		valAccAddr := sdk.AccAddress(valAddr).String()
   143  
   144  		delBal, delOk := balancesMap[valAccAddr]
   145  		if !delOk {
   146  			_, file, no, ok := runtime.Caller(1)
   147  			if ok {
   148  				fmt.Printf("CollectTxs-1, called from %s#%d\n", file, no)
   149  			}
   150  
   151  			return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", valAccAddr, balancesMap)
   152  		}
   153  
   154  		_, valOk := balancesMap[sdk.AccAddress(valAddr).String()]
   155  		if !valOk {
   156  			_, file, no, ok := runtime.Caller(1)
   157  			if ok {
   158  				fmt.Printf("CollectTxs-2, called from %s#%d - %s\n", file, no, sdk.AccAddress(msg.ValidatorAddress).String())
   159  			}
   160  			return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", valAddr, balancesMap)
   161  		}
   162  
   163  		if delBal.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) {
   164  			return appGenTxs, persistentPeers, fmt.Errorf(
   165  				"insufficient fund for delegation %v: %v < %v",
   166  				delBal.GetAddress(), delBal.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount,
   167  			)
   168  		}
   169  
   170  		// exclude itself from persistent peers
   171  		if msg.Description.Moniker != moniker {
   172  			addressesIPs = append(addressesIPs, nodeAddrIP)
   173  		}
   174  	}
   175  
   176  	sort.Strings(addressesIPs)
   177  	persistentPeers = strings.Join(addressesIPs, ",")
   178  
   179  	return appGenTxs, persistentPeers, nil
   180  }