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 }