diff --git a/cmd/tendermint/commands/init.go b/cmd/tendermint/commands/init.go index d8e8bde40..cbafac3ef 100644 --- a/cmd/tendermint/commands/init.go +++ b/cmd/tendermint/commands/init.go @@ -29,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, }} diff --git a/cmd/tendermint/commands/testnet.go b/cmd/tendermint/commands/testnet.go index 7fc4f94fe..ac6f337a9 100644 --- a/cmd/tendermint/commands/testnet.go +++ b/cmd/tendermint/commands/testnet.go @@ -47,7 +47,7 @@ func testnetFiles(cmd *cobra.Command, args []string) { privValFile := path.Join(dataDir, mach, "priv_validator.json") privVal := types.LoadPrivValidatorFS(privValFile) genVals[i] = types.GenesisValidator{ - PubKey: privVal.PubKey(), + PubKey: privVal.GetPubKey(), Power: 1, Name: mach, } diff --git a/config/toml.go b/config/toml.go index 02ae3fc61..4366695db 100644 --- a/config/toml.go +++ b/config/toml.go @@ -127,22 +127,16 @@ var testGenesis = `{ }` var testPrivValidator = `{ - "id": { "address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456", "pub_key": { "type": "ed25519", "data": "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" - } - }, - "signer": { + }, "priv_key": { "type": "ed25519", "data": "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" - } - }, - "info": { + }, "last_height": 0, "last_round": 0, "last_step": 0 - } }` diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index d8b6b0495..0f2d7b040 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -272,12 +272,12 @@ func NewByzantinePrivValidator(pv types.PrivValidator) *ByzantinePrivValidator { } } -func (privVal *ByzantinePrivValidator) Address() data.Bytes { - return privVal.pv.Address() +func (privVal *ByzantinePrivValidator) GetAddress() data.Bytes { + return privVal.pv.GetAddress() } -func (privVal *ByzantinePrivValidator) PubKey() crypto.PubKey { - return privVal.pv.PubKey() +func (privVal *ByzantinePrivValidator) GetPubKey() crypto.PubKey { + return privVal.pv.GetPubKey() } func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) (err error) { @@ -296,5 +296,5 @@ func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat * } func (privVal *ByzantinePrivValidator) String() string { - return Fmt("PrivValidator{%X}", privVal.Address) + return Fmt("PrivValidator{%X}", privVal.GetAddress()) } diff --git a/consensus/common_test.go b/consensus/common_test.go index a746ec59c..b16afc3d0 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -65,7 +65,7 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato 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") } diff --git a/consensus/height_vote_set_test.go b/consensus/height_vote_set_test.go index 3d22a1dab..7e03e40f5 100644 --- a/consensus/height_vote_set_test.go +++ b/consensus/height_vote_set_test.go @@ -47,7 +47,7 @@ func TestPeerCatchupRounds(t *testing.T) { 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, diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 752c759f1..623a65413 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -119,7 +119,7 @@ func TestVotingPowerChange(t *testing.T) { // map of active validators activeVals := make(map[string]struct{}) for i := 0; i < nVals; i++ { - activeVals[string(css[i].privValidator.Address())] = struct{}{} + activeVals[string(css[i].privValidator.GetAddress())] = struct{}{} } // wait till everyone makes block 1 @@ -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.PubKey() + val1PubKey := css[0].privValidator.GetPubKey() updateValidatorTx := dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 25) previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower() @@ -180,7 +180,7 @@ func TestValidatorSetChanges(t *testing.T) { // map of active validators activeVals := make(map[string]struct{}) for i := 0; i < nVals; i++ { - activeVals[string(css[i].privValidator.Address())] = struct{}{} + activeVals[string(css[i].privValidator.GetAddress())] = struct{}{} } // wait till everyone makes block 1 @@ -193,7 +193,7 @@ func TestValidatorSetChanges(t *testing.T) { //--------------------------------------------------------------------------- t.Log("---------------------------- Testing adding one validator") - newValidatorPubKey1 := css[nVals].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.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.PubKey() + newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey() newValidatorTx2 := dummy.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), uint64(testMinPower)) - newValidatorPubKey3 := css[nVals+2].privValidator.PubKey() + newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey() newValidatorTx3 := dummy.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), uint64(testMinPower)) waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3) diff --git a/consensus/replay_test.go b/consensus/replay_test.go index c6504380d..765434677 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -184,10 +184,10 @@ func setupReplayTest(t *testing.T, thisCase *testCase, nLines int, crashAfter bo cs := fixedConsensusStateDummy() // set the last step according to when we crashed vs the wal - toPV(cs.privValidator).Info.LastHeight = 1 // first block - toPV(cs.privValidator).Info.LastStep = thisCase.stepMap[lineStep] + toPV(cs.privValidator).LastHeight = 1 // first block + toPV(cs.privValidator).LastStep = thisCase.stepMap[lineStep] - t.Logf("[WARN] setupReplayTest LastStep=%v", toPV(cs.privValidator).Info.LastStep) + t.Logf("[WARN] setupReplayTest LastStep=%v", toPV(cs.privValidator).LastStep) newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1) @@ -230,8 +230,8 @@ func TestWALCrashBeforeWritePropose(t *testing.T) { msg := readTimedWALMessage(t, proposalMsg) proposal := msg.Msg.(msgInfo).Msg.(*ProposalMessage) // Set LastSig - toPV(cs.privValidator).Info.LastSignBytes = types.SignBytes(cs.state.ChainID, proposal.Proposal) - toPV(cs.privValidator).Info.LastSignature = proposal.Proposal.Signature + toPV(cs.privValidator).LastSignBytes = types.SignBytes(cs.state.ChainID, proposal.Proposal) + toPV(cs.privValidator).LastSignature = proposal.Proposal.Signature runReplayTest(t, cs, walFile, newBlockCh, thisCase, lineNum) } } @@ -255,8 +255,8 @@ func testReplayCrashBeforeWriteVote(t *testing.T, thisCase *testCase, lineNum in msg := readTimedWALMessage(t, voteMsg) vote := msg.Msg.(msgInfo).Msg.(*VoteMessage) // Set LastSig - toPV(cs.privValidator).Info.LastSignBytes = types.SignBytes(cs.state.ChainID, vote.Vote) - toPV(cs.privValidator).Info.LastSignature = vote.Vote.Signature + toPV(cs.privValidator).LastSignBytes = types.SignBytes(cs.state.ChainID, vote.Vote) + toPV(cs.privValidator).LastSignature = vote.Vote.Signature }) runReplayTest(t, cs, walFile, newBlockCh, thisCase, lineNum) } @@ -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) } diff --git a/consensus/state.go b/consensus/state.go index f141cad58..648fc0559 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -817,7 +817,7 @@ func (cs *ConsensusState) needProofBlock(height int) bool { func (cs *ConsensusState) proposalHeartbeat(height, round int) { counter := 0 - addr := cs.privValidator.Address() + addr := cs.privValidator.GetAddress() valIndex, v := cs.Validators.GetByAddress(addr) if v == nil { // not a validator @@ -878,7 +878,7 @@ func (cs *ConsensusState) enterPropose(height int, round int) { if !cs.isProposer() { cs.Logger.Info("enterPropose: Not our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator) - if cs.Validators.HasAddress(cs.privValidator.Address()) { + if cs.Validators.HasAddress(cs.privValidator.GetAddress()) { cs.Logger.Debug("This node is a validator") } else { cs.Logger.Debug("This node is not a validator") @@ -891,7 +891,7 @@ func (cs *ConsensusState) enterPropose(height int, round int) { } func (cs *ConsensusState) isProposer() bool { - return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.Address()) + return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.GetAddress()) } func (cs *ConsensusState) defaultDecideProposal(height, round int) { @@ -1436,7 +1436,7 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerKey string) error { if err == ErrVoteHeightMismatch { return err } else if _, ok := err.(*types.ErrVoteConflictingVotes); ok { - if bytes.Equal(vote.ValidatorAddress, cs.privValidator.Address()) { + if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) { cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type) return err } @@ -1565,7 +1565,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool, } func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) { - addr := cs.privValidator.Address() + addr := cs.privValidator.GetAddress() valIndex, _ := cs.Validators.GetByAddress(addr) vote := &types.Vote{ ValidatorAddress: addr, @@ -1582,7 +1582,7 @@ func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSet // sign the vote and publish on internalMsgQueue func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote { // if we don't have a key or we're not in the validator set, do nothing - if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.Address()) { + if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) { return nil } vote, err := cs.signVote(type_, hash, header) diff --git a/consensus/state_test.go b/consensus/state_test.go index 977d6445c..c4a6769e9 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -65,7 +65,7 @@ func TestProposerSelection0(t *testing.T) { // lets commit a block and ensure proposer for the next height is correct prop := cs1.GetRoundState().Validators.GetProposer() - if !bytes.Equal(prop.Address, cs1.privValidator.Address()) { + if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) { t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address) } @@ -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)) } @@ -613,7 +613,7 @@ func TestLockPOLUnlock(t *testing.T) { timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1) unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // everything done from perspective of cs1 @@ -707,7 +707,7 @@ func TestLockPOLSafety1(t *testing.T) { timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // start round and wait for propose and prevote startTestRound(cs1, cs1.Height, 0) @@ -829,7 +829,7 @@ func TestLockPOLSafety2(t *testing.T) { timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1) unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // the block for R0: gets polkad but we miss it // (even though we signed it, shhh) @@ -921,7 +921,7 @@ func TestSlashingPrevotes(t *testing.T) { proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1) timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1) newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // start round and wait for propose and prevote startTestRound(cs1, cs1.Height, 0) @@ -956,7 +956,7 @@ func TestSlashingPrecommits(t *testing.T) { proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1) timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1) newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // start round and wait for propose and prevote startTestRound(cs1, cs1.Height, 0) @@ -1003,7 +1003,7 @@ func TestHalt1(t *testing.T) { timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1) newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1) - voteCh := subscribeToVoter(cs1, cs1.privValidator.Address()) + voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) // start round and wait for propose and prevote startTestRound(cs1, cs1.Height, 0) diff --git a/node/node.go b/node/node.go index 761f4d5e4..0fb064514 100644 --- a/node/node.go +++ b/node/node.go @@ -188,13 +188,13 @@ func NewNode(config *cfg.Config, 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") @@ -386,7 +386,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()) diff --git a/types/priv_validator.go b/types/priv_validator.go index 892a4f06a..6db240966 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -37,8 +37,8 @@ func voteToStep(vote *Vote) int8 { // PrivValidator defines the functionality of a local Tendermint validator // that signs votes, proposals, and heartbeats, and never double signs. type PrivValidator interface { - Address() data.Bytes // redundant since .PubKey().Address() - PubKey() crypto.PubKey + GetAddress() data.Bytes // redundant since .PubKey().Address() + GetPubKey() crypto.PubKey SignVote(chainID string, vote *Vote) error SignProposal(chainID string, proposal *Proposal) error @@ -49,29 +49,34 @@ type PrivValidator interface { // to prevent double signing. The Signer itself can be mutated to use // something besides the default, for instance a hardware signer. type PrivValidatorFS struct { - ID ValidatorID `json:"id"` - Signer Signer `json:"signer"` + 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 - // mutable state to be persisted to disk - // after each signature to prevent double signing - mtx sync.Mutex - Info LastSignedInfo `json:"info"` + // 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 } -// Address returns the address of the validator. +// GetAddress returns the address of the validator. // Implements PrivValidator. -func (pv *PrivValidatorFS) Address() data.Bytes { - return pv.ID.Address +func (pv *PrivValidatorFS) GetAddress() data.Bytes { + return pv.Address } -// PubKey returns the public key of the validator. +// GetPubKey returns the public key of the validator. // Implements PrivValidator. -func (pv *PrivValidatorFS) PubKey() crypto.PubKey { - return pv.ID.PubKey +func (pv *PrivValidatorFS) GetPubKey() crypto.PubKey { + return pv.PubKey } // SignVote signs a canonical representation of the vote, along with the chainID. @@ -79,12 +84,10 @@ func (pv *PrivValidatorFS) PubKey() crypto.PubKey { func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() - signature, err := privVal.Info.SignBytesHRS(privVal.Signer, - vote.Height, vote.Round, voteToStep(vote), SignBytes(chainID, vote)) + signature, err := privVal.signBytesHRS(vote.Height, vote.Round, voteToStep(vote), SignBytes(chainID, vote)) if err != nil { return errors.New(cmn.Fmt("Error signing vote: %v", err)) } - privVal.save() vote.Signature = signature return nil } @@ -94,12 +97,10 @@ func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error { func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() - signature, err := privVal.Info.SignBytesHRS(privVal.Signer, - proposal.Height, proposal.Round, stepPropose, SignBytes(chainID, proposal)) + signature, err := privVal.signBytesHRS(proposal.Height, proposal.Round, stepPropose, SignBytes(chainID, proposal)) if err != nil { return fmt.Errorf("Error signing proposal: %v", err) } - privVal.save() proposal.Signature = signature return nil } @@ -137,45 +138,75 @@ func (privVal *PrivValidatorFS) save() { } } -// UnmarshalJSON unmarshals the given jsonString -// into a PrivValidatorFS using a DefaultSigner. -func (pv *PrivValidatorFS) UnmarshalJSON(jsonString []byte) error { - idAndInfo := &struct { - ID ValidatorID `json:"id"` - Info LastSignedInfo `json:"info"` - }{} - if err := json.Unmarshal(jsonString, idAndInfo); err != nil { - return err +// 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 { + return sig, errors.New("Height regression") + } + // More cases for when the height matches + if privVal.LastHeight == height { + // If round regression, err + if privVal.LastRound > round { + return sig, errors.New("Round regression") + } + // If step regression, err + if privVal.LastRound == round { + if privVal.LastStep > step { + return sig, errors.New("Step regression") + } else if privVal.LastStep == step { + if privVal.LastSignBytes != nil { + if privVal.LastSignature.Empty() { + 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), + // so we can actually lose them, but will still never sign conflicting ones + if bytes.Equal(privVal.LastSignBytes, signBytes) { + // log.Notice("Using privVal.LastSignature", "sig", privVal.LastSignature) + return privVal.LastSignature, nil + } + } + return sig, errors.New("Step regression") + } + } } - signer := &struct { - Signer *DefaultSigner `json:"signer"` - }{} - if err := json.Unmarshal(jsonString, signer); err != nil { - return err + // Sign + sig, err := privVal.Signer.Sign(signBytes) + if err != nil { + return sig, err } - pv.ID = idAndInfo.ID - pv.Info = idAndInfo.Info - pv.Signer = signer.Signer - return nil + // Persist height/round/step + privVal.LastHeight = height + privVal.LastRound = round + privVal.LastStep = step + privVal.LastSignature = sig + privVal.LastSignBytes = signBytes + privVal.save() + + return sig, nil } -// Reset resets all fields in the PrivValidatorFS.Info. +// Reset resets all fields in the PrivValidatorFS. // NOTE: Unsafe! func (privVal *PrivValidatorFS) Reset() { - privVal.Info.LastHeight = 0 - privVal.Info.LastRound = 0 - privVal.Info.LastStep = 0 - privVal.Info.LastSignature = crypto.Signature{} - privVal.Info.LastSignBytes = nil + privVal.LastHeight = 0 + privVal.LastRound = 0 + privVal.LastStep = 0 + privVal.LastSignature = crypto.Signature{} + privVal.LastSignBytes = nil privVal.Save() } // String returns a string representation of the PrivValidatorFS. func (privVal *PrivValidatorFS) String() string { - info := privVal.Info - return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.Address(), info.LastHeight, info.LastRound, info.LastStep) + return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep) } // LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath @@ -204,6 +235,7 @@ func LoadPrivValidatorFS(filePath string) *PrivValidatorFS { } privVal.filePath = filePath + privVal.Signer = NewDefaultSigner(privVal.PrivKey) return &privVal } @@ -212,10 +244,10 @@ func LoadPrivValidatorFS(filePath string) *PrivValidatorFS { func GenPrivValidatorFS(filePath string) *PrivValidatorFS { privKey := crypto.GenPrivKeyEd25519().Wrap() return &PrivValidatorFS{ - ID: ValidatorID{privKey.PubKey().Address(), privKey.PubKey()}, - Info: LastSignedInfo{ - LastStep: stepNone, - }, + Address: privKey.PubKey().Address(), + PubKey: privKey.PubKey(), + PrivKey: privKey, + LastStep: stepNone, Signer: NewDefaultSigner(privKey), filePath: filePath, } @@ -225,7 +257,7 @@ func GenPrivValidatorFS(filePath string) *PrivValidatorFS { // 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(ValidatorID) Signer) *PrivValidatorFS { +func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(crypto.PubKey) Signer) *PrivValidatorFS { privValJSONBytes, err := ioutil.ReadFile(filePath) if err != nil { cmn.Exit(err.Error()) @@ -237,85 +269,12 @@ func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(ValidatorID) } privVal.filePath = filePath - privVal.Signer = signerFunc(privVal.ID) + privVal.Signer = signerFunc(privVal.PubKey) return &privVal } //------------------------------------- -// ValidatorID contains the identity of the validator. -type ValidatorID struct { - Address data.Bytes `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` -} - -//------------------------------------- - -// LastSignedInfo contains information about the latest -// data signed by a validator to help prevent double signing. -type LastSignedInfo struct { - 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 -} - -// SignBytesHRS signs the given signBytes with the signer if the height/round/step (HRS) -// are greater than the latest state of the LastSignedInfo. If the HRS are equal, -// it returns the LastSignedInfo.LastSignature. -func (info *LastSignedInfo) SignBytesHRS(signer Signer, - height, round int, step int8, signBytes []byte) (crypto.Signature, error) { - - sig := crypto.Signature{} - // If height regression, err - if info.LastHeight > height { - return sig, errors.New("Height regression") - } - // More cases for when the height matches - if info.LastHeight == height { - // If round regression, err - if info.LastRound > round { - return sig, errors.New("Round regression") - } - // If step regression, err - if info.LastRound == round { - if info.LastStep > step { - return sig, errors.New("Step regression") - } else if info.LastStep == step { - if info.LastSignBytes != nil { - if info.LastSignature.Empty() { - 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), - // so we can actually lose them, but will still never sign conflicting ones - if bytes.Equal(info.LastSignBytes, signBytes) { - // log.Notice("Using info.LastSignature", "sig", info.LastSignature) - return info.LastSignature, nil - } - } - return sig, errors.New("Step regression") - } - } - } - - // Sign - sig, err := signer.Sign(signBytes) - if err != nil { - return sig, err - } - - // Persist height/round/step - info.LastHeight = height - info.LastRound = round - info.LastStep = step - info.LastSignature = sig - info.LastSignBytes = signBytes - - return sig, nil -} - //------------------------------------- // Signer is an interface that defines how to sign messages. @@ -353,7 +312,7 @@ func (pvs PrivValidatorsByAddress) Len() int { } 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) { diff --git a/types/priv_validator_test.go b/types/priv_validator_test.go index 58a43d489..d56cb9ec9 100644 --- a/types/priv_validator_test.go +++ b/types/priv_validator_test.go @@ -29,25 +29,19 @@ func TestLoadValidator(t *testing.T) { require.Nil(err, "%+v", err) serialized := fmt.Sprintf(`{ - "id": { "address": "%s", "pub_key": { "type": "ed25519", "data": "%s" - } - }, - "info": { + }, "last_height": 0, "last_round": 0, "last_step": 0, - "last_signature": null - }, - "signer": { + "last_signature": null, "priv_key": { "type": "ed25519", "data": "%s" } - } }`, addrStr, pubStr, privStr) val := PrivValidatorFS{} @@ -55,10 +49,9 @@ func TestLoadValidator(t *testing.T) { require.Nil(err, "%+v", err) // make sure the values match - assert.EqualValues(addrBytes, val.Address()) - assert.EqualValues(pubKey, val.PubKey()) - valPrivKey := val.Signer.(*DefaultSigner).PrivKey - assert.EqualValues(privKey, valPrivKey) + assert.EqualValues(addrBytes, val.GetAddress()) + assert.EqualValues(pubKey, val.GetPubKey()) + assert.EqualValues(privKey, val.PrivKey) // export it and make sure it is the same out, err := json.Marshal(val) diff --git a/types/proposal_test.go b/types/proposal_test.go index 2e4e7e198..d1c991849 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -38,7 +38,7 @@ func BenchmarkProposalVerifySignature(b *testing.B) { signBytes := SignBytes("test_chain_id", testProposal) privVal := GenPrivValidatorFS("") signature, _ := privVal.Signer.Sign(signBytes) - pubKey := privVal.PubKey() + pubKey := privVal.GetPubKey() for i := 0; i < b.N; i++ { pubKey.VerifyBytes(SignBytes("test_chain_id", testProposal), signature) diff --git a/types/validator.go b/types/validator.go index e52831e27..506828913 100644 --- a/types/validator.go +++ b/types/validator.go @@ -113,6 +113,6 @@ func RandValidator(randPower bool, minPower int64) (*Validator, *PrivValidatorFS if randPower { votePower += int64(cmn.RandUint32()) } - val := NewValidator(privVal.PubKey(), votePower) + val := NewValidator(privVal.GetPubKey(), votePower) return val, privVal } diff --git a/types/vote_set_test.go b/types/vote_set_test.go index ab1456ed9..80ee6135c 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -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) }