Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/oasis-node/cmd/genesis: Add convert CLI command #3290

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
go/oasis-node/cmd/genesis: Add convert CLI command
It can be used to convert a given genesis file to the canonical form.
  • Loading branch information
tjanez committed Sep 18, 2020
commit 489bf77eee05fa8e9d6c42896f8d272ba996da97
3 changes: 3 additions & 0 deletions .changelog/3290.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go/oasis-node: Add `oasis-node genesis convert` CLI command

It can be used to convert a given genesis file to the canonical form.
86 changes: 74 additions & 12 deletions go/oasis-node/cmd/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math"
"os"
Expand All @@ -27,7 +28,7 @@ import (
tendermint "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/api"
epochtime "github.com/oasisprotocol/oasis-core/go/epochtime/api"
genesis "github.com/oasisprotocol/oasis-core/go/genesis/api"
genesisFile "github.com/oasisprotocol/oasis-core/go/genesis/file"
genesisfile "github.com/oasisprotocol/oasis-core/go/genesis/file"
keymanager "github.com/oasisprotocol/oasis-core/go/keymanager/api"
cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common"
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags"
Expand All @@ -39,6 +40,9 @@ import (
)

const (
cfgGenesisCanonicalFile = "genesis.canonical_file"
cfgGenesisCanonicalFileShort = "C"

cfgEntity = "entity"
cfgRuntime = "runtime"
cfgNode = "node"
Expand Down Expand Up @@ -102,9 +106,10 @@ const (
)

var (
checkGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
dumpGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
initGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
checkGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
convertGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
dumpGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)
initGenesisFlags = flag.NewFlagSet("", flag.ContinueOnError)

genesisCmd = &cobra.Command{
Use: "genesis",
Expand All @@ -129,6 +134,12 @@ var (
Run: doCheckGenesis,
}

convertGenesisCmd = &cobra.Command{
Use: "convert",
Short: "convert genesis file to canonical form",
Run: doConvertGenesis,
}

logger = logging.GetLogger("cmd/genesis")
)

Expand Down Expand Up @@ -588,30 +599,72 @@ func doDumpGenesis(cmd *cobra.Command, args []string) {
}
}

func loadGenesisDocument(genFilePath string) (*genesis.Document, error) {
provider, err := genesisfile.NewFileProvider(genFilePath)
if err != nil {
return nil, fmt.Errorf("failed to open genesis file: %w", err)
}
doc, err := provider.GetGenesisDocument()
if err != nil {
return nil, fmt.Errorf("failed to get genesis document: %w", err)
}
return doc, nil
}

func doCheckGenesis(cmd *cobra.Command, args []string) {
if err := cmdCommon.Init(); err != nil {
cmdCommon.EarlyLogAndExit(err)
}

filename := flags.GenesisFile()
provider, err := genesisFile.NewFileProvider(filename)
doc, err := loadGenesisDocument(flags.GenesisFile())
if err != nil {
logger.Error("failed to open genesis file", "err", err)
logger.Error("failed to load genesis document", "err", err)
os.Exit(1)
}
doc, err := provider.GetGenesisDocument()

err = doc.SanityCheck()
if err != nil {
logger.Error("failed to get genesis document", "err", err)
logger.Error("genesis document sanity check failed", "err", err)
os.Exit(1)
}
}

err = doc.SanityCheck()
func doConvertGenesis(cmd *cobra.Command, args []string) {
if err := cmdCommon.Init(); err != nil {
cmdCommon.EarlyLogAndExit(err)
}

doc, err := loadGenesisDocument(flags.GenesisFile())
if err != nil {
logger.Error("genesis document sanity check failed", "err", err)
logger.Error("failed to load genesis document", "err", err)
os.Exit(1)
}

// TODO: Pretty-print contents of genesis document.
data, err := json.MarshalIndent(doc, "", " ")
if err != nil {
logger.Error("failed to marshal genesis document into JSON",
"err", err,
)
os.Exit(1)
}

w, shouldClose, err := cmdCommon.GetOutputWriter(cmd, cfgGenesisCanonicalFile)
if err != nil {
logger.Error("failed to get writer for canonical genesis file",
"err", err,
)
os.Exit(1)
}
if shouldClose {
defer w.Close()
}

if _, err = w.Write(data); err != nil {
logger.Error("failed to write marshalled document to the canonical genesis file",
"err", err,
)
os.Exit(1)
}
}

// Register registers the genesis sub-command and all of it's children.
Expand All @@ -620,11 +673,13 @@ func Register(parentCmd *cobra.Command) {
dumpGenesisCmd.Flags().AddFlagSet(dumpGenesisFlags)
dumpGenesisCmd.PersistentFlags().AddFlagSet(cmdGrpc.ClientFlags)
checkGenesisCmd.Flags().AddFlagSet(checkGenesisFlags)
convertGenesisCmd.Flags().AddFlagSet(convertGenesisFlags)

for _, v := range []*cobra.Command{
initGenesisCmd,
dumpGenesisCmd,
checkGenesisCmd,
convertGenesisCmd,
} {
genesisCmd.AddCommand(v)
}
Expand All @@ -636,6 +691,13 @@ func init() {
_ = viper.BindPFlags(checkGenesisFlags)
checkGenesisFlags.AddFlagSet(flags.GenesisFileFlags)

_ = viper.BindPFlags(convertGenesisFlags)
convertGenesisFlags.AddFlagSet(flags.GenesisFileFlags)
convertGenesisFlags.StringP(
cfgGenesisCanonicalFile, cfgGenesisCanonicalFileShort,
"", "path to where to output the canonical genesis file (default: stdout)",
)

dumpGenesisFlags.Int64(cfgBlockHeight, consensus.HeightLatest, "block height at which to dump state")
_ = viper.BindPFlags(dumpGenesisFlags)
dumpGenesisFlags.AddFlagSet(flags.GenesisFileFlags)
Expand Down
57 changes: 46 additions & 11 deletions go/oasis-test-runner/scenario/e2e/genesis_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,52 +47,87 @@ func (s *genesisFileImpl) Fixture() (*oasis.NetworkFixture, error) {
}

func (s *genesisFileImpl) Run(childEnv *env.Env) error {
var err error
var out bytes.Buffer

// Manually provision genesis file.
s.Logger.Info("manually provisioning genesis file before starting the network")
if err := s.Net.MakeGenesis(); err != nil {
if err = s.Net.MakeGenesis(); err != nil {
return fmt.Errorf("e2e/genesis-file: failed to create genesis file")
}
// Set this genesis file in network's configuration.
cfg := s.Net.Config()
cfg.GenesisFile = s.Net.GenesisPath()

if err := checkGenesisFile(s.Net.GenesisPath()); err != nil {
// Checking if genesis check command works.
args := []string{
"genesis", "check",
"--genesis.file", s.Net.GenesisPath(),
"--debug.dont_blame_oasis",
"--debug.allow_test_keys",
}
out, err = cli.RunSubCommandWithOutput(childEnv, s.Logger, "genesis-file", s.Net.Config().NodeBinary, args)
if err != nil {
return fmt.Errorf("e2e/genesis-file: failed to run genesis check: error: %w output: %s", err, out.String())
}
s.Logger.Info("manually provisioned genesis file passed genesis check command")

if err = checkGenesisFileCanonical(s.Net.GenesisPath()); err != nil {
return fmt.Errorf("e2e/genesis-file: %w", err)
}
s.Logger.Info("manually provisioned genesis file equals canonical form")

if err := s.Net.Start(); err != nil {
if err = s.Net.Start(); err != nil {
return fmt.Errorf("e2e/genesis-file: failed to start network: %w", err)
}

s.Logger.Info("waiting for network to come up")
if err := s.Net.Controller().WaitNodesRegistered(context.Background(), 1); err != nil {
if err = s.Net.Controller().WaitNodesRegistered(context.Background(), 1); err != nil {
return fmt.Errorf("e2e/genesis-file: failed to wait for registered nodes: %w", err)
}

// Dump network state to a genesis file.
s.Logger.Info("dumping network state to genesis file")

dumpPath := filepath.Join(childEnv.Dir(), "genesis_dump.json")
args := []string{
args = []string{
"genesis", "dump",
"--height", "0",
"--genesis.file", dumpPath,
"--address", "unix:" + s.Net.Validators()[0].SocketPath(),
}
if err := cli.RunSubCommand(childEnv, s.Logger, "genesis-file", s.Net.Config().NodeBinary, args); err != nil {
return fmt.Errorf("e2e/genesis-file: failed to dump state: %w", err)
out, err = cli.RunSubCommandWithOutput(childEnv, s.Logger, "genesis-file", s.Net.Config().NodeBinary, args)
if err != nil {
return fmt.Errorf("e2e/genesis-file: failed to dump state: error: %w output: %s", err, out.String())
}
if err := checkGenesisFile(dumpPath); err != nil {
if err = checkGenesisFileCanonical(dumpPath); err != nil {
return fmt.Errorf("e2e/genesis-file: %w", err)
}
s.Logger.Info("genesis file from dumped network state equals canonical form")

// Checking if genesis convert command returns canonical form.
convertPath := filepath.Join(childEnv.Dir(), "genesis_convert.json")
args = []string{
"genesis", "convert",
"--genesis.file", dumpPath,
"--genesis.canonical_file", convertPath,
"--debug.dont_blame_oasis",
"--debug.allow_test_keys",
}
out, err = cli.RunSubCommandWithOutput(childEnv, s.Logger, "genesis-file", s.Net.Config().NodeBinary, args)
if err != nil {
return fmt.Errorf("e2e/genesis-file: failed to run genesis convert: error: %w output: %s", err, out.String())
}
if err = checkGenesisFileCanonical(convertPath); err != nil {
return fmt.Errorf("e2e/genesis-file: %w", err)
}
s.Logger.Info("genesis file generated via convert command equals canonical form")

return nil
}

// checkGenesisFile checks if the given genesis file equals the canonical form.
func checkGenesisFile(filePath string) error {
// checkGenesisFileCanonical checks if the given genesis file equals the
// canonical form.
func checkGenesisFileCanonical(filePath string) error {
// Load genesis document from the genesis file.
provider, err := genesisFile.NewFileProvider(filePath)
if err != nil {
Expand Down