interim gen app tx refactor

This commit is contained in:
rigelrozanski 2018-04-25 01:37:46 -04:00
parent d1402f4e92
commit 12f20d160a
1 changed files with 147 additions and 179 deletions

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
@ -25,59 +24,42 @@ import (
dbm "github.com/tendermint/tmlibs/db"
)
// genesis piece structure for creating combined genesis
type GenesisTx struct {
NodeID string `json:"node_id"`
IP string `json:"ip"`
Validator tmtypes.GenesisValidator `json:"validator"`
AppGenTx json.RawMessage `json:"app_gen_tx"`
}
var (
flagOverwrite = "overwrite"
flagGenTxs = "gen-txs"
flagIP = "ip"
flagChainID = "ip"
)
// get cmd to initialize all files for tendermint and application
func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
flagOverwrite, flagPieceFile, flagIP := "overwrite", "piece-file", "ip"
func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
Use: "gen-tx",
Short: "Create genesis transaction file (under [--home]/gentx-[nodeID].json)",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
RunE: func(_ *cobra.Command, args []string) error {
config := ctx.Config
pubkey := ReadOrCreatePrivValidator(config)
chainID, validators, appState, cliPrint, err := appInit.GenAppParams(cdc, pubkey)
if err != nil {
return err
}
genFile := config.GenesisFile()
if !viper.GetBool(flagOverwrite) && cmn.FileExists(genFile) {
return fmt.Errorf("genesis config file already exists: %v", genFile)
}
err = WriteGenesisFile(cdc, genFile, chainID, validators, appState)
if err != nil {
return err
}
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
nodeID := string(nodeKey.ID())
pubKey := ReadOrCreatePrivValidator(config)
// print out some key information
toPrint := struct {
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
AppMessage json.RawMessage `json:"app_message"`
}{
chainID,
nodeID,
cliPrint,
}
out, err := wire.MarshalJSONIndent(cdc, toPrint)
appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey)
if err != nil {
return err
}
fmt.Println(string(out))
// write the piece file is path specified
if viper.GetBool(flagPieceFile) {
//create the piece
ip := viper.GetString(flagIP)
if len(ip) == 0 {
ip, err = externalIP()
@ -85,169 +67,154 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return err
}
}
piece := GenesisPiece{
ChainID: chainID,
tx := GenesisTx{
NodeID: nodeID,
IP: ip,
AppState: appState,
Validators: validators,
Validator: validator,
AppGenTx: appGenTx,
}
bz, err := wire.MarshalJSONIndent(cdc, piece)
bz, err := wire.MarshalJSONIndent(cdc, tx)
if err != nil {
return err
}
name := fmt.Sprintf("piece%v.json", nodeID)
name := fmt.Sprintf("gentx-%v.json", nodeID)
file := filepath.Join(viper.GetString("home"), name)
return cmn.WriteFile(file, bz, 0644)
if err != nil {
return err
err = cmn.WriteFile(file, bz, 0644)
}
out, err := wire.MarshalJSONIndent(cdc, toPrint)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
if appInit.AppendAppState != nil {
cmd.AddCommand(FromPiecesCmd(ctx, cdc, appInit))
cmd.Flags().BoolP(flagPieceFile, "a", false, "create an append file (under [--home]/[nodeID]piece.json) for others to import")
}
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file")
cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine")
cmd.Flags().AddFlagSet(appInit.Flags)
cmd.Flags().AddFlagSet(appInit.FlagsAppTx)
return cmd
}
// genesis piece structure for creating combined genesis
type GenesisPiece struct {
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
IP string `json:"ip"`
AppState json.RawMessage `json:"app_state"`
Validators []tmtypes.GenesisValidator `json:"validators"`
}
// get cmd to initialize all files for tendermint and application
func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return &cobra.Command{
Use: "from-pieces [directory]",
Short: "Create genesis from directory of genesis pieces",
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
pieceDir := args[0]
func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
// ensure that the privVal and nodeKey file already exist
config := ctx.Config
privValFile := config.PrivValidatorFile()
nodeKeyFile := config.NodeKeyFile()
if !cmn.FileExists(privValFile) {
return fmt.Errorf("privVal file must already exist, please initialize with init cmd: %v", privValFile)
}
if !cmn.FileExists(nodeKeyFile) {
return fmt.Errorf("nodeKey file must already exist, please initialize with init cmd: %v", nodeKeyFile)
}
// remove genFile for creation
genFile := config.GenesisFile()
os.Remove(genFile)
// deterministically walk the directory for genesis-piece files to import
err := filepath.Walk(pieceDir, appendPiece(ctx, cdc, appInit, nodeKeyFile, genFile))
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
nodeID := string(nodeKey.ID())
pubKey := ReadOrCreatePrivValidator(config)
chainID := viper.GetString(flagChainID)
if chainID == "" {
chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6))
}
genFile := config.GenesisFile()
if !viper.GetBool(flagOverwrite) && cmn.FileExists(genFile) {
return fmt.Errorf("genesis.json file already exists: %v", genFile)
}
// process genesis transactions, or otherwise create one for defaults
var appGenTxs, cliPrints []json.RawMessage
var validators []tmtypes.GenesisValidator
var persistentPeers string
genTxsDir := viper.GetString(flagGenTxs)
if genTxsDir != "" {
validators, persistentPeers, appGenTxs, cliPrints = processGenTxs(genTxsDir, cdc, appInit)
config.P2P.PersistentPeers = persistentPeers
configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get
cfg.WriteConfigFile(configFilePath, config)
} else {
appTx, cliPrint, validator, err := appInit.GenAppTx(cdc, pubKey)
if err != nil {
return err
}
validators = []tmtypes.GenesisValidator{validator}
appGenTxs = []json.RawMessage{appTx}
cliPrints = []json.RawMessage{cliPrint}
}
appState, err := appInit.GenAppParams(cdc, appGenTxs)
if err != nil {
return err
}
err = WriteGenesisFile(cdc, genFile, chainID, validators, appState)
if err != nil {
return err
}
// print out some key information
toPrint := struct {
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
AppMessage []json.RawMessage `json:"app_messages"`
}{
chainID,
nodeID,
cliPrints,
}
out, err := wire.MarshalJSONIndent(cdc, toPrint)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
cmd.Flags().String(flagChainID, "", "designated chain-id for the genesis")
cmd.Flags().AddFlagSet(appInit.FlagsAppParams)
return cmd
}
// append a genesis-piece
func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, genFile string) filepath.WalkFunc {
return func(pieceFile string, _ os.FileInfo, err error) error {
fmt.Printf("debug pieceFile: %v\n", pieceFile)
if err != nil {
return err
}
if path.Ext(pieceFile) != ".json" {
func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
validators []tmtypes.GenesisValidator, appGenTxs, cliPrints []json.RawMessage, persistentPeers string, err error) {
fos, err := ioutil.ReadDir(genTxsDir)
for _, fo := range fos {
filename := fo.Name()
if !fo.IsDir() && (path.Ext(filename) != ".json") {
return nil
}
// get the piece file bytes
bz, err := ioutil.ReadFile(pieceFile)
// get the genTx
bz, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
var genTx GenesisTx
err = cdc.UnmarshalJSON(bz, &genTx)
if err != nil {
return err
}
// get the piece
var piece GenesisPiece
err = cdc.UnmarshalJSON(bz, &piece)
if err != nil {
return err
}
// combine some stuff
validators = append(validators, genTx.Validator)
appGenTxs = append(appGenTxs, genTx.AppGenTxs)
cliPrints = append(cliPrints, genTx.CliPrints)
// if the first file, create the genesis from scratch with piece inputs
if !cmn.FileExists(genFile) {
return WriteGenesisFile(cdc, genFile, piece.ChainID, piece.Validators, piece.AppState)
}
// read in the genFile
bz, err = ioutil.ReadFile(genFile)
if err != nil {
return err
}
var genMap map[string]json.RawMessage
err = cdc.UnmarshalJSON(bz, &genMap)
if err != nil {
return err
}
appState := genMap["app_state"]
// verify chain-ids are the same
var genChainID string
err = cdc.UnmarshalJSON(genMap["chain_id"], &genChainID)
if err != nil {
return err
}
if piece.ChainID != genChainID {
return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genChainID)
}
// combine the validator set
var validators []tmtypes.GenesisValidator
err = cdc.UnmarshalJSON(genMap["validators"], &validators)
if err != nil {
return err
}
validators = append(validators, piece.Validators...)
// combine the app state
appState, err = appInit.AppendAppState(cdc, appState, piece.AppState)
if err != nil {
return err
}
// write the appended genesis file
err = WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState)
if err != nil {
return err
}
// Add a persistent peer if the config (if it's not me)
myIP, err := externalIP()
if err != nil {
return err
}
if myIP == piece.IP {
return nil
}
// Add a persistent peer
comma := ","
if len(ctx.Config.P2P.PersistentPeers) == 0 {
if len(persistentPeers) == 0 {
comma = ""
}
//newPeer := fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP)
ctx.Config.P2P.PersistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP)
configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get
cfg.WriteConfigFile(configFilePath, ctx.Config)
persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP)
}
return nil
}
}
//________________________________________________________________________________________
@ -299,15 +266,17 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js
// Core functionality passed from the application to the server init command
type AppInit struct {
// flags required for GenAppParams
Flags *pflag.FlagSet
// flags required for application init functions
FlagsAppParams *pflag.FlagSet
FlagsAppTx *pflag.FlagSet
// GenAppParams creates the core parameters initialization. It takes in a
// pubkey meant to represent the pubkey of the validator of this machine.
GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error)
GenAppParams func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error)
// append appState1 with appState2
AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error)
// create the application genesis tx
GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) (
appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error)
}
// simple default application init
@ -316,7 +285,8 @@ var DefaultAppInit = AppInit{
}
// Create one account with a whole bunch of mycoin in it
func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) {
func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage) (
validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) {
var addr sdk.Address
@ -330,8 +300,6 @@ func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string,
bz, err := cdc.MarshalJSON(mm)
cliPrint = json.RawMessage(bz)
chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6))
validators = []tmtypes.GenesisValidator{{
PubKey: pubKey,
Power: 10,