Browse Source

Refactor priv_validator

Users can now just pass an object that implements the Signer interface.
pull/637/head
Adrian Brink 7 years ago
committed by Ethan Buchman
parent
commit
7dd3c007c7
16 changed files with 152 additions and 165 deletions
  1. +0
    -47
      cmd/hsm/main.go
  2. +2
    -0
      cmd/tendermint/commands/gen_validator.go
  3. +1
    -0
      cmd/tendermint/commands/init.go
  4. +1
    -0
      cmd/tendermint/commands/probe_upnp.go
  5. +3
    -0
      cmd/tendermint/commands/replay.go
  6. +11
    -7
      cmd/tendermint/commands/reset_priv_validator.go
  7. +1
    -0
      cmd/tendermint/commands/root.go
  8. +40
    -35
      cmd/tendermint/commands/run_node.go
  9. +2
    -1
      cmd/tendermint/commands/show_validator.go
  10. +8
    -6
      cmd/tendermint/commands/testnet.go
  11. +1
    -0
      cmd/tendermint/commands/version.go
  12. +20
    -2
      cmd/tendermint/main.go
  13. +1
    -1
      consensus/common_test.go
  14. +1
    -1
      node/node.go
  15. +1
    -1
      rpc/test/helpers.go
  16. +59
    -64
      types/priv_validator.go

+ 0
- 47
cmd/hsm/main.go View File

@ -1,47 +0,0 @@
package main
import (
tcrypto "github.com/tendermint/go-crypto"
tc "github.com/tendermint/tendermint/cmd/tendermint/commands"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
"github.com/tendermint/tmlibs/log"
"os"
)
var (
config = cfg.DefaultConfig()
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "main")
)
func main() {
// TODO: Make it easier to build a tendermint instance from scratch.
// All commands should be exported and it should be easy to override
// certain aspects of a single command.
// Probably every command should have a constructor that allows a user
// to vary the configuration. This is at least true for run_node.go
rootCmd := tc.RootCmd
rootCmd.AddCommand(tc.GenValidatorCmd)
rootCmd.AddCommand(tc.InitFilesCmd)
rootCmd.AddCommand(tc.ProbeUpnpCmd)
rootCmd.AddCommand(tc.ReplayCmd)
rootCmd.AddCommand(tc.ReplayConsoleCmd)
rootCmd.AddCommand(tc.ResetAllCmd)
rootCmd.AddCommand(tc.ResetPrivValidatorCmd)
rootCmd.AddCommand(tc.ShowValidatorCmd)
rootCmd.AddCommand(tc.TestnetFilesCmd)
rootCmd.AddCommand(tc.VersionCmd)
signerGenerator := func(pk tcrypto.PrivKey) types.Signer {
// Return your own signer implementation here
return types.NewDefaultSigner(pk)
}
privValidator := types.LoadPrivValidatorWithSigner(config.PrivValidatorFile(), signerGenerator)
rootCmd.AddCommand(tc.NewRunNodeCmd(privValidator))
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
cmd.Execute()
}

+ 2
- 0
cmd/tendermint/commands/gen_validator.go View File

@ -9,6 +9,8 @@ import (
"github.com/tendermint/tendermint/types"
)
// GenValidatorCmd allows the generation of a keypair for a
// validator.
var GenValidatorCmd = &cobra.Command{
Use: "gen_validator",
Short: "Generate new validator keypair",


+ 1
- 0
cmd/tendermint/commands/init.go View File

@ -9,6 +9,7 @@ import (
cmn "github.com/tendermint/tmlibs/common"
)
// InitFilesCmd initialises a fresh Tendermint Core instance.
var InitFilesCmd = &cobra.Command{
Use: "init",
Short: "Initialize Tendermint",


+ 1
- 0
cmd/tendermint/commands/probe_upnp.go View File

@ -9,6 +9,7 @@ import (
"github.com/tendermint/tendermint/p2p/upnp"
)
// ProbeUpnpCmd adds capabilities to test the UPnP functionality.
var ProbeUpnpCmd = &cobra.Command{
Use: "probe_upnp",
Short: "Test UPnP functionality",


+ 3
- 0
cmd/tendermint/commands/replay.go View File

@ -6,6 +6,7 @@ import (
"github.com/tendermint/tendermint/consensus"
)
// ReplayCmd allows replaying of messages from the WAL.
var ReplayCmd = &cobra.Command{
Use: "replay",
Short: "Replay messages from WAL",
@ -14,6 +15,8 @@ var ReplayCmd = &cobra.Command{
},
}
// ReplayConsoleCmd allows replaying of messages from the WAL in a
// console.
var ReplayConsoleCmd = &cobra.Command{
Use: "replay_console",
Short: "Replay messages from WAL in a console",


+ 11
- 7
cmd/tendermint/commands/reset_priv_validator.go View File

@ -9,18 +9,29 @@ import (
"github.com/tendermint/tmlibs/log"
)
// ResetAllCmd removes the database of this Tendermint core
// instance.
var ResetAllCmd = &cobra.Command{
Use: "unsafe_reset_all",
Short: "(unsafe) Remove all the data and WAL, reset this node's validator",
Run: resetAll,
}
// ResetPrivValidatorCmd resets the private validator files.
var ResetPrivValidatorCmd = &cobra.Command{
Use: "unsafe_reset_priv_validator",
Short: "(unsafe) Reset this node's validator",
Run: resetPrivValidator,
}
// ResetAll removes the privValidator files.
// Exported so other CLI tools can use it
func ResetAll(dbDir, privValFile string, logger log.Logger) {
resetPrivValidatorLocal(privValFile, logger)
os.RemoveAll(dbDir)
logger.Info("Removed all data", "dir", dbDir)
}
// XXX: this is totally unsafe.
// it's only suitable for testnets.
func resetAll(cmd *cobra.Command, args []string) {
@ -33,13 +44,6 @@ func resetPrivValidator(cmd *cobra.Command, args []string) {
resetPrivValidatorLocal(config.PrivValidatorFile(), logger)
}
// Exported so other CLI tools can use it
func ResetAll(dbDir, privValFile string, logger log.Logger) {
resetPrivValidatorLocal(privValFile, logger)
os.RemoveAll(dbDir)
logger.Info("Removed all data", "dir", dbDir)
}
func resetPrivValidatorLocal(privValFile string, logger log.Logger) {
// Get PrivValidator
var privValidator *types.PrivValidator


+ 1
- 0
cmd/tendermint/commands/root.go View File

@ -34,6 +34,7 @@ func ParseConfig() (*cfg.Config, error) {
return conf, err
}
// RootCmd is the root command for Tendermint core.
var RootCmd = &cobra.Command{
Use: "tendermint",
Short: "Tendermint Core (BFT Consensus) in Go",


+ 40
- 35
cmd/tendermint/commands/run_node.go View File

@ -12,6 +12,38 @@ import (
"github.com/tendermint/tendermint/types"
)
func init() {
AddNodeFlags(RunNodeCmd)
}
// 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) {
// bind flags
cmd.Flags().String("moniker", config.Moniker, "Node Name")
// node flags
cmd.Flags().Bool("fast_sync", config.FastSync, "Fast blockchain syncing")
// abci flags
cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or 'nilapp' or 'dummy' for local testing.")
cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)")
// rpc flags
cmd.Flags().String("rpc.laddr", config.RPC.ListenAddress, "RPC listen address. Port required")
cmd.Flags().String("rpc.grpc_laddr", config.RPC.GRPCListenAddress, "GRPC listen address (BroadcastTx only). Port required")
cmd.Flags().Bool("rpc.unsafe", config.RPC.Unsafe, "Enabled unsafe rpc methods")
// p2p flags
cmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma delimited host:port seed nodes")
cmd.Flags().Bool("p2p.skip_upnp", config.P2P.SkipUPNP, "Skip UPNP configuration")
cmd.Flags().Bool("p2p.pex", config.P2P.PexReactor, "Enable Peer-Exchange (dev feature)")
// consensus flags
cmd.Flags().Bool("consensus.create_empty_blocks", config.Consensus.CreateEmptyBlocks, "Set this to false to only produce blocks when there are txs or when the AppHash changes")
}
// RunNodeCmd creates and starts a tendermint node.
var RunNodeCmd = &cobra.Command{
Use: "node",
@ -19,8 +51,8 @@ var RunNodeCmd = &cobra.Command{
RunE: runNode,
}
// NewRunNodeCmd creates and starts a tendermint node. It allows the user to
// use a custom PrivValidator.
// NewRunNodeCmd returns the command that allows the CLI to start a
// node. It can be used with a custom PrivValidator.
func NewRunNodeCmd(privVal *types.PrivValidator) *cobra.Command {
return &cobra.Command{
Use: "node",
@ -43,7 +75,12 @@ func NewRunNodeCmd(privVal *types.PrivValidator) *cobra.Command {
config.ChainID = genDoc.ChainID
// Create & start node
n := node.NewNode(config, privVal, proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), logger)
var n *node.Node
if privVal == nil {
n = node.NewNodeDefault(config, logger.With("module", "node"))
}
n = node.NewNode(config, privVal, proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), logger)
if _, err := n.Start(); err != nil {
return fmt.Errorf("Failed to start node: %v", err)
} else {
@ -58,38 +95,6 @@ func NewRunNodeCmd(privVal *types.PrivValidator) *cobra.Command {
}
}
func init() {
AddNodeFlags(RunNodeCmd)
}
// 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) {
// bind flags
cmd.Flags().String("moniker", config.Moniker, "Node Name")
// node flags
cmd.Flags().Bool("fast_sync", config.FastSync, "Fast blockchain syncing")
// abci flags
cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or 'nilapp' or 'dummy' for local testing.")
cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)")
// rpc flags
cmd.Flags().String("rpc.laddr", config.RPC.ListenAddress, "RPC listen address. Port required")
cmd.Flags().String("rpc.grpc_laddr", config.RPC.GRPCListenAddress, "GRPC listen address (BroadcastTx only). Port required")
cmd.Flags().Bool("rpc.unsafe", config.RPC.Unsafe, "Enabled unsafe rpc methods")
// p2p flags
cmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma delimited host:port seed nodes")
cmd.Flags().Bool("p2p.skip_upnp", config.P2P.SkipUPNP, "Skip UPNP configuration")
cmd.Flags().Bool("p2p.pex", config.P2P.PexReactor, "Enable Peer-Exchange (dev feature)")
// consensus flags
cmd.Flags().Bool("consensus.create_empty_blocks", config.Consensus.CreateEmptyBlocks, "Set this to false to only produce blocks when there are txs or when the AppHash changes")
}
// Users wishing to:
// * Use an external signer for their validators
// * Supply an in-proc abci app


+ 2
- 1
cmd/tendermint/commands/show_validator.go View File

@ -9,6 +9,7 @@ import (
"github.com/tendermint/tendermint/types"
)
// ShowValidatorCmd adds capabilities for showing the validator info.
var ShowValidatorCmd = &cobra.Command{
Use: "show_validator",
Short: "Show this node's validator info",
@ -16,7 +17,7 @@ var ShowValidatorCmd = &cobra.Command{
}
func showValidator(cmd *cobra.Command, args []string) {
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile(), logger)
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile())
pubKeyJSONBytes, _ := data.ToJSON(privValidator.PubKey)
fmt.Println(string(pubKeyJSONBytes))
}

+ 8
- 6
cmd/tendermint/commands/testnet.go View File

@ -11,12 +11,6 @@ import (
cmn "github.com/tendermint/tmlibs/common"
)
var TestnetFilesCmd = &cobra.Command{
Use: "testnet",
Short: "Initialize files for a Tendermint testnet",
Run: testnetFiles,
}
//flags
var (
nValidators int
@ -30,6 +24,14 @@ func init() {
"Directory to store initialization data for the testnet")
}
// TestnetFilesCmd allows initialisation of files for a
// Tendermint testnet.
var TestnetFilesCmd = &cobra.Command{
Use: "testnet",
Short: "Initialize files for a Tendermint testnet",
Run: testnetFiles,
}
func testnetFiles(cmd *cobra.Command, args []string) {
genVals := make([]types.GenesisValidator, nValidators)


+ 1
- 0
cmd/tendermint/commands/version.go View File

@ -8,6 +8,7 @@ import (
"github.com/tendermint/tendermint/version"
)
// VersionCmd ...
var VersionCmd = &cobra.Command{
Use: "version",
Short: "Show version infoooooooo",


+ 20
- 2
cmd/tendermint/main.go View File

@ -3,11 +3,29 @@ package main
import (
"os"
"github.com/tendermint/tendermint/cmd/tendermint/commands"
// crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/tmlibs/cli"
. "github.com/tendermint/tendermint/cmd/tendermint/commands"
// "github.com/tendermint/tendermint/types"
)
func main() {
cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
rootCmd := RootCmd
rootCmd.AddCommand(GenValidatorCmd, InitFilesCmd, ProbeUpnpCmd,
ReplayCmd, ReplayConsoleCmd, ResetAllCmd, ResetPrivValidatorCmd,
ShowValidatorCmd, TestnetFilesCmd, VersionCmd)
// NOTE: Implement your own type that implements the Signer interface
// and then instantiate it here.
// signer := types.NewDefaultSigner(pk)
// privValidator := types.LoadPrivValidatorWithSigner(signer)
// rootCmd.AddCommand(NewRunNodeCmd(privValidator))
// Create & start node
rootCmd.AddCommand(RunNodeCmd)
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
cmd.Execute()
}

+ 1
- 1
consensus/common_test.go View File

@ -261,7 +261,7 @@ func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv *ty
func loadPrivValidator(config *cfg.Config) *types.PrivValidator {
privValidatorFile := config.PrivValidatorFile()
ensureDir(path.Dir(privValidatorFile), 0700)
privValidator := types.LoadOrGenPrivValidator(privValidatorFile, log.TestingLogger())
privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
privValidator.Reset()
return privValidator
}


+ 1
- 1
node/node.go View File

@ -60,7 +60,7 @@ type Node struct {
func NewNodeDefault(config *cfg.Config, logger log.Logger) *Node {
// Get PrivValidator
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile(), logger)
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile())
return NewNode(config, privValidator,
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), logger)
}


+ 1
- 1
rpc/test/helpers.go View File

@ -79,7 +79,7 @@ func NewTendermint(app abci.Application) *nm.Node {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privValidator := types.LoadOrGenPrivValidator(privValidatorFile, logger)
privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
papp := proxy.NewLocalClientCreator(app)
node := nm.NewNode(config, privValidator, papp, logger)
return node


+ 59
- 64
types/priv_validator.go View File

@ -12,7 +12,6 @@ import (
crypto "github.com/tendermint/go-crypto"
data "github.com/tendermint/go-wire/data"
. "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
// TODO: type ?
@ -35,30 +34,6 @@ func voteToStep(vote *Vote) int8 {
}
}
// PrivValidator implements the functionality for signing blocks.
type PrivValidator struct {
Address data.Bytes `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
LastHeight int `json:"last_height"`
LastRound int `json:"last_round"`
LastStep int8 `json:"last_step"`
LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures
LastSignBytes data.Bytes `json:"last_signbytes,omitempty"` // so we dont lose signatures
// PrivKey should be empty if a Signer other than the default is being used.
PrivKey crypto.PrivKey `json:"priv_key"`
Signer `json:"-"`
// For persistence.
// Overloaded for testing.
filePath string
mtx sync.Mutex
}
type SignerGenerator func(pk crypto.PrivKey) (Signer)
// This is used to sign votes.
// It is the caller's duty to verify the msg before calling Sign,
// eg. to avoid double signing.
@ -90,38 +65,39 @@ func (ds *DefaultSigner) PubKey() crypto.PubKey {
return ds.priv.PubKey()
}
func (privVal *PrivValidator) SetSigner(s Signer) {
privVal.Signer = s
privVal.setPubKeyAndAddress()
}
// PrivValidator implements the functionality for signing blocks.
type PrivValidator struct {
Address data.Bytes `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
LastHeight int `json:"last_height"`
LastRound int `json:"last_round"`
LastStep int8 `json:"last_step"`
LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures
LastSignBytes data.Bytes `json:"last_signbytes,omitempty"` // so we dont lose signatures
// Overwrite address and pubkey for convenience
func (privVal *PrivValidator) setPubKeyAndAddress() {
privVal.PubKey = privVal.Signer.PubKey()
privVal.Address = privVal.PubKey.Address()
// PrivKey should be empty if a Signer other than the default is being used.
PrivKey crypto.PrivKey `json:"priv_key"`
Signer `json:"-"`
// For persistence.
// Overloaded for testing.
filePath string
mtx sync.Mutex
}
// Generates a new validator with private key.
func GenPrivValidator() *PrivValidator {
privKey := crypto.GenPrivKeyEd25519().Wrap()
pubKey := privKey.PubKey()
return &PrivValidator{
Address: pubKey.Address(),
PubKey: pubKey,
PrivKey: privKey,
LastStep: stepNone,
filePath: "",
Signer: NewDefaultSigner(privKey),
func LoadOrGenPrivValidator(filePath string) *PrivValidator {
var privValidator *PrivValidator
if _, err := os.Stat(filePath); err == nil {
privValidator = LoadPrivValidator(filePath)
} else {
privValidator = GenPrivValidator()
privValidator.SetFile(filePath)
privValidator.Save()
}
return privValidator
}
func LoadPrivValidator(filePath string) *PrivValidator {
return LoadPrivValidatorWithSigner(filePath, func(pk crypto.PrivKey) Signer {
return NewDefaultSigner(pk)
})
}
func LoadPrivValidatorWithSigner(filePath string, generator SignerGenerator) *PrivValidator {
privValJSONBytes, err := ioutil.ReadFile(filePath)
if err != nil {
Exit(err.Error())
@ -133,25 +109,44 @@ func LoadPrivValidatorWithSigner(filePath string, generator SignerGenerator) *Pr
}
privVal.filePath = filePath
privVal.Signer = generator(privVal.PrivKey)
privVal.Signer = NewDefaultSigner(privVal.PrivKey)
privVal.setPubKeyAndAddress()
return &privVal
}
func LoadOrGenPrivValidator(filePath string, logger log.Logger) *PrivValidator {
var privValidator *PrivValidator
if _, err := os.Stat(filePath); err == nil {
privValidator = LoadPrivValidator(filePath)
logger.Info("Loaded PrivValidator",
"file", filePath, "privValidator", privValidator)
} else {
privValidator = GenPrivValidator()
privValidator.SetFile(filePath)
privValidator.Save()
logger.Info("Generated PrivValidator", "file", filePath)
// Generates a new validator with private key.
func GenPrivValidator() *PrivValidator {
privKey := crypto.GenPrivKeyEd25519().Wrap()
pubKey := privKey.PubKey()
return &PrivValidator{
Address: pubKey.Address(),
PubKey: pubKey,
PrivKey: privKey,
LastStep: stepNone,
filePath: "",
Signer: NewDefaultSigner(privKey),
}
return privValidator
}
func LoadPrivValidatorWithSigner(signer Signer) *PrivValidator {
return &PrivValidator{
Address: signer.PubKey().Address(),
PubKey: signer.PubKey(),
LastStep: stepNone,
filePath: "",
Signer: signer,
}
}
func (privVal *PrivValidator) SetSigner(s Signer) {
privVal.Signer = s
privVal.setPubKeyAndAddress()
}
// Overwrite address and pubkey for convenience
func (privVal *PrivValidator) setPubKeyAndAddress() {
privVal.PubKey = privVal.Signer.PubKey()
privVal.Address = privVal.PubKey.Address()
}
func (privVal *PrivValidator) SetFile(filePath string) {


Loading…
Cancel
Save