diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 4e7021745..066f63028 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -97,6 +97,7 @@ program](https://hackerone.com/tendermint). - [p2p] \#4053 Add `unconditional_peer_ids` and `persistent_peers_max_dial_period` config variables (see ADR-050) (@dongsam) - [cli] \#4234 Add `--db_backend and --db_dir` flags (@princesinha19) +- [cli] \#4113 Add optional `--genesis_hash` flag to check genesis hash upon startup ### IMPROVEMENTS: diff --git a/cmd/tendermint/commands/run_node.go b/cmd/tendermint/commands/run_node.go index aaa9bc041..074ebfbc6 100644 --- a/cmd/tendermint/commands/run_node.go +++ b/cmd/tendermint/commands/run_node.go @@ -1,14 +1,24 @@ package commands import ( + "bytes" + "crypto/sha256" "fmt" + "io" + "os" + "github.com/pkg/errors" "github.com/spf13/cobra" + cfg "github.com/tendermint/tendermint/config" cmn "github.com/tendermint/tendermint/libs/common" nm "github.com/tendermint/tendermint/node" ) +var ( + genesisHash []byte +) + // AddNodeFlags exposes some common configuration options on the command-line // These are exposed for convenience of commands embedding a tendermint node func AddNodeFlags(cmd *cobra.Command) { @@ -23,6 +33,11 @@ func AddNodeFlags(cmd *cobra.Command) { // node flags cmd.Flags().Bool("fast_sync", config.FastSyncMode, "Fast blockchain syncing") + cmd.Flags().BytesHexVar( + &genesisHash, + "genesis_hash", + []byte{}, + "Optional SHA-256 hash of the genesis file") // abci flags cmd.Flags().String( @@ -96,6 +111,10 @@ func NewRunNodeCmd(nodeProvider nm.Provider) *cobra.Command { } }) + if err := checkGenesisHash(config); err != nil { + return err + } + if err := n.Start(); err != nil { return fmt.Errorf("failed to start node: %v", err) } @@ -109,3 +128,30 @@ func NewRunNodeCmd(nodeProvider nm.Provider) *cobra.Command { AddNodeFlags(cmd) return cmd } + +func checkGenesisHash(config *cfg.Config) error { + if len(genesisHash) == 0 || config.Genesis == "" { + return nil + } + + // Calculate SHA-256 hash of the genesis file. + f, err := os.Open(config.GenesisFile()) + if err != nil { + return errors.Wrap(err, "can't open genesis file") + } + defer f.Close() + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return errors.Wrap(err, "error when hashing genesis file") + } + actualHash := h.Sum(nil) + + // Compare with the flag. + if !bytes.Equal(genesisHash, actualHash) { + return errors.Errorf( + "--genesis_hash=%X does not match %s hash: %X", + genesisHash, config.GenesisFile(), actualHash) + } + + return nil +} diff --git a/node/node.go b/node/node.go index 00754002a..7decbf191 100644 --- a/node/node.go +++ b/node/node.go @@ -79,7 +79,7 @@ func DefaultGenesisDocProviderFunc(config *cfg.Config) GenesisDocProvider { } } -// NodeProvider takes a config and a logger and returns a ready to go Node. +// Provider takes a config and a logger and returns a ready to go Node. type Provider func(*cfg.Config, log.Logger) (*Node, error) // DefaultNewNode returns a Tendermint node with default settings for the