github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/genutil/collect.go (about)

     1  package genutil
     2  
     3  // DONTCOVER
     4  
     5  import (
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  
    15  	stakingtypes "github.com/fibonacci-chain/fbc/x/staking/types"
    16  
    17  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    18  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    19  	authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
    20  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    21  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/genutil/types"
    22  	cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config"
    23  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    24  )
    25  
    26  // GenAppStateFromConfig gets the genesis app state from the config
    27  func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config,
    28  	initCfg InitConfig, genDoc tmtypes.GenesisDoc,
    29  	genAccIterator types.GenesisAccountsIterator,
    30  ) (appState json.RawMessage, err error) {
    31  
    32  	// process genesis transactions, else create default genesis.json
    33  	appGenTxs, persistentPeers, err := CollectStdTxs(
    34  		cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genAccIterator)
    35  	if err != nil {
    36  		return appState, err
    37  	}
    38  
    39  	config.P2P.PersistentPeers = persistentPeers
    40  
    41  	var nodeKeyWhiteList []string
    42  	for _, nodeAddr := range strings.Split(persistentPeers, ",") {
    43  		nodeKey := strings.Split(nodeAddr, "@")[0]
    44  		nodeKeyWhiteList = append(nodeKeyWhiteList, nodeKey)
    45  	}
    46  	config.Mempool.NodeKeyWhitelist = nodeKeyWhiteList
    47  	cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
    48  
    49  	// if there are no gen txs to be processed, return the default empty state
    50  	if len(appGenTxs) == 0 {
    51  		return appState, errors.New("there must be at least one genesis tx")
    52  	}
    53  
    54  	// create the app state
    55  	appGenesisState, err := GenesisStateFromGenDoc(cdc, genDoc)
    56  	if err != nil {
    57  		return appState, err
    58  	}
    59  
    60  	appGenesisState, err = SetGenTxsInAppGenesisState(cdc, appGenesisState, appGenTxs)
    61  	if err != nil {
    62  		return appState, err
    63  	}
    64  	appState, err = codec.MarshalJSONIndent(cdc, appGenesisState)
    65  	if err != nil {
    66  		return appState, err
    67  	}
    68  
    69  	genDoc.AppState = appState
    70  	err = ExportGenesisFile(&genDoc, config.GenesisFile())
    71  	return appState, err
    72  }
    73  
    74  // CollectStdTxs processes and validates application's genesis StdTxs and returns
    75  // the list of appGenTxs, and persistent peers required to generate genesis.json.
    76  func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string,
    77  	genDoc tmtypes.GenesisDoc, genAccIterator types.GenesisAccountsIterator,
    78  ) (appGenTxs []authtypes.StdTx, persistentPeers string, err error) {
    79  
    80  	var fos []os.FileInfo
    81  	fos, err = ioutil.ReadDir(genTxsDir)
    82  	if err != nil {
    83  		return appGenTxs, persistentPeers, err
    84  	}
    85  
    86  	// prepare a map of all accounts in genesis state to then validate
    87  	// against the validators addresses
    88  	var appState map[string]json.RawMessage
    89  	if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
    90  		return appGenTxs, persistentPeers, err
    91  	}
    92  
    93  	addrMap := make(map[string]authexported.Account)
    94  	genAccIterator.IterateGenesisAccounts(cdc, appState,
    95  		func(acc authexported.Account) (stop bool) {
    96  			addrMap[acc.GetAddress().String()] = acc
    97  			return false
    98  		},
    99  	)
   100  
   101  	// addresses and IPs (and port) validator server info
   102  	var addressesIPs []string
   103  
   104  	for _, fo := range fos {
   105  		if fo == nil {
   106  			continue
   107  		}
   108  		filename := filepath.Join(genTxsDir, fo.Name())
   109  		if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
   110  			continue
   111  		}
   112  
   113  		// get the genStdTx
   114  		var jsonRawTx []byte
   115  		if jsonRawTx, err = ioutil.ReadFile(filename); err != nil {
   116  			return appGenTxs, persistentPeers, err
   117  		}
   118  		var genStdTx authtypes.StdTx
   119  		if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil {
   120  			return appGenTxs, persistentPeers, err
   121  		}
   122  		appGenTxs = append(appGenTxs, genStdTx)
   123  
   124  		// genesis transactions must be single-message
   125  		msgs := genStdTx.GetMsgs()
   126  		if len(msgs) != 1 {
   127  			return appGenTxs, persistentPeers, errors.New(
   128  				"each genesis transaction must provide a single genesis message")
   129  		}
   130  
   131  		//ignore not create validator tx
   132  		msg, ok := msgs[0].(stakingtypes.MsgCreateValidator)
   133  		if !ok {
   134  			continue
   135  		}
   136  
   137  		// the memo flag is used to store
   138  		// the ip and node-id, for example this may be:
   139  		// "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656"
   140  		nodeAddrIP := genStdTx.GetMemo()
   141  		if len(nodeAddrIP) == 0 {
   142  			return appGenTxs, persistentPeers, fmt.Errorf(
   143  				"couldn't find node's address and IP in %s", fo.Name())
   144  		}
   145  
   146  		// TODO abstract out staking message validation back to staking
   147  		// validate delegator and validator addresses and funds against the accounts in the state
   148  		delAddr := msg.DelegatorAddress.String()
   149  		valAddr := sdk.AccAddress(msg.ValidatorAddress).String()
   150  
   151  		delAcc, delOk := addrMap[delAddr]
   152  		if !delOk {
   153  			return appGenTxs, persistentPeers, fmt.Errorf(
   154  				"account %v not in genesis.json: %+v", delAddr, addrMap)
   155  		}
   156  
   157  		_, valOk := addrMap[valAddr]
   158  		if !valOk {
   159  			return appGenTxs, persistentPeers, fmt.Errorf(
   160  				"account %v not in genesis.json: %+v", valAddr, addrMap)
   161  		}
   162  
   163  		if delAcc.GetCoins().AmountOf(msg.MinSelfDelegation.Denom).LT(msg.MinSelfDelegation.Amount) {
   164  			return appGenTxs, persistentPeers, fmt.Errorf(
   165  				"insufficient fund for delegation %v: %v < %v",
   166  				delAcc.GetAddress(), delAcc.GetCoins().AmountOf(msg.MinSelfDelegation.Denom), msg.MinSelfDelegation.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  }