Merge pull request #637 from tendermint/feature/hsm
PrivValidator Interface
This commit is contained in:
commit
7f5908b622
|
@ -9,18 +9,16 @@ import (
|
|||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
var genValidatorCmd = &cobra.Command{
|
||||
// GenValidatorCmd allows the generation of a keypair for a
|
||||
// validator.
|
||||
var GenValidatorCmd = &cobra.Command{
|
||||
Use: "gen_validator",
|
||||
Short: "Generate new validator keypair",
|
||||
Run: genValidator,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(genValidatorCmd)
|
||||
}
|
||||
|
||||
func genValidator(cmd *cobra.Command, args []string) {
|
||||
privValidator := types.GenPrivValidator()
|
||||
privValidator := types.GenPrivValidatorFS("")
|
||||
privValidatorJSONBytes, _ := json.MarshalIndent(privValidator, "", "\t")
|
||||
fmt.Printf(`%v
|
||||
`, string(privValidatorJSONBytes))
|
||||
|
|
|
@ -9,21 +9,17 @@ import (
|
|||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
var initFilesCmd = &cobra.Command{
|
||||
// InitFilesCmd initialises a fresh Tendermint Core instance.
|
||||
var InitFilesCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize Tendermint",
|
||||
Run: initFiles,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(initFilesCmd)
|
||||
}
|
||||
|
||||
func initFiles(cmd *cobra.Command, args []string) {
|
||||
privValFile := config.PrivValidatorFile()
|
||||
if _, err := os.Stat(privValFile); os.IsNotExist(err) {
|
||||
privValidator := types.GenPrivValidator()
|
||||
privValidator.SetFile(privValFile)
|
||||
privValidator := types.GenPrivValidatorFS(privValFile)
|
||||
privValidator.Save()
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
|
@ -33,7 +29,7 @@ func initFiles(cmd *cobra.Command, args []string) {
|
|||
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
|
||||
}
|
||||
genDoc.Validators = []types.GenesisValidator{types.GenesisValidator{
|
||||
PubKey: privValidator.PubKey,
|
||||
PubKey: privValidator.GetPubKey(),
|
||||
Power: 10,
|
||||
}}
|
||||
|
||||
|
|
|
@ -9,16 +9,13 @@ import (
|
|||
"github.com/tendermint/tendermint/p2p/upnp"
|
||||
)
|
||||
|
||||
var probeUpnpCmd = &cobra.Command{
|
||||
// ProbeUpnpCmd adds capabilities to test the UPnP functionality.
|
||||
var ProbeUpnpCmd = &cobra.Command{
|
||||
Use: "probe_upnp",
|
||||
Short: "Test UPnP functionality",
|
||||
RunE: probeUpnp,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(probeUpnpCmd)
|
||||
}
|
||||
|
||||
func probeUpnp(cmd *cobra.Command, args []string) error {
|
||||
capabilities, err := upnp.Probe(logger)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,8 @@ import (
|
|||
"github.com/tendermint/tendermint/consensus"
|
||||
)
|
||||
|
||||
var replayCmd = &cobra.Command{
|
||||
// ReplayCmd allows replaying of messages from the WAL.
|
||||
var ReplayCmd = &cobra.Command{
|
||||
Use: "replay",
|
||||
Short: "Replay messages from WAL",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
@ -14,15 +15,12 @@ var replayCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var replayConsoleCmd = &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",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
consensus.RunReplayFile(config.BaseConfig, config.Consensus, true)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(replayCmd)
|
||||
RootCmd.AddCommand(replayConsoleCmd)
|
||||
}
|
||||
|
|
|
@ -9,21 +9,27 @@ import (
|
|||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
var resetAllCmd = &cobra.Command{
|
||||
// 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,
|
||||
}
|
||||
|
||||
var resetPrivValidatorCmd = &cobra.Command{
|
||||
// ResetPrivValidatorCmd resets the private validator files.
|
||||
var ResetPrivValidatorCmd = &cobra.Command{
|
||||
Use: "unsafe_reset_priv_validator",
|
||||
Short: "(unsafe) Reset this node's validator",
|
||||
Run: resetPrivValidator,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(resetAllCmd)
|
||||
RootCmd.AddCommand(resetPrivValidatorCmd)
|
||||
// ResetAll removes the privValidator files.
|
||||
// Exported so other CLI tools can use it
|
||||
func ResetAll(dbDir, privValFile string, logger log.Logger) {
|
||||
resetPrivValidatorFS(privValFile, logger)
|
||||
os.RemoveAll(dbDir)
|
||||
logger.Info("Removed all data", "dir", dbDir)
|
||||
}
|
||||
|
||||
// XXX: this is totally unsafe.
|
||||
|
@ -35,26 +41,17 @@ func resetAll(cmd *cobra.Command, args []string) {
|
|||
// XXX: this is totally unsafe.
|
||||
// it's only suitable for testnets.
|
||||
func resetPrivValidator(cmd *cobra.Command, args []string) {
|
||||
resetPrivValidatorLocal(config.PrivValidatorFile(), logger)
|
||||
resetPrivValidatorFS(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) {
|
||||
func resetPrivValidatorFS(privValFile string, logger log.Logger) {
|
||||
// Get PrivValidator
|
||||
var privValidator *types.PrivValidator
|
||||
if _, err := os.Stat(privValFile); err == nil {
|
||||
privValidator = types.LoadPrivValidator(privValFile)
|
||||
privValidator := types.LoadPrivValidatorFS(privValFile)
|
||||
privValidator.Reset()
|
||||
logger.Info("Reset PrivValidator", "file", privValFile)
|
||||
} else {
|
||||
privValidator = types.GenPrivValidator()
|
||||
privValidator.SetFile(privValFile)
|
||||
privValidator := types.GenPrivValidatorFS(privValFile)
|
||||
privValidator.Save()
|
||||
logger.Info("Generated PrivValidator", "file", privValFile)
|
||||
}
|
||||
|
|
|
@ -34,11 +34,12 @@ 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",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
if cmd.Name() == versionCmd.Name() {
|
||||
if cmd.Name() == VersionCmd.Name() {
|
||||
return nil
|
||||
}
|
||||
config, err = ParseConfig()
|
||||
|
|
|
@ -5,21 +5,9 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/node"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
nm "github.com/tendermint/tendermint/node"
|
||||
)
|
||||
|
||||
var runNodeCmd = &cobra.Command{
|
||||
Use: "node",
|
||||
Short: "Run the tendermint node",
|
||||
RunE: runNode,
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddNodeFlags(runNodeCmd)
|
||||
RootCmd.AddCommand(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) {
|
||||
|
@ -48,31 +36,32 @@ func AddNodeFlags(cmd *cobra.Command) {
|
|||
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
|
||||
// should import github.com/tendermint/tendermint/node and implement
|
||||
// their own run_node to call node.NewNode (instead of node.NewNodeDefault)
|
||||
// with their custom priv validator and/or custom proxy.ClientCreator
|
||||
func runNode(cmd *cobra.Command, args []string) error {
|
||||
// NewRunNodeCmd returns the command that allows the CLI to start a
|
||||
// node. It can be used with a custom PrivValidator and in-process ABCI application.
|
||||
func NewRunNodeCmd(nodeProvider nm.NodeProvider) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "node",
|
||||
Short: "Run the tendermint node",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Create & start node
|
||||
n, err := nodeProvider(config, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create node: %v", err)
|
||||
}
|
||||
|
||||
genDocFile := config.GenesisFile()
|
||||
genDoc, err := types.GenesisDocFromFile(genDocFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ChainID = genDoc.ChainID
|
||||
if _, err := n.Start(); err != nil {
|
||||
return fmt.Errorf("Failed to start node: %v", err)
|
||||
} else {
|
||||
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
|
||||
}
|
||||
|
||||
// Create & start node
|
||||
n := node.NewNodeDefault(config, logger.With("module", "node"))
|
||||
if _, err := n.Start(); err != nil {
|
||||
return fmt.Errorf("Failed to start node: %v", err)
|
||||
} else {
|
||||
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
|
||||
// Trap signal, run forever.
|
||||
n.RunForever()
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Trap signal, run forever.
|
||||
n.RunForever()
|
||||
|
||||
return nil
|
||||
AddNodeFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -9,18 +9,15 @@ import (
|
|||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
var showValidatorCmd = &cobra.Command{
|
||||
// ShowValidatorCmd adds capabilities for showing the validator info.
|
||||
var ShowValidatorCmd = &cobra.Command{
|
||||
Use: "show_validator",
|
||||
Short: "Show this node's validator info",
|
||||
Run: showValidator,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(showValidatorCmd)
|
||||
}
|
||||
|
||||
func showValidator(cmd *cobra.Command, args []string) {
|
||||
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile(), logger)
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile())
|
||||
pubKeyJSONBytes, _ := data.ToJSON(privValidator.PubKey)
|
||||
fmt.Println(string(pubKeyJSONBytes))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -24,12 +18,18 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
testnetFilesCmd.Flags().IntVar(&nValidators, "n", 4,
|
||||
TestnetFilesCmd.Flags().IntVar(&nValidators, "n", 4,
|
||||
"Number of validators to initialize the testnet with")
|
||||
testnetFilesCmd.Flags().StringVar(&dataDir, "dir", "mytestnet",
|
||||
TestnetFilesCmd.Flags().StringVar(&dataDir, "dir", "mytestnet",
|
||||
"Directory to store initialization data for the testnet")
|
||||
}
|
||||
|
||||
RootCmd.AddCommand(testnetFilesCmd)
|
||||
// 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) {
|
||||
|
@ -45,9 +45,9 @@ func testnetFiles(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
// Read priv_validator.json to populate vals
|
||||
privValFile := path.Join(dataDir, mach, "priv_validator.json")
|
||||
privVal := types.LoadPrivValidator(privValFile)
|
||||
privVal := types.LoadPrivValidatorFS(privValFile)
|
||||
genVals[i] = types.GenesisValidator{
|
||||
PubKey: privVal.PubKey,
|
||||
PubKey: privVal.GetPubKey(),
|
||||
Power: 1,
|
||||
Name: mach,
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ func ensurePrivValidator(file string) {
|
|||
if cmn.FileExists(file) {
|
||||
return
|
||||
}
|
||||
privValidator := types.GenPrivValidator()
|
||||
privValidator.SetFile(file)
|
||||
privValidator := types.GenPrivValidatorFS(file)
|
||||
privValidator.Save()
|
||||
}
|
||||
|
|
|
@ -8,14 +8,11 @@ import (
|
|||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
// VersionCmd ...
|
||||
var VersionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Show version info",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(version.Version)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
|
|
@ -3,11 +3,39 @@ package main
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
cmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
nm "github.com/tendermint/tendermint/node"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
|
||||
rootCmd := cmd.RootCmd
|
||||
rootCmd.AddCommand(
|
||||
cmd.GenValidatorCmd,
|
||||
cmd.InitFilesCmd,
|
||||
cmd.ProbeUpnpCmd,
|
||||
cmd.ReplayCmd,
|
||||
cmd.ReplayConsoleCmd,
|
||||
cmd.ResetAllCmd,
|
||||
cmd.ResetPrivValidatorCmd,
|
||||
cmd.ShowValidatorCmd,
|
||||
cmd.TestnetFilesCmd,
|
||||
cmd.VersionCmd)
|
||||
|
||||
// NOTE:
|
||||
// Users wishing to:
|
||||
// * Use an external signer for their validators
|
||||
// * Supply an in-proc abci app
|
||||
// * Supply a genesis doc file from another source
|
||||
// * Provide their own DB implementation
|
||||
// can copy this file and use something other than the
|
||||
// DefaultNewNode function
|
||||
nodeFunc := nm.DefaultNewNode
|
||||
|
||||
// Create & start node
|
||||
rootCmd.AddCommand(cmd.NewRunNodeCmd(nodeFunc))
|
||||
|
||||
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
|
||||
cmd.Execute()
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
data "github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
. "github.com/tendermint/tmlibs/common"
|
||||
|
@ -53,7 +55,7 @@ func TestByzantine(t *testing.T) {
|
|||
eventLogger := logger.With("module", "events")
|
||||
for i := 0; i < N; i++ {
|
||||
if i == 0 {
|
||||
css[i].privValidator = NewByzantinePrivValidator(css[i].privValidator.(*types.PrivValidator))
|
||||
css[i].privValidator = NewByzantinePrivValidator(css[i].privValidator)
|
||||
// make byzantine
|
||||
css[i].decideProposal = func(j int) func(int, int) {
|
||||
return func(height, round int) {
|
||||
|
@ -257,51 +259,42 @@ func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
|
|||
// byzantine privValidator
|
||||
|
||||
type ByzantinePrivValidator struct {
|
||||
Address []byte `json:"address"`
|
||||
types.Signer `json:"-"`
|
||||
types.Signer
|
||||
|
||||
mtx sync.Mutex
|
||||
pv types.PrivValidator
|
||||
}
|
||||
|
||||
// Return a priv validator that will sign anything
|
||||
func NewByzantinePrivValidator(pv *types.PrivValidator) *ByzantinePrivValidator {
|
||||
func NewByzantinePrivValidator(pv types.PrivValidator) *ByzantinePrivValidator {
|
||||
return &ByzantinePrivValidator{
|
||||
Address: pv.Address,
|
||||
Signer: pv.Signer,
|
||||
Signer: pv.(*types.PrivValidatorFS).Signer,
|
||||
pv: pv,
|
||||
}
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) GetAddress() []byte {
|
||||
return privVal.Address
|
||||
func (privVal *ByzantinePrivValidator) GetAddress() data.Bytes {
|
||||
return privVal.pv.GetAddress()
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) GetPubKey() crypto.PubKey {
|
||||
return privVal.pv.GetPubKey()
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) (err error) {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
|
||||
// Sign
|
||||
vote.Signature, err = privVal.Sign(types.SignBytes(chainID, vote))
|
||||
return err
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignProposal(chainID string, proposal *types.Proposal) (err error) {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
|
||||
// Sign
|
||||
proposal.Signature, err = privVal.Sign(types.SignBytes(chainID, proposal))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat *types.Heartbeat) (err error) {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
|
||||
// Sign
|
||||
heartbeat.Signature, err = privVal.Sign(types.SignBytes(chainID, heartbeat))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) String() string {
|
||||
return Fmt("PrivValidator{%X}", privVal.Address)
|
||||
return Fmt("PrivValidator{%X}", privVal.GetAddress())
|
||||
}
|
||||
|
|
|
@ -50,12 +50,12 @@ type validatorStub struct {
|
|||
Index int // Validator index. NOTE: we don't assume validator set changes.
|
||||
Height int
|
||||
Round int
|
||||
*types.PrivValidator
|
||||
types.PrivValidator
|
||||
}
|
||||
|
||||
var testMinPower = 10
|
||||
|
||||
func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validatorStub {
|
||||
func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validatorStub {
|
||||
return &validatorStub{
|
||||
Index: valIndex,
|
||||
PrivValidator: privValidator,
|
||||
|
@ -65,7 +65,7 @@ func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validat
|
|||
func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
||||
vote := &types.Vote{
|
||||
ValidatorIndex: vs.Index,
|
||||
ValidatorAddress: vs.PrivValidator.Address,
|
||||
ValidatorAddress: vs.PrivValidator.GetAddress(),
|
||||
Height: vs.Height,
|
||||
Round: vs.Round,
|
||||
Type: voteType,
|
||||
|
@ -142,7 +142,7 @@ func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.P
|
|||
func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
|
||||
prevotes := cs.Votes.Prevotes(round)
|
||||
var vote *types.Vote
|
||||
if vote = prevotes.GetByAddress(privVal.Address); vote == nil {
|
||||
if vote = prevotes.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
panic("Failed to find prevote from validator")
|
||||
}
|
||||
if blockHash == nil {
|
||||
|
@ -159,7 +159,7 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *valid
|
|||
func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
|
||||
votes := cs.LastCommit
|
||||
var vote *types.Vote
|
||||
if vote = votes.GetByAddress(privVal.Address); vote == nil {
|
||||
if vote = votes.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
panic("Failed to find precommit from validator")
|
||||
}
|
||||
if !bytes.Equal(vote.BlockID.Hash, blockHash) {
|
||||
|
@ -170,7 +170,7 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS
|
|||
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
|
||||
precommits := cs.Votes.Precommits(thisRound)
|
||||
var vote *types.Vote
|
||||
if vote = precommits.GetByAddress(privVal.Address); vote == nil {
|
||||
if vote = precommits.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
panic("Failed to find precommit from validator")
|
||||
}
|
||||
|
||||
|
@ -225,11 +225,11 @@ func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
|
|||
//-------------------------------------------------------------------------------
|
||||
// consensus states
|
||||
|
||||
func newConsensusState(state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
|
||||
func newConsensusState(state *sm.State, pv types.PrivValidator, app abci.Application) *ConsensusState {
|
||||
return newConsensusStateWithConfig(config, state, pv, app)
|
||||
}
|
||||
|
||||
func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
|
||||
func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv types.PrivValidator, app abci.Application) *ConsensusState {
|
||||
// Get BlockStore
|
||||
blockDB := dbm.NewMemDB()
|
||||
blockStore := bc.NewBlockStore(blockDB)
|
||||
|
@ -258,17 +258,17 @@ func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv *ty
|
|||
return cs
|
||||
}
|
||||
|
||||
func loadPrivValidator(config *cfg.Config) *types.PrivValidator {
|
||||
func loadPrivValidator(config *cfg.Config) *types.PrivValidatorFS {
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
ensureDir(path.Dir(privValidatorFile), 0700)
|
||||
privValidator := types.LoadOrGenPrivValidator(privValidatorFile, log.TestingLogger())
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
privValidator.Reset()
|
||||
return privValidator
|
||||
}
|
||||
|
||||
func fixedConsensusStateDummy() *ConsensusState {
|
||||
stateDB := dbm.NewMemDB()
|
||||
state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
state, _ := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
state.SetLogger(log.TestingLogger().With("module", "state"))
|
||||
privValidator := loadPrivValidator(config)
|
||||
cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
|
||||
|
@ -338,7 +338,7 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou
|
|||
logger := consensusLogger()
|
||||
for i := 0; i < nValidators; i++ {
|
||||
db := dbm.NewMemDB() // each state needs its own db
|
||||
state := sm.MakeGenesisState(db, genDoc)
|
||||
state, _ := sm.MakeGenesisState(db, genDoc)
|
||||
state.SetLogger(logger.With("module", "state", "validator", i))
|
||||
state.Save()
|
||||
thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
|
||||
|
@ -359,18 +359,17 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
|
|||
css := make([]*ConsensusState, nPeers)
|
||||
for i := 0; i < nPeers; i++ {
|
||||
db := dbm.NewMemDB() // each state needs its own db
|
||||
state := sm.MakeGenesisState(db, genDoc)
|
||||
state, _ := sm.MakeGenesisState(db, genDoc)
|
||||
state.SetLogger(log.TestingLogger().With("module", "state"))
|
||||
state.Save()
|
||||
thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
|
||||
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
var privVal *types.PrivValidator
|
||||
var privVal types.PrivValidator
|
||||
if i < nValidators {
|
||||
privVal = privVals[i]
|
||||
} else {
|
||||
privVal = types.GenPrivValidator()
|
||||
_, tempFilePath := Tempfile("priv_validator_")
|
||||
privVal.SetFile(tempFilePath)
|
||||
privVal = types.GenPrivValidatorFS(tempFilePath)
|
||||
}
|
||||
|
||||
css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, appFunc())
|
||||
|
@ -393,9 +392,9 @@ func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
|||
//-------------------------------------------------------------------------------
|
||||
// genesis
|
||||
|
||||
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
|
||||
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidatorFS) {
|
||||
validators := make([]types.GenesisValidator, numValidators)
|
||||
privValidators := make([]*types.PrivValidator, numValidators)
|
||||
privValidators := make([]*types.PrivValidatorFS, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privVal := types.RandValidator(randPower, minPower)
|
||||
validators[i] = types.GenesisValidator{
|
||||
|
@ -412,10 +411,10 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
|||
}, privValidators
|
||||
}
|
||||
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidatorFS) {
|
||||
genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
|
||||
db := dbm.NewMemDB()
|
||||
s0 := sm.MakeGenesisState(db, genDoc)
|
||||
s0, _ := sm.MakeGenesisState(db, genDoc)
|
||||
s0.SetLogger(log.TestingLogger().With("module", "state"))
|
||||
s0.Save()
|
||||
return s0, privValidators
|
||||
|
|
|
@ -44,10 +44,10 @@ func TestPeerCatchupRounds(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func makeVoteHR(t *testing.T, height, round int, privVals []*types.PrivValidator, valIndex int) *types.Vote {
|
||||
func makeVoteHR(t *testing.T, height, round int, privVals []*types.PrivValidatorFS, valIndex int) *types.Vote {
|
||||
privVal := privVals[valIndex]
|
||||
vote := &types.Vote{
|
||||
ValidatorAddress: privVal.Address,
|
||||
ValidatorAddress: privVal.GetAddress(),
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
|
|
|
@ -132,7 +132,7 @@ func TestVotingPowerChange(t *testing.T) {
|
|||
//---------------------------------------------------------------------------
|
||||
t.Log("---------------------------- Testing changing the voting power of one validator a few times")
|
||||
|
||||
val1PubKey := css[0].privValidator.(*types.PrivValidator).PubKey
|
||||
val1PubKey := css[0].privValidator.GetPubKey()
|
||||
updateValidatorTx := dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 25)
|
||||
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||
|
||||
|
@ -193,7 +193,7 @@ func TestValidatorSetChanges(t *testing.T) {
|
|||
//---------------------------------------------------------------------------
|
||||
t.Log("---------------------------- Testing adding one validator")
|
||||
|
||||
newValidatorPubKey1 := css[nVals].privValidator.(*types.PrivValidator).PubKey
|
||||
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||
newValidatorTx1 := dummy.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), uint64(testMinPower))
|
||||
|
||||
// wait till everyone makes block 2
|
||||
|
@ -219,7 +219,7 @@ func TestValidatorSetChanges(t *testing.T) {
|
|||
//---------------------------------------------------------------------------
|
||||
t.Log("---------------------------- Testing changing the voting power of one validator")
|
||||
|
||||
updateValidatorPubKey1 := css[nVals].privValidator.(*types.PrivValidator).PubKey
|
||||
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||
updateValidatorTx1 := dummy.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25)
|
||||
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
|
||||
|
||||
|
@ -235,10 +235,10 @@ func TestValidatorSetChanges(t *testing.T) {
|
|||
//---------------------------------------------------------------------------
|
||||
t.Log("---------------------------- Testing adding two validators at once")
|
||||
|
||||
newValidatorPubKey2 := css[nVals+1].privValidator.(*types.PrivValidator).PubKey
|
||||
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
|
||||
newValidatorTx2 := dummy.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), uint64(testMinPower))
|
||||
|
||||
newValidatorPubKey3 := css[nVals+2].privValidator.(*types.PrivValidator).PubKey
|
||||
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
|
||||
newValidatorTx3 := dummy.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), uint64(testMinPower))
|
||||
|
||||
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
|
||||
|
|
|
@ -241,12 +241,15 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo
|
|||
|
||||
// Get State
|
||||
stateDB := dbm.NewDB("state", config.DBBackend, config.DBDir())
|
||||
state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
state, err := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
|
||||
// Create proxyAppConn connection (consensus, mempool, query)
|
||||
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
|
||||
proxyApp := proxy.NewAppConns(clientCreator, NewHandshaker(state, blockStore))
|
||||
_, err := proxyApp.Start()
|
||||
_, err = proxyApp.Start()
|
||||
if err != nil {
|
||||
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))
|
||||
}
|
||||
|
|
|
@ -162,8 +162,8 @@ LOOP:
|
|||
cs.Wait()
|
||||
}
|
||||
|
||||
func toPV(pv PrivValidator) *types.PrivValidator {
|
||||
return pv.(*types.PrivValidator)
|
||||
func toPV(pv types.PrivValidator) *types.PrivValidatorFS {
|
||||
return pv.(*types.PrivValidatorFS)
|
||||
}
|
||||
|
||||
func setupReplayTest(t *testing.T, thisCase *testCase, nLines int, crashAfter bool) (*ConsensusState, chan interface{}, string, string) {
|
||||
|
@ -317,7 +317,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
|||
walFile := writeWAL(string(walBody))
|
||||
config.Consensus.SetWalFile(walFile)
|
||||
|
||||
privVal := types.LoadPrivValidator(config.PrivValidatorFile())
|
||||
privVal := types.LoadPrivValidatorFS(config.PrivValidatorFile())
|
||||
|
||||
wal, err := NewWAL(walFile, false)
|
||||
if err != nil {
|
||||
|
@ -332,7 +332,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
|||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
state, store := stateAndStore(config, privVal.PubKey)
|
||||
state, store := stateAndStore(config, privVal.GetPubKey())
|
||||
store.chain = chain
|
||||
store.commits = commits
|
||||
|
||||
|
@ -346,7 +346,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
|||
// run nBlocks against a new client to build up the app state.
|
||||
// use a throwaway tendermint state
|
||||
proxyApp := proxy.NewAppConns(clientCreator2, nil)
|
||||
state, _ := stateAndStore(config, privVal.PubKey)
|
||||
state, _ := stateAndStore(config, privVal.GetPubKey())
|
||||
buildAppStateFromChain(proxyApp, state, chain, nBlocks, mode)
|
||||
}
|
||||
|
||||
|
@ -558,7 +558,7 @@ func readPieceFromWAL(msgBytes []byte) (interface{}, error) {
|
|||
// fresh state and mock store
|
||||
func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBlockStore) {
|
||||
stateDB := dbm.NewMemDB()
|
||||
state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
state, _ := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
|
||||
state.SetLogger(log.TestingLogger().With("module", "state"))
|
||||
|
||||
store := NewMockBlockStore(config, state.Params())
|
||||
|
|
|
@ -180,14 +180,6 @@ func (ti *timeoutInfo) String() string {
|
|||
return fmt.Sprintf("%v ; %d/%d %v", ti.Duration, ti.Height, ti.Round, ti.Step)
|
||||
}
|
||||
|
||||
// PrivValidator is a validator that can sign votes and proposals.
|
||||
type PrivValidator interface {
|
||||
GetAddress() []byte
|
||||
SignVote(chainID string, vote *types.Vote) error
|
||||
SignProposal(chainID string, proposal *types.Proposal) error
|
||||
SignHeartbeat(chainID string, heartbeat *types.Heartbeat) error
|
||||
}
|
||||
|
||||
// ConsensusState handles execution of the consensus algorithm.
|
||||
// It processes votes and proposals, and upon reaching agreement,
|
||||
// commits blocks to the chain and executes them against the application.
|
||||
|
@ -197,7 +189,7 @@ type ConsensusState struct {
|
|||
|
||||
// config details
|
||||
config *cfg.ConsensusConfig
|
||||
privValidator PrivValidator // for signing votes
|
||||
privValidator types.PrivValidator // for signing votes
|
||||
|
||||
// services for creating and executing blocks
|
||||
proxyAppConn proxy.AppConnConsensus
|
||||
|
@ -308,7 +300,7 @@ func (cs *ConsensusState) GetValidators() (int, []*types.Validator) {
|
|||
}
|
||||
|
||||
// SetPrivValidator sets the private validator account for signing votes.
|
||||
func (cs *ConsensusState) SetPrivValidator(priv PrivValidator) {
|
||||
func (cs *ConsensusState) SetPrivValidator(priv types.PrivValidator) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
cs.privValidator = priv
|
||||
|
|
|
@ -79,7 +79,7 @@ func TestProposerSelection0(t *testing.T) {
|
|||
<-newRoundCh
|
||||
|
||||
prop = cs1.GetRoundState().Validators.GetProposer()
|
||||
if !bytes.Equal(prop.Address, vss[1].Address) {
|
||||
if !bytes.Equal(prop.Address, vss[1].GetAddress()) {
|
||||
panic(Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address))
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func TestProposerSelection2(t *testing.T) {
|
|||
// everyone just votes nil. we get a new proposer each round
|
||||
for i := 0; i < len(vss); i++ {
|
||||
prop := cs1.GetRoundState().Validators.GetProposer()
|
||||
if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].Address) {
|
||||
if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].GetAddress()) {
|
||||
panic(Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
|
||||
}
|
||||
|
||||
|
@ -502,8 +502,6 @@ func TestLockPOLRelock(t *testing.T) {
|
|||
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
|
||||
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlockHeader(), 1)
|
||||
|
||||
t.Logf("vs2 last round %v", vs2.PrivValidator.LastRound)
|
||||
|
||||
// everything done from perspective of cs1
|
||||
|
||||
/*
|
||||
|
|
148
node/node.go
148
node/node.go
|
@ -3,6 +3,7 @@ package node
|
|||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -10,11 +11,15 @@ import (
|
|||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
bc "github.com/tendermint/tendermint/blockchain"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/consensus"
|
||||
mempl "github.com/tendermint/tendermint/mempool"
|
||||
p2p "github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
rpccore "github.com/tendermint/tendermint/rpc/core"
|
||||
grpccore "github.com/tendermint/tendermint/rpc/grpc"
|
||||
|
@ -26,20 +31,66 @@ import (
|
|||
"github.com/tendermint/tendermint/state/txindex/null"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// DBContext specifies config information for loading a new DB.
|
||||
type DBContext struct {
|
||||
ID string
|
||||
Config *cfg.Config
|
||||
}
|
||||
|
||||
// DBProvider takes a DBContext and returns an instantiated DB.
|
||||
type DBProvider func(*DBContext) (dbm.DB, error)
|
||||
|
||||
// DefaultDBProvider returns a database using the DBBackend and DBDir
|
||||
// specified in the ctx.Config.
|
||||
func DefaultDBProvider(ctx *DBContext) (dbm.DB, error) {
|
||||
return dbm.NewDB(ctx.ID, ctx.Config.DBBackend, ctx.Config.DBDir()), nil
|
||||
}
|
||||
|
||||
// GenesisDocProvider returns a GenesisDoc.
|
||||
// It allows the GenesisDoc to be pulled from sources other than the
|
||||
// filesystem, for instance from a distributed key-value store cluster.
|
||||
type GenesisDocProvider func() (*types.GenesisDoc, error)
|
||||
|
||||
// DefaultGenesisDocProviderFunc returns a GenesisDocProvider that loads
|
||||
// the GenesisDoc from the config.GenesisFile() on the filesystem.
|
||||
func DefaultGenesisDocProviderFunc(config *cfg.Config) GenesisDocProvider {
|
||||
return func() (*types.GenesisDoc, error) {
|
||||
return types.GenesisDocFromFile(config.GenesisFile())
|
||||
}
|
||||
}
|
||||
|
||||
// NodeProvider takes a config and a logger and returns a ready to go Node.
|
||||
type NodeProvider func(*cfg.Config, log.Logger) (*Node, error)
|
||||
|
||||
// DefaultNewNode returns a Tendermint node with default settings for the
|
||||
// PrivValidator, ClientCreator, GenesisDoc, and DBProvider.
|
||||
// It implements NodeProvider.
|
||||
func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
|
||||
return NewNode(config,
|
||||
types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile()),
|
||||
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
|
||||
DefaultGenesisDocProviderFunc(config),
|
||||
DefaultDBProvider,
|
||||
logger)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Node is the highest level interface to a full Tendermint node.
|
||||
// It includes all configuration information and running services.
|
||||
type Node struct {
|
||||
cmn.BaseService
|
||||
|
||||
// config
|
||||
config *cfg.Config
|
||||
genesisDoc *types.GenesisDoc // initial validator set
|
||||
privValidator *types.PrivValidator // local node's validator key
|
||||
genesisDoc *types.GenesisDoc // initial validator set
|
||||
privValidator types.PrivValidator // local node's validator key
|
||||
|
||||
// network
|
||||
privKey crypto.PrivKeyEd25519 // local node's p2p key
|
||||
|
@ -58,24 +109,42 @@ type Node struct {
|
|||
txIndexer txindex.TxIndexer
|
||||
}
|
||||
|
||||
func NewNodeDefault(config *cfg.Config, logger log.Logger) *Node {
|
||||
// Get PrivValidator
|
||||
privValidator := types.LoadOrGenPrivValidator(config.PrivValidatorFile(), logger)
|
||||
return NewNode(config, privValidator,
|
||||
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), logger)
|
||||
}
|
||||
// NewNode returns a new, ready to go, Tendermint Node.
|
||||
func NewNode(config *cfg.Config,
|
||||
privValidator types.PrivValidator,
|
||||
clientCreator proxy.ClientCreator,
|
||||
genesisDocProvider GenesisDocProvider,
|
||||
dbProvider DBProvider,
|
||||
logger log.Logger) (*Node, error) {
|
||||
|
||||
func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreator proxy.ClientCreator, logger log.Logger) *Node {
|
||||
// Get BlockStore
|
||||
blockStoreDB := dbm.NewDB("blockstore", config.DBBackend, config.DBDir())
|
||||
blockStoreDB, err := dbProvider(&DBContext{"blockstore", config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockStore := bc.NewBlockStore(blockStoreDB)
|
||||
|
||||
consensusLogger := logger.With("module", "consensus")
|
||||
stateLogger := logger.With("module", "state")
|
||||
|
||||
// Get State
|
||||
stateDB := dbm.NewDB("state", config.DBBackend, config.DBDir())
|
||||
state := sm.GetState(stateDB, config.GenesisFile())
|
||||
stateDB, err := dbProvider(&DBContext{"state", config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state := sm.LoadState(stateDB)
|
||||
if state == nil {
|
||||
genDoc, err := genesisDocProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = sm.MakeGenesisState(stateDB, genDoc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state.Save()
|
||||
}
|
||||
|
||||
state.SetLogger(stateLogger)
|
||||
|
||||
// Create the proxyApp, which manages connections (consensus, mempool, query)
|
||||
|
@ -85,7 +154,7 @@ func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreat
|
|||
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
|
||||
proxyApp.SetLogger(logger.With("module", "proxy"))
|
||||
if _, err := proxyApp.Start(); err != nil {
|
||||
cmn.Exit(cmn.Fmt("Error starting proxy app connections: %v", err))
|
||||
return nil, fmt.Errorf("Error starting proxy app connections: %v", err)
|
||||
}
|
||||
|
||||
// reload the state (it may have been updated by the handshake)
|
||||
|
@ -96,7 +165,10 @@ func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreat
|
|||
var txIndexer txindex.TxIndexer
|
||||
switch config.TxIndex {
|
||||
case "kv":
|
||||
store := dbm.NewDB("tx_index", config.DBBackend, config.DBDir())
|
||||
store, err := dbProvider(&DBContext{"tx_index", config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txIndexer = kv.NewTxIndex(store)
|
||||
default:
|
||||
txIndexer = &null.TxIndex{}
|
||||
|
@ -109,9 +181,8 @@ func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreat
|
|||
// Make event switch
|
||||
eventSwitch := types.NewEventSwitch()
|
||||
eventSwitch.SetLogger(logger.With("module", "types"))
|
||||
_, err := eventSwitch.Start()
|
||||
if err != nil {
|
||||
cmn.Exit(cmn.Fmt("Failed to start switch: %v", err))
|
||||
if _, err := eventSwitch.Start(); err != nil {
|
||||
return nil, fmt.Errorf("Failed to start switch: %v", err)
|
||||
}
|
||||
|
||||
// Decide whether to fast-sync or not
|
||||
|
@ -119,13 +190,13 @@ func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreat
|
|||
fastSync := config.FastSync
|
||||
if state.Validators.Size() == 1 {
|
||||
addr, _ := state.Validators.GetByIndex(0)
|
||||
if bytes.Equal(privValidator.Address, addr) {
|
||||
if bytes.Equal(privValidator.GetAddress(), addr) {
|
||||
fastSync = false
|
||||
}
|
||||
}
|
||||
|
||||
// Log whether this node is a validator or an observer
|
||||
if state.Validators.HasAddress(privValidator.Address) {
|
||||
if state.Validators.HasAddress(privValidator.GetAddress()) {
|
||||
consensusLogger.Info("This node is a validator")
|
||||
} else {
|
||||
consensusLogger.Info("This node is not a validator")
|
||||
|
@ -232,9 +303,10 @@ func NewNode(config *cfg.Config, privValidator *types.PrivValidator, clientCreat
|
|||
txIndexer: txIndexer,
|
||||
}
|
||||
node.BaseService = *cmn.NewBaseService(logger, "Node", node)
|
||||
return node
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// OnStart starts the Node. It implements cmn.Service.
|
||||
func (n *Node) OnStart() error {
|
||||
// Create & add listener
|
||||
protocol, address := ProtocolAndAddress(n.config.P2P.ListenAddress)
|
||||
|
@ -270,6 +342,7 @@ func (n *Node) OnStart() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// OnStop stops the Node. It implements cmn.Service.
|
||||
func (n *Node) OnStop() {
|
||||
n.BaseService.OnStop()
|
||||
|
||||
|
@ -285,6 +358,7 @@ func (n *Node) OnStop() {
|
|||
}
|
||||
}
|
||||
|
||||
// RunForever waits for an interupt signal and stops the node.
|
||||
func (n *Node) RunForever() {
|
||||
// Sleep forever and then...
|
||||
cmn.TrapSignal(func() {
|
||||
|
@ -292,15 +366,15 @@ func (n *Node) RunForever() {
|
|||
})
|
||||
}
|
||||
|
||||
// Add the event switch to reactors, mempool, etc.
|
||||
// SetEventSwitch adds the event switch to reactors, mempool, etc.
|
||||
func SetEventSwitch(evsw types.EventSwitch, eventables ...types.Eventable) {
|
||||
for _, e := range eventables {
|
||||
e.SetEventSwitch(evsw)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a Listener to accept inbound peer connections.
|
||||
// Add listeners before starting the Node.
|
||||
// AddListener adds a listener to accept inbound peer connections.
|
||||
// It should be called before starting the Node.
|
||||
// The first listener is the primary listener (in NodeInfo)
|
||||
func (n *Node) AddListener(l p2p.Listener) {
|
||||
n.sw.AddListener(l)
|
||||
|
@ -314,7 +388,7 @@ func (n *Node) ConfigureRPC() {
|
|||
rpccore.SetConsensusState(n.consensusState)
|
||||
rpccore.SetMempool(n.mempoolReactor.Mempool)
|
||||
rpccore.SetSwitch(n.sw)
|
||||
rpccore.SetPubKey(n.privValidator.PubKey)
|
||||
rpccore.SetPubKey(n.privValidator.GetPubKey())
|
||||
rpccore.SetGenesisDoc(n.genesisDoc)
|
||||
rpccore.SetAddrBook(n.addrBook)
|
||||
rpccore.SetProxyAppQuery(n.proxyApp.Query())
|
||||
|
@ -360,39 +434,48 @@ func (n *Node) startRPC() ([]net.Listener, error) {
|
|||
return listeners, nil
|
||||
}
|
||||
|
||||
// Switch returns the Node's Switch.
|
||||
func (n *Node) Switch() *p2p.Switch {
|
||||
return n.sw
|
||||
}
|
||||
|
||||
// BlockStore returns the Node's BlockStore.
|
||||
func (n *Node) BlockStore() *bc.BlockStore {
|
||||
return n.blockStore
|
||||
}
|
||||
|
||||
// ConsensusState returns the Node's ConsensusState.
|
||||
func (n *Node) ConsensusState() *consensus.ConsensusState {
|
||||
return n.consensusState
|
||||
}
|
||||
|
||||
// ConsensusReactor returns the Node's ConsensusReactor.
|
||||
func (n *Node) ConsensusReactor() *consensus.ConsensusReactor {
|
||||
return n.consensusReactor
|
||||
}
|
||||
|
||||
// MempoolReactor returns the Node's MempoolReactor.
|
||||
func (n *Node) MempoolReactor() *mempl.MempoolReactor {
|
||||
return n.mempoolReactor
|
||||
}
|
||||
|
||||
// EventSwitch returns the Node's EventSwitch.
|
||||
func (n *Node) EventSwitch() types.EventSwitch {
|
||||
return n.evsw
|
||||
}
|
||||
|
||||
// XXX: for convenience
|
||||
func (n *Node) PrivValidator() *types.PrivValidator {
|
||||
// PrivValidator returns the Node's PrivValidator.
|
||||
// XXX: for convenience only!
|
||||
func (n *Node) PrivValidator() types.PrivValidator {
|
||||
return n.privValidator
|
||||
}
|
||||
|
||||
// GenesisDoc returns the Node's GenesisDoc.
|
||||
func (n *Node) GenesisDoc() *types.GenesisDoc {
|
||||
return n.genesisDoc
|
||||
}
|
||||
|
||||
// ProxyApp returns the Node's AppConns, representing its connections to the ABCI application.
|
||||
func (n *Node) ProxyApp() proxy.AppConns {
|
||||
return n.proxyApp
|
||||
}
|
||||
|
@ -442,15 +525,18 @@ func (n *Node) makeNodeInfo() *p2p.NodeInfo {
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// NodeInfo returns the Node's Info from the Switch.
|
||||
func (n *Node) NodeInfo() *p2p.NodeInfo {
|
||||
return n.sw.NodeInfo()
|
||||
}
|
||||
|
||||
// DialSeeds dials the given seeds on the Switch.
|
||||
func (n *Node) DialSeeds(seeds []string) error {
|
||||
return n.sw.DialSeeds(n.addrBook, seeds)
|
||||
}
|
||||
|
||||
// Defaults to tcp
|
||||
// ProtocolAndAddress returns the transport protocol
|
||||
// and the ip address from the given string. Defaults to tcp.
|
||||
func ProtocolAndAddress(listenAddr string) (string, string) {
|
||||
protocol, address := "tcp", listenAddr
|
||||
parts := strings.SplitN(address, "://", 2)
|
||||
|
|
|
@ -4,15 +4,19 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
)
|
||||
|
||||
func TestNodeStartStop(t *testing.T) {
|
||||
config := cfg.ResetTestRoot("node_node_test")
|
||||
|
||||
// Create & start node
|
||||
n := NewNodeDefault(config, log.TestingLogger())
|
||||
n, err := DefaultNewNode(config, log.TestingLogger())
|
||||
assert.NoError(t, err, "expected no err on DefaultNewNode")
|
||||
n.Start()
|
||||
t.Logf("Started node %v", n.sw.NodeInfo())
|
||||
|
||||
|
|
|
@ -79,8 +79,13 @@ 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.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
papp := proxy.NewLocalClientCreator(app)
|
||||
node := nm.NewNode(config, privValidator, papp, logger)
|
||||
node, err := nm.NewNode(config, privValidator, papp,
|
||||
nm.DefaultGenesisDocProviderFunc(config),
|
||||
nm.DefaultDBProvider, logger)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
|
|
@ -55,13 +55,14 @@ func makeTxs(blockNum int) (txs []types.Tx) {
|
|||
}
|
||||
|
||||
func state() *State {
|
||||
return MakeGenesisState(dbm.NewMemDB(), &types.GenesisDoc{
|
||||
s, _ := MakeGenesisState(dbm.NewMemDB(), &types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: []types.GenesisValidator{
|
||||
types.GenesisValidator{privKey.PubKey(), 10000, "test"},
|
||||
},
|
||||
AppHash: nil,
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
func makeBlock(num int, state *State) *types.Block {
|
||||
|
|
|
@ -68,14 +68,17 @@ type State struct {
|
|||
// GetState loads the most recent state from the database,
|
||||
// or creates a new one from the given genesisFile and persists the result
|
||||
// to the database.
|
||||
func GetState(stateDB dbm.DB, genesisFile string) *State {
|
||||
func GetState(stateDB dbm.DB, genesisFile string) (*State, error) {
|
||||
var err error
|
||||
state := LoadState(stateDB)
|
||||
if state == nil {
|
||||
state = MakeGenesisStateFromFile(stateDB, genesisFile)
|
||||
state, err = MakeGenesisStateFromFile(stateDB, genesisFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state.Save()
|
||||
}
|
||||
|
||||
return state
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// LoadState loads the State from the database.
|
||||
|
@ -316,25 +319,34 @@ func (vi *ValidatorsInfo) Bytes() []byte {
|
|||
// file.
|
||||
//
|
||||
// Used during replay and in tests.
|
||||
func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
|
||||
func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) (*State, error) {
|
||||
genDoc, err := MakeGenesisDocFromFile(genDocFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return MakeGenesisState(db, genDoc)
|
||||
}
|
||||
|
||||
// MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
|
||||
func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
|
||||
genDocJSON, err := ioutil.ReadFile(genDocFile)
|
||||
if err != nil {
|
||||
cmn.Exit(cmn.Fmt("Couldn't read GenesisDoc file: %v", err))
|
||||
return nil, fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
|
||||
}
|
||||
genDoc, err := types.GenesisDocFromJSON(genDocJSON)
|
||||
if err != nil {
|
||||
cmn.Exit(cmn.Fmt("Error reading GenesisDoc: %v", err))
|
||||
return nil, fmt.Errorf("Error reading GenesisDoc: %v", err)
|
||||
}
|
||||
return MakeGenesisState(db, genDoc)
|
||||
return genDoc, nil
|
||||
}
|
||||
|
||||
// MakeGenesisState creates state from types.GenesisDoc.
|
||||
//
|
||||
// Used in tests.
|
||||
func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
|
||||
func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) (*State, error) {
|
||||
err := genDoc.ValidateAndComplete()
|
||||
if err != nil {
|
||||
cmn.Exit(cmn.Fmt("Error in genesis file: %v", err))
|
||||
return nil, fmt.Errorf("Error in genesis file: %v", err)
|
||||
}
|
||||
|
||||
// Make validators slice
|
||||
|
@ -363,5 +375,5 @@ func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
|
|||
AppHash: genDoc.AppHash,
|
||||
TxIndexer: &null.TxIndex{}, // we do not need indexer during replay and in tests
|
||||
LastHeightValidatorsChanged: 1,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ import (
|
|||
func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, *State) {
|
||||
config := cfg.ResetTestRoot("state_")
|
||||
stateDB := dbm.NewDB("state", config.DBBackend, config.DBDir())
|
||||
state := GetState(stateDB, config.GenesisFile())
|
||||
state, err := GetState(stateDB, config.GenesisFile())
|
||||
assert.NoError(t, err, "expected no error on GetState")
|
||||
state.SetLogger(log.TestingLogger())
|
||||
|
||||
tearDown := func(t *testing.T) {}
|
||||
|
|
|
@ -11,8 +11,7 @@ import (
|
|||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
data "github.com/tendermint/go-wire/data"
|
||||
. "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
// TODO: type ?
|
||||
|
@ -30,12 +29,26 @@ func voteToStep(vote *Vote) int8 {
|
|||
case VoteTypePrecommit:
|
||||
return stepPrecommit
|
||||
default:
|
||||
PanicSanity("Unknown vote type")
|
||||
cmn.PanicSanity("Unknown vote type")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
type PrivValidator struct {
|
||||
// PrivValidator defines the functionality of a local Tendermint validator
|
||||
// that signs votes, proposals, and heartbeats, and never double signs.
|
||||
type PrivValidator interface {
|
||||
GetAddress() data.Bytes // redundant since .PubKey().Address()
|
||||
GetPubKey() crypto.PubKey
|
||||
|
||||
SignVote(chainID string, vote *Vote) error
|
||||
SignProposal(chainID string, proposal *Proposal) error
|
||||
SignHeartbeat(chainID string, heartbeat *Heartbeat) error
|
||||
}
|
||||
|
||||
// PrivValidatorFS implements PrivValidator using data persisted to disk
|
||||
// to prevent double signing. The Signer itself can be mutated to use
|
||||
// something besides the default, for instance a hardware signer.
|
||||
type PrivValidatorFS struct {
|
||||
Address data.Bytes `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
LastHeight int `json:"last_height"`
|
||||
|
@ -54,121 +67,124 @@ type PrivValidator struct {
|
|||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
// This is used to sign votes.
|
||||
// Signer is an interface that defines how to sign messages.
|
||||
// It is the caller's duty to verify the msg before calling Sign,
|
||||
// eg. to avoid double signing.
|
||||
// Currently, the only callers are SignVote and SignProposal
|
||||
// Currently, the only callers are SignVote, SignProposal, and SignHeartbeat.
|
||||
type Signer interface {
|
||||
PubKey() crypto.PubKey
|
||||
Sign(msg []byte) (crypto.Signature, error)
|
||||
}
|
||||
|
||||
// Implements Signer
|
||||
// DefaultSigner implements Signer.
|
||||
// It uses a standard, unencrypted crypto.PrivKey.
|
||||
type DefaultSigner struct {
|
||||
priv crypto.PrivKey
|
||||
PrivKey crypto.PrivKey `json:"priv_key"`
|
||||
}
|
||||
|
||||
// NewDefaultSigner returns an instance of DefaultSigner.
|
||||
func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner {
|
||||
return &DefaultSigner{priv: priv}
|
||||
return &DefaultSigner{
|
||||
PrivKey: priv,
|
||||
}
|
||||
}
|
||||
|
||||
// Implements Signer
|
||||
// Sign implements Signer. It signs the byte slice with a private key.
|
||||
func (ds *DefaultSigner) Sign(msg []byte) (crypto.Signature, error) {
|
||||
return ds.priv.Sign(msg), nil
|
||||
return ds.PrivKey.Sign(msg), nil
|
||||
}
|
||||
|
||||
// Implements Signer
|
||||
func (ds *DefaultSigner) PubKey() crypto.PubKey {
|
||||
return ds.priv.PubKey()
|
||||
// GetAddress returns the address of the validator.
|
||||
// Implements PrivValidator.
|
||||
func (pv *PrivValidatorFS) GetAddress() data.Bytes {
|
||||
return pv.Address
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SetSigner(s Signer) {
|
||||
privVal.Signer = s
|
||||
privVal.setPubKeyAndAddress()
|
||||
// GetPubKey returns the public key of the validator.
|
||||
// Implements PrivValidator.
|
||||
func (pv *PrivValidatorFS) GetPubKey() crypto.PubKey {
|
||||
return pv.PubKey
|
||||
}
|
||||
|
||||
// Overwrite address and pubkey for convenience
|
||||
func (privVal *PrivValidator) setPubKeyAndAddress() {
|
||||
privVal.PubKey = privVal.Signer.PubKey()
|
||||
privVal.Address = privVal.PubKey.Address()
|
||||
}
|
||||
|
||||
// Generates a new validator with private key.
|
||||
func GenPrivValidator() *PrivValidator {
|
||||
// GenPrivValidatorFS generates a new validator with randomly generated private key
|
||||
// and sets the filePath, but does not call Save().
|
||||
func GenPrivValidatorFS(filePath string) *PrivValidatorFS {
|
||||
privKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||
pubKey := privKey.PubKey()
|
||||
return &PrivValidator{
|
||||
Address: pubKey.Address(),
|
||||
PubKey: pubKey,
|
||||
return &PrivValidatorFS{
|
||||
Address: privKey.PubKey().Address(),
|
||||
PubKey: privKey.PubKey(),
|
||||
PrivKey: privKey,
|
||||
LastStep: stepNone,
|
||||
filePath: "",
|
||||
Signer: NewDefaultSigner(privKey),
|
||||
filePath: filePath,
|
||||
}
|
||||
}
|
||||
|
||||
func LoadPrivValidator(filePath string) *PrivValidator {
|
||||
// LoadPrivValidatorFS loads a PrivValidatorFS from the filePath.
|
||||
func LoadPrivValidatorFS(filePath string) *PrivValidatorFS {
|
||||
return LoadPrivValidatorFSWithSigner(filePath, func(privVal PrivValidator) Signer {
|
||||
return NewDefaultSigner(privVal.(*PrivValidatorFS).PrivKey)
|
||||
})
|
||||
}
|
||||
|
||||
// LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath
|
||||
// or else generates a new one and saves it to the filePath.
|
||||
func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS {
|
||||
var privVal *PrivValidatorFS
|
||||
if _, err := os.Stat(filePath); err == nil {
|
||||
privVal = LoadPrivValidatorFS(filePath)
|
||||
} else {
|
||||
privVal = GenPrivValidatorFS(filePath)
|
||||
privVal.Save()
|
||||
}
|
||||
return privVal
|
||||
}
|
||||
|
||||
// LoadPrivValidatorWithSigner loads a PrivValidatorFS with a custom
|
||||
// signer object. The PrivValidatorFS handles double signing prevention by persisting
|
||||
// data to the filePath, while the Signer handles the signing.
|
||||
// If the filePath does not exist, the PrivValidatorFS must be created manually and saved.
|
||||
func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(PrivValidator) Signer) *PrivValidatorFS {
|
||||
privValJSONBytes, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
privVal := PrivValidator{}
|
||||
privVal := &PrivValidatorFS{}
|
||||
err = json.Unmarshal(privValJSONBytes, &privVal)
|
||||
if err != nil {
|
||||
Exit(Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
|
||||
cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
|
||||
}
|
||||
|
||||
privVal.filePath = filePath
|
||||
privVal.Signer = NewDefaultSigner(privVal.PrivKey)
|
||||
privVal.setPubKeyAndAddress()
|
||||
return &privVal
|
||||
privVal.Signer = signerFunc(privVal)
|
||||
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)
|
||||
}
|
||||
return privValidator
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SetFile(filePath string) {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
privVal.filePath = filePath
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) Save() {
|
||||
// Save persists the PrivValidatorFS to disk.
|
||||
func (privVal *PrivValidatorFS) Save() {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
privVal.save()
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) save() {
|
||||
func (privVal *PrivValidatorFS) save() {
|
||||
if privVal.filePath == "" {
|
||||
PanicSanity("Cannot save PrivValidator: filePath not set")
|
||||
cmn.PanicSanity("Cannot save PrivValidator: filePath not set")
|
||||
}
|
||||
jsonBytes, err := json.Marshal(privVal)
|
||||
if err != nil {
|
||||
// `@; BOOM!!!
|
||||
PanicCrisis(err)
|
||||
cmn.PanicCrisis(err)
|
||||
}
|
||||
err = WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
|
||||
err = cmn.WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
|
||||
if err != nil {
|
||||
// `@; BOOM!!!
|
||||
PanicCrisis(err)
|
||||
cmn.PanicCrisis(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets all fields in the PrivValidatorFS.
|
||||
// NOTE: Unsafe!
|
||||
func (privVal *PrivValidator) Reset() {
|
||||
func (privVal *PrivValidatorFS) Reset() {
|
||||
privVal.LastHeight = 0
|
||||
privVal.LastRound = 0
|
||||
privVal.LastStep = 0
|
||||
|
@ -177,22 +193,22 @@ func (privVal *PrivValidator) Reset() {
|
|||
privVal.Save()
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) GetAddress() []byte {
|
||||
return privVal.Address
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignVote(chainID string, vote *Vote) error {
|
||||
// SignVote signs a canonical representation of the vote, along with the chainID.
|
||||
// Implements PrivValidator.
|
||||
func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
signature, err := privVal.signBytesHRS(vote.Height, vote.Round, voteToStep(vote), SignBytes(chainID, vote))
|
||||
if err != nil {
|
||||
return errors.New(Fmt("Error signing vote: %v", err))
|
||||
return errors.New(cmn.Fmt("Error signing vote: %v", err))
|
||||
}
|
||||
vote.Signature = signature
|
||||
return nil
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error {
|
||||
// SignProposal signs a canonical representation of the proposal, along with the chainID.
|
||||
// Implements PrivValidator.
|
||||
func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
signature, err := privVal.signBytesHRS(proposal.Height, proposal.Round, stepPropose, SignBytes(chainID, proposal))
|
||||
|
@ -203,8 +219,11 @@ func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) e
|
|||
return nil
|
||||
}
|
||||
|
||||
// check if there's a regression. Else sign and write the hrs+signature to disk
|
||||
func (privVal *PrivValidator) signBytesHRS(height, round int, step int8, signBytes []byte) (crypto.Signature, error) {
|
||||
// signBytesHRS signs the given signBytes if the height/round/step (HRS)
|
||||
// are greater than the latest state. If the HRS are equal,
|
||||
// it returns the privValidator.LastSignature.
|
||||
func (privVal *PrivValidatorFS) signBytesHRS(height, round int, step int8, signBytes []byte) (crypto.Signature, error) {
|
||||
|
||||
sig := crypto.Signature{}
|
||||
// If height regression, err
|
||||
if privVal.LastHeight > height {
|
||||
|
@ -223,7 +242,7 @@ func (privVal *PrivValidator) signBytesHRS(height, round int, step int8, signByt
|
|||
} else if privVal.LastStep == step {
|
||||
if privVal.LastSignBytes != nil {
|
||||
if privVal.LastSignature.Empty() {
|
||||
PanicSanity("privVal: LastSignature is nil but LastSignBytes is not!")
|
||||
cmn.PanicSanity("privVal: LastSignature is nil but LastSignBytes is not!")
|
||||
}
|
||||
// so we dont sign a conflicting vote or proposal
|
||||
// NOTE: proposals are non-deterministic (include time),
|
||||
|
@ -253,10 +272,11 @@ func (privVal *PrivValidator) signBytesHRS(height, round int, step int8, signByt
|
|||
privVal.save()
|
||||
|
||||
return sig, nil
|
||||
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
|
||||
// SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID.
|
||||
// Implements PrivValidator.
|
||||
func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
|
||||
privVal.mtx.Lock()
|
||||
defer privVal.mtx.Unlock()
|
||||
var err error
|
||||
|
@ -264,20 +284,21 @@ func (privVal *PrivValidator) SignHeartbeat(chainID string, heartbeat *Heartbeat
|
|||
return err
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) String() string {
|
||||
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep)
|
||||
// String returns a string representation of the PrivValidatorFS.
|
||||
func (privVal *PrivValidatorFS) String() string {
|
||||
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep)
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type PrivValidatorsByAddress []*PrivValidator
|
||||
type PrivValidatorsByAddress []*PrivValidatorFS
|
||||
|
||||
func (pvs PrivValidatorsByAddress) Len() int {
|
||||
return len(pvs)
|
||||
}
|
||||
|
||||
func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
|
||||
return bytes.Compare(pvs[i].Address, pvs[j].Address) == -1
|
||||
return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1
|
||||
}
|
||||
|
||||
func (pvs PrivValidatorsByAddress) Swap(i, j int) {
|
||||
|
|
|
@ -4,14 +4,44 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
func TestLoadValidator(t *testing.T) {
|
||||
func TestGenLoadValidator(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
privVal := GenPrivValidatorFS(tempFilePath)
|
||||
|
||||
height := 100
|
||||
privVal.LastHeight = height
|
||||
privVal.Save()
|
||||
addr := privVal.GetAddress()
|
||||
|
||||
privVal = LoadPrivValidatorFS(tempFilePath)
|
||||
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
|
||||
assert.Equal(height, privVal.LastHeight, "expected privval.LastHeight to have been saved")
|
||||
}
|
||||
|
||||
func TestLoadOrGenValidator(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
os.Remove(tempFilePath)
|
||||
privVal := LoadOrGenPrivValidatorFS(tempFilePath)
|
||||
addr := privVal.GetAddress()
|
||||
privVal = LoadOrGenPrivValidatorFS(tempFilePath)
|
||||
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
|
||||
}
|
||||
|
||||
func TestUnmarshalValidator(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
// create some fixed values
|
||||
|
@ -34,23 +64,23 @@ func TestLoadValidator(t *testing.T) {
|
|||
"type": "ed25519",
|
||||
"data": "%s"
|
||||
},
|
||||
"priv_key": {
|
||||
"type": "ed25519",
|
||||
"data": "%s"
|
||||
},
|
||||
"last_height": 0,
|
||||
"last_round": 0,
|
||||
"last_step": 0,
|
||||
"last_signature": null
|
||||
"last_signature": null,
|
||||
"priv_key": {
|
||||
"type": "ed25519",
|
||||
"data": "%s"
|
||||
}
|
||||
}`, addrStr, pubStr, privStr)
|
||||
|
||||
val := PrivValidator{}
|
||||
val := PrivValidatorFS{}
|
||||
err = json.Unmarshal([]byte(serialized), &val)
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// make sure the values match
|
||||
assert.EqualValues(addrBytes, val.Address)
|
||||
assert.EqualValues(pubKey, val.PubKey)
|
||||
assert.EqualValues(addrBytes, val.GetAddress())
|
||||
assert.EqualValues(pubKey, val.GetPubKey())
|
||||
assert.EqualValues(privKey, val.PrivKey)
|
||||
|
||||
// export it and make sure it is the same
|
||||
|
@ -58,3 +88,89 @@ func TestLoadValidator(t *testing.T) {
|
|||
require.Nil(err, "%+v", err)
|
||||
assert.JSONEq(serialized, string(out))
|
||||
}
|
||||
|
||||
func TestSignVote(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
privVal := GenPrivValidatorFS(tempFilePath)
|
||||
|
||||
block1 := BlockID{[]byte{1, 2, 3}, PartSetHeader{}}
|
||||
block2 := BlockID{[]byte{3, 2, 1}, PartSetHeader{}}
|
||||
height, round := 10, 1
|
||||
voteType := VoteTypePrevote
|
||||
|
||||
// sign a vote for first time
|
||||
vote := newVote(privVal.Address, 0, height, round, voteType, block1)
|
||||
err := privVal.SignVote("mychainid", vote)
|
||||
assert.NoError(err, "expected no error signing vote")
|
||||
|
||||
// try to sign the same vote again; should be fine
|
||||
err = privVal.SignVote("mychainid", vote)
|
||||
assert.NoError(err, "expected no error on signing same vote")
|
||||
|
||||
// now try some bad votes
|
||||
cases := []*Vote{
|
||||
newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression
|
||||
newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression
|
||||
newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round
|
||||
newVote(privVal.Address, 0, height, round, voteType, block2), // different block
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
err = privVal.SignVote("mychainid", c)
|
||||
assert.Error(err, "expected error on signing conflicting vote")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignProposal(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
privVal := GenPrivValidatorFS(tempFilePath)
|
||||
|
||||
block1 := PartSetHeader{5, []byte{1, 2, 3}}
|
||||
block2 := PartSetHeader{10, []byte{3, 2, 1}}
|
||||
height, round := 10, 1
|
||||
|
||||
// sign a proposal for first time
|
||||
proposal := newProposal(height, round, block1)
|
||||
err := privVal.SignProposal("mychainid", proposal)
|
||||
assert.NoError(err, "expected no error signing proposal")
|
||||
|
||||
// try to sign the same proposal again; should be fine
|
||||
err = privVal.SignProposal("mychainid", proposal)
|
||||
assert.NoError(err, "expected no error on signing same proposal")
|
||||
|
||||
// now try some bad Proposals
|
||||
cases := []*Proposal{
|
||||
newProposal(height, round-1, block1), // round regression
|
||||
newProposal(height-1, round, block1), // height regression
|
||||
newProposal(height-2, round+4, block1), // height regression and different round
|
||||
newProposal(height, round, block2), // different block
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
err = privVal.SignProposal("mychainid", c)
|
||||
assert.Error(err, "expected error on signing conflicting proposal")
|
||||
}
|
||||
}
|
||||
|
||||
func newVote(addr data.Bytes, idx, height, round int, typ byte, blockID BlockID) *Vote {
|
||||
return &Vote{
|
||||
ValidatorAddress: addr,
|
||||
ValidatorIndex: idx,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: typ,
|
||||
BlockID: blockID,
|
||||
}
|
||||
}
|
||||
|
||||
func newProposal(height, round int, partsHeader PartSetHeader) *Proposal {
|
||||
return &Proposal{
|
||||
Height: height,
|
||||
Round: round,
|
||||
BlockPartsHeader: partsHeader,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,17 +28,17 @@ func BenchmarkProposalWriteSignBytes(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkProposalSign(b *testing.B) {
|
||||
privVal := GenPrivValidator()
|
||||
privVal := GenPrivValidatorFS("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
privVal.Sign(SignBytes("test_chain_id", testProposal))
|
||||
privVal.Signer.Sign(SignBytes("test_chain_id", testProposal))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProposalVerifySignature(b *testing.B) {
|
||||
signBytes := SignBytes("test_chain_id", testProposal)
|
||||
privVal := GenPrivValidator()
|
||||
signature, _ := privVal.Sign(signBytes)
|
||||
pubKey := privVal.PubKey
|
||||
privVal := GenPrivValidatorFS("")
|
||||
signature, _ := privVal.Signer.Sign(signBytes)
|
||||
pubKey := privVal.GetPubKey()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
pubKey.VerifyBytes(SignBytes("test_chain_id", testProposal), signature)
|
||||
|
|
|
@ -106,14 +106,13 @@ func (vc validatorCodec) Compare(o1 interface{}, o2 interface{}) int {
|
|||
//--------------------------------------------------------------------------------
|
||||
// For testing...
|
||||
|
||||
func RandValidator(randPower bool, minPower int64) (*Validator, *PrivValidator) {
|
||||
privVal := GenPrivValidator()
|
||||
func RandValidator(randPower bool, minPower int64) (*Validator, *PrivValidatorFS) {
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
privVal.SetFile(tempFilePath)
|
||||
privVal := GenPrivValidatorFS(tempFilePath)
|
||||
votePower := minPower
|
||||
if randPower {
|
||||
votePower += int64(cmn.RandUint32())
|
||||
}
|
||||
val := NewValidator(privVal.PubKey, votePower)
|
||||
val := NewValidator(privVal.GetPubKey(), votePower)
|
||||
return val, privVal
|
||||
}
|
||||
|
|
|
@ -369,9 +369,9 @@ func (ac accumComparable) Less(o interface{}) bool {
|
|||
// For testing
|
||||
|
||||
// NOTE: PrivValidator are in order.
|
||||
func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*PrivValidator) {
|
||||
func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*PrivValidatorFS) {
|
||||
vals := make([]*Validator, numValidators)
|
||||
privValidators := make([]*PrivValidator, numValidators)
|
||||
privValidators := make([]*PrivValidatorFS, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privValidator := RandValidator(false, votingPower)
|
||||
vals[i] = val
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
// NOTE: privValidators are in order
|
||||
func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []*PrivValidator) {
|
||||
func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []*PrivValidatorFS) {
|
||||
valSet, privValidators := RandValidatorSet(numValidators, votingPower)
|
||||
return NewVoteSet("test_chain_id", height, round, type_, valSet), valSet, privValidators
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
|
|||
return vote
|
||||
}
|
||||
|
||||
func signAddVote(privVal *PrivValidator, vote *Vote, voteSet *VoteSet) (bool, error) {
|
||||
func signAddVote(privVal *PrivValidatorFS, vote *Vote, voteSet *VoteSet) (bool, error) {
|
||||
var err error
|
||||
vote.Signature, err = privVal.Sign(SignBytes(voteSet.ChainID(), vote))
|
||||
vote.Signature, err = privVal.Signer.Sign(SignBytes(voteSet.ChainID(), vote))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func TestAddVote(t *testing.T) {
|
|||
|
||||
// t.Logf(">> %v", voteSet)
|
||||
|
||||
if voteSet.GetByAddress(val0.Address) != nil {
|
||||
if voteSet.GetByAddress(val0.GetAddress()) != nil {
|
||||
t.Errorf("Expected GetByAddress(val0.Address) to be nil")
|
||||
}
|
||||
if voteSet.BitArray().GetIndex(0) {
|
||||
|
@ -88,7 +88,7 @@ func TestAddVote(t *testing.T) {
|
|||
}
|
||||
|
||||
vote := &Vote{
|
||||
ValidatorAddress: val0.Address,
|
||||
ValidatorAddress: val0.GetAddress(),
|
||||
ValidatorIndex: 0, // since privValidators are in order
|
||||
Height: height,
|
||||
Round: round,
|
||||
|
@ -100,7 +100,7 @@ func TestAddVote(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if voteSet.GetByAddress(val0.Address) == nil {
|
||||
if voteSet.GetByAddress(val0.GetAddress()) == nil {
|
||||
t.Errorf("Expected GetByAddress(val0.Address) to be present")
|
||||
}
|
||||
if !voteSet.BitArray().GetIndex(0) {
|
||||
|
@ -126,7 +126,7 @@ func Test2_3Majority(t *testing.T) {
|
|||
}
|
||||
// 6 out of 10 voted for nil.
|
||||
for i := 0; i < 6; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].Address, i)
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
signAddVote(privValidators[i], vote, voteSet)
|
||||
}
|
||||
blockID, ok := voteSet.TwoThirdsMajority()
|
||||
|
@ -136,7 +136,7 @@ func Test2_3Majority(t *testing.T) {
|
|||
|
||||
// 7th validator voted for some blockhash
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[6].Address, 6)
|
||||
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6)
|
||||
signAddVote(privValidators[6], withBlockHash(vote, RandBytes(32)), voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
if ok || !blockID.IsZero() {
|
||||
|
@ -146,7 +146,7 @@ func Test2_3Majority(t *testing.T) {
|
|||
|
||||
// 8th validator voted for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[7].Address, 7)
|
||||
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7)
|
||||
signAddVote(privValidators[7], vote, voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
if !ok || !blockID.IsZero() {
|
||||
|
@ -174,7 +174,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 66 out of 100 voted for nil.
|
||||
for i := 0; i < 66; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].Address, i)
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
signAddVote(privValidators[i], vote, voteSet)
|
||||
}
|
||||
blockID, ok := voteSet.TwoThirdsMajority()
|
||||
|
@ -184,7 +184,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 67th validator voted for nil
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[66].Address, 66)
|
||||
vote := withValidator(voteProto, privValidators[66].GetAddress(), 66)
|
||||
signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
if ok || !blockID.IsZero() {
|
||||
|
@ -194,7 +194,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 68th validator voted for a different BlockParts PartSetHeader
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[67].Address, 67)
|
||||
vote := withValidator(voteProto, privValidators[67].GetAddress(), 67)
|
||||
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
|
||||
signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
|
@ -205,7 +205,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 69th validator voted for different BlockParts Total
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[68].Address, 68)
|
||||
vote := withValidator(voteProto, privValidators[68].GetAddress(), 68)
|
||||
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash}
|
||||
signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
|
@ -216,7 +216,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 70th validator voted for different BlockHash
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[69].Address, 69)
|
||||
vote := withValidator(voteProto, privValidators[69].GetAddress(), 69)
|
||||
signAddVote(privValidators[69], withBlockHash(vote, RandBytes(32)), voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
if ok || !blockID.IsZero() {
|
||||
|
@ -226,7 +226,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||
|
||||
// 71st validator voted for the right BlockHash & BlockPartsHeader
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[70].Address, 70)
|
||||
vote := withValidator(voteProto, privValidators[70].GetAddress(), 70)
|
||||
signAddVote(privValidators[70], vote, voteSet)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
if !ok || !blockID.Equals(BlockID{blockHash, blockPartsHeader}) {
|
||||
|
@ -250,7 +250,7 @@ func TestBadVotes(t *testing.T) {
|
|||
|
||||
// val0 votes for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], vote, voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
|
@ -259,7 +259,7 @@ func TestBadVotes(t *testing.T) {
|
|||
|
||||
// val0 votes again for some block.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
|
||||
|
@ -268,7 +268,7 @@ func TestBadVotes(t *testing.T) {
|
|||
|
||||
// val1 votes on another height
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[1].Address, 1)
|
||||
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1)
|
||||
added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong height")
|
||||
|
@ -277,7 +277,7 @@ func TestBadVotes(t *testing.T) {
|
|||
|
||||
// val2 votes on another round
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].Address, 2)
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong round")
|
||||
|
@ -286,7 +286,7 @@ func TestBadVotes(t *testing.T) {
|
|||
|
||||
// val3 votes of another type.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[3].Address, 3)
|
||||
vote := withValidator(voteProto, privValidators[3].GetAddress(), 3)
|
||||
added, err := signAddVote(privValidators[3], withType(vote, VoteTypePrecommit), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
||||
|
@ -311,7 +311,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val0 votes for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], vote, voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
|
@ -320,7 +320,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
|
||||
if added {
|
||||
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
|
||||
|
@ -335,7 +335,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added {
|
||||
t.Errorf("Expected VoteSet.Add to succeed, called SetPeerMaj23().")
|
||||
|
@ -350,7 +350,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].Address, 0)
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
|
||||
if added {
|
||||
t.Errorf("Expected VoteSet.Add to fail, duplicate SetPeerMaj23() from peerA")
|
||||
|
@ -362,7 +362,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val1 votes for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[1].Address, 1)
|
||||
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1)
|
||||
added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
|
@ -379,7 +379,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val2 votes for blockHash2.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].Address, 2)
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
|
@ -399,7 +399,7 @@ func TestConflicts(t *testing.T) {
|
|||
|
||||
// val2 votes for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].Address, 2)
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
|
@ -439,7 +439,7 @@ func TestMakeCommit(t *testing.T) {
|
|||
|
||||
// 6 out of 10 voted for some block.
|
||||
for i := 0; i < 6; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].Address, i)
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
signAddVote(privValidators[i], vote, voteSet)
|
||||
}
|
||||
|
||||
|
@ -448,7 +448,7 @@ func TestMakeCommit(t *testing.T) {
|
|||
|
||||
// 7th voted for some other block.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[6].Address, 6)
|
||||
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6)
|
||||
vote = withBlockHash(vote, RandBytes(32))
|
||||
vote = withBlockPartsHeader(vote, PartSetHeader{123, RandBytes(32)})
|
||||
signAddVote(privValidators[6], vote, voteSet)
|
||||
|
@ -456,7 +456,7 @@ func TestMakeCommit(t *testing.T) {
|
|||
|
||||
// The 8th voted like everyone else.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[7].Address, 7)
|
||||
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7)
|
||||
signAddVote(privValidators[7], vote, voteSet)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue