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