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" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"path" "path"
"path/filepath" "path/filepath"
@ -25,59 +24,42 @@ import (
dbm "github.com/tendermint/tmlibs/db" 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 // get cmd to initialize all files for tendermint and application
func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
flagOverwrite, flagPieceFile, flagIP := "overwrite", "piece-file", "ip"
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "init", Use: "gen-tx",
Short: "Initialize genesis config, priv-validator file, and p2p-node file", Short: "Create genesis transaction file (under [--home]/gentx-[nodeID].json)",
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error { RunE: func(_ *cobra.Command, args []string) error {
config := ctx.Config 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()) nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil { if err != nil {
return err return err
} }
nodeID := string(nodeKey.ID()) nodeID := string(nodeKey.ID())
pubKey := ReadOrCreatePrivValidator(config)
// print out some key information appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey)
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)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(string(out))
// write the piece file is path specified
if viper.GetBool(flagPieceFile) {
//create the piece
ip := viper.GetString(flagIP) ip := viper.GetString(flagIP)
if len(ip) == 0 { if len(ip) == 0 {
ip, err = externalIP() ip, err = externalIP()
@ -85,169 +67,154 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return err return err
} }
} }
piece := GenesisPiece{
ChainID: chainID, tx := GenesisTx{
NodeID: nodeID, NodeID: nodeID,
IP: ip, IP: ip,
AppState: appState, Validator: validator,
Validators: validators, AppGenTx: appGenTx,
} }
bz, err := wire.MarshalJSONIndent(cdc, piece) bz, err := wire.MarshalJSONIndent(cdc, tx)
if err != nil { if err != nil {
return err return err
} }
name := fmt.Sprintf("piece%v.json", nodeID) name := fmt.Sprintf("gentx-%v.json", nodeID)
file := filepath.Join(viper.GetString("home"), name) 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 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().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 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 // get cmd to initialize all files for tendermint and application
func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return &cobra.Command{ cmd := &cobra.Command{
Use: "from-pieces [directory]", Use: "init",
Short: "Create genesis from directory of genesis pieces", Short: "Initialize genesis config, priv-validator file, and p2p-node file",
Args: cobra.ExactArgs(1), Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, _ []string) error {
pieceDir := args[0]
// ensure that the privVal and nodeKey file already exist
config := ctx.Config config := ctx.Config
privValFile := config.PrivValidatorFile() nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
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))
if err != nil { if err != nil {
return err 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 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 // append a genesis-piece
func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, genFile string) filepath.WalkFunc { func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
return func(pieceFile string, _ os.FileInfo, err error) error { validators []tmtypes.GenesisValidator, appGenTxs, cliPrints []json.RawMessage, persistentPeers string, err error) {
fmt.Printf("debug pieceFile: %v\n", pieceFile)
if err != nil { fos, err := ioutil.ReadDir(genTxsDir)
return err for _, fo := range fos {
} filename := fo.Name()
if path.Ext(pieceFile) != ".json" { if !fo.IsDir() && (path.Ext(filename) != ".json") {
return nil return nil
} }
// get the piece file bytes // get the genTx
bz, err := ioutil.ReadFile(pieceFile) bz, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
var genTx GenesisTx
err = cdc.UnmarshalJSON(bz, &genTx)
if err != nil { if err != nil {
return err return err
} }
// get the piece // combine some stuff
var piece GenesisPiece validators = append(validators, genTx.Validator)
err = cdc.UnmarshalJSON(bz, &piece) appGenTxs = append(appGenTxs, genTx.AppGenTxs)
if err != nil { cliPrints = append(cliPrints, genTx.CliPrints)
return err
}
// if the first file, create the genesis from scratch with piece inputs // Add a persistent peer
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
}
comma := "," comma := ","
if len(ctx.Config.P2P.PersistentPeers) == 0 { if len(persistentPeers) == 0 {
comma = "" comma = ""
} }
//newPeer := fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) persistentPeers += 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)
return nil 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 // Core functionality passed from the application to the server init command
type AppInit struct { type AppInit struct {
// flags required for GenAppParams // flags required for application init functions
Flags *pflag.FlagSet FlagsAppParams *pflag.FlagSet
FlagsAppTx *pflag.FlagSet
// GenAppParams creates the core parameters initialization. It takes in a // GenAppParams creates the core parameters initialization. It takes in a
// pubkey meant to represent the pubkey of the validator of this machine. // 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 // create the application genesis tx
AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) (
appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error)
} }
// simple default application init // simple default application init
@ -316,7 +285,8 @@ var DefaultAppInit = AppInit{
} }
// Create one account with a whole bunch of mycoin in it // 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 var addr sdk.Address
@ -330,8 +300,6 @@ func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string,
bz, err := cdc.MarshalJSON(mm) bz, err := cdc.MarshalJSON(mm)
cliPrint = json.RawMessage(bz) cliPrint = json.RawMessage(bz)
chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6))
validators = []tmtypes.GenesisValidator{{ validators = []tmtypes.GenesisValidator{{
PubKey: pubKey, PubKey: pubKey,
Power: 10, Power: 10,