mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-19 06:31:57 +00:00
Refactor Tx, Validator, and Account structure
This commit is contained in:
+42
-72
@@ -2,111 +2,81 @@ package consensus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
. "github.com/tendermint/tendermint/account"
|
||||
. "github.com/tendermint/tendermint/blocks"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
"github.com/tendermint/tendermint/state"
|
||||
)
|
||||
|
||||
// Each signature of a POL (proof-of-lock, see whitepaper) is
|
||||
// either a prevote or a commit.
|
||||
// Commits require an additional round which is strictly less than
|
||||
// the POL round. Prevote rounds are equal to the POL round.
|
||||
type POLVoteSignature struct {
|
||||
Round uint
|
||||
Signature SignatureEd25519
|
||||
}
|
||||
|
||||
// Proof of lock.
|
||||
// +2/3 of validators' prevotes for a given blockhash (or nil)
|
||||
type POL struct {
|
||||
Height uint32
|
||||
Round uint16
|
||||
BlockHash []byte // Could be nil, which makes this a proof of unlock.
|
||||
BlockParts PartSetHeader // When BlockHash is nil, this is zero.
|
||||
Votes []Signature // Vote signatures for height/round/hash
|
||||
Commits []RoundSignature // Commit signatures for height/hash
|
||||
}
|
||||
|
||||
func ReadPOL(r io.Reader, n *int64, err *error) *POL {
|
||||
return &POL{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
Round: ReadUInt16(r, n, err),
|
||||
BlockHash: ReadByteSlice(r, n, err),
|
||||
BlockParts: ReadPartSetHeader(r, n, err),
|
||||
Votes: ReadSignatures(r, n, err),
|
||||
Commits: ReadRoundSignatures(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (pol *POL) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteUInt32(w, pol.Height, &n, &err)
|
||||
WriteUInt16(w, pol.Round, &n, &err)
|
||||
WriteByteSlice(w, pol.BlockHash, &n, &err)
|
||||
WriteBinary(w, pol.BlockParts, &n, &err)
|
||||
WriteSignatures(w, pol.Votes, &n, &err)
|
||||
WriteRoundSignatures(w, pol.Commits, &n, &err)
|
||||
return
|
||||
Height uint
|
||||
Round uint
|
||||
BlockHash []byte // Could be nil, which makes this a proof of unlock.
|
||||
BlockParts PartSetHeader // When BlockHash is nil, this is zero.
|
||||
Votes []POLVoteSignature // Prevote and commit signatures in ValidatorSet order.
|
||||
}
|
||||
|
||||
// Returns whether +2/3 have voted/committed for BlockHash.
|
||||
func (pol *POL) Verify(vset *state.ValidatorSet) error {
|
||||
func (pol *POL) Verify(valSet *state.ValidatorSet) error {
|
||||
|
||||
if uint(len(pol.Votes)) != valSet.Size() {
|
||||
return Errorf("Invalid POL votes count: Expected %v, got %v",
|
||||
valSet.Size(), len(pol.Votes))
|
||||
}
|
||||
|
||||
talliedVotingPower := uint64(0)
|
||||
voteDoc := BinaryBytes(&Vote{
|
||||
prevoteDoc := SignBytes(&Vote{
|
||||
Height: pol.Height, Round: pol.Round, Type: VoteTypePrevote,
|
||||
BlockHash: pol.BlockHash,
|
||||
BlockParts: pol.BlockParts,
|
||||
})
|
||||
seenValidators := map[uint64]struct{}{}
|
||||
seenValidators := map[string]struct{}{}
|
||||
|
||||
for _, sig := range pol.Votes {
|
||||
for idx, sig := range pol.Votes {
|
||||
voteDoc := prevoteDoc
|
||||
_, val := valSet.GetByIndex(uint(idx))
|
||||
|
||||
// Commit signature?
|
||||
if sig.Round < pol.Round {
|
||||
voteDoc = SignBytes(&Vote{
|
||||
Height: pol.Height, Round: sig.Round, Type: VoteTypeCommit,
|
||||
BlockHash: pol.BlockHash,
|
||||
BlockParts: pol.BlockParts,
|
||||
})
|
||||
} else if sig.Round > pol.Round {
|
||||
return Errorf("Invalid commit round %v for POL %v", sig.Round, pol)
|
||||
}
|
||||
|
||||
// Validate
|
||||
if _, seen := seenValidators[sig.SignerId]; seen {
|
||||
if _, seen := seenValidators[string(val.Address)]; seen {
|
||||
return Errorf("Duplicate validator for vote %v for POL %v", sig, pol)
|
||||
}
|
||||
_, val := vset.GetById(sig.SignerId)
|
||||
if val == nil {
|
||||
return Errorf("Invalid validator for vote %v for POL %v", sig, pol)
|
||||
}
|
||||
if !val.VerifyBytes(voteDoc, sig) {
|
||||
if !val.PubKey.VerifyBytes(voteDoc, sig.Signature.Bytes) {
|
||||
return Errorf("Invalid signature for vote %v for POL %v", sig, pol)
|
||||
}
|
||||
|
||||
// Tally
|
||||
seenValidators[val.Id] = struct{}{}
|
||||
seenValidators[string(val.Address)] = struct{}{}
|
||||
talliedVotingPower += val.VotingPower
|
||||
}
|
||||
|
||||
for _, rsig := range pol.Commits {
|
||||
round := rsig.Round
|
||||
sig := rsig.Signature
|
||||
|
||||
// Validate
|
||||
if _, seen := seenValidators[sig.SignerId]; seen {
|
||||
return Errorf("Duplicate validator for commit %v for POL %v", sig, pol)
|
||||
}
|
||||
_, val := vset.GetById(sig.SignerId)
|
||||
if val == nil {
|
||||
return Errorf("Invalid validator for commit %v for POL %v", sig, pol)
|
||||
}
|
||||
if round >= pol.Round {
|
||||
return Errorf("Invalid commit round %v for POL %v", round, pol)
|
||||
}
|
||||
|
||||
commitDoc := BinaryBytes(&Vote{
|
||||
Height: pol.Height, Round: round, Type: VoteTypeCommit,
|
||||
BlockHash: pol.BlockHash,
|
||||
BlockParts: pol.BlockParts,
|
||||
})
|
||||
if !val.VerifyBytes(commitDoc, sig) {
|
||||
return Errorf("Invalid signature for commit %v for POL %v", sig, pol)
|
||||
}
|
||||
|
||||
// Tally
|
||||
seenValidators[val.Id] = struct{}{}
|
||||
talliedVotingPower += val.VotingPower
|
||||
}
|
||||
|
||||
if talliedVotingPower > vset.TotalVotingPower()*2/3 {
|
||||
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
||||
return nil
|
||||
} else {
|
||||
return Errorf("Invalid POL, insufficient voting power %v, needed %v",
|
||||
talliedVotingPower, (vset.TotalVotingPower()*2/3 + 1))
|
||||
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+152
-16
@@ -1,30 +1,166 @@
|
||||
package consensus
|
||||
|
||||
// TODO: This logic is crude. Should be more transactional.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
. "github.com/tendermint/tendermint/account"
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
. "github.com/tendermint/tendermint/blocks"
|
||||
db_ "github.com/tendermint/tendermint/db"
|
||||
"github.com/tendermint/tendermint/state"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
. "github.com/tendermint/tendermint/config"
|
||||
|
||||
"github.com/tendermint/go-ed25519"
|
||||
)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const (
|
||||
stepNone = 0 // Used to distinguish the initial state
|
||||
stepPropose = 1
|
||||
stepPrevote = 2
|
||||
stepPrecommit = 3
|
||||
stepCommit = 4
|
||||
)
|
||||
|
||||
func voteToStep(vote *Vote) uint8 {
|
||||
switch vote.Type {
|
||||
case VoteTypePrevote:
|
||||
return stepPrevote
|
||||
case VoteTypePrecommit:
|
||||
return stepPrecommit
|
||||
case VoteTypeCommit:
|
||||
return stepCommit
|
||||
default:
|
||||
panic("Unknown vote type")
|
||||
}
|
||||
}
|
||||
|
||||
type PrivValidator struct {
|
||||
db db_.DB
|
||||
state.PrivAccount
|
||||
Address []byte
|
||||
PubKey PubKeyEd25519
|
||||
PrivKey PrivKeyEd25519
|
||||
LastHeight uint
|
||||
LastRound uint
|
||||
LastStep uint8
|
||||
}
|
||||
|
||||
// Generates a new validator with private key.
|
||||
func GenPrivValidator() *PrivValidator {
|
||||
privKeyBytes := CRandBytes(32)
|
||||
pubKeyBytes := ed25519.MakePubKey(privKeyBytes)
|
||||
pubKey := PubKeyEd25519{pubKeyBytes}
|
||||
privKey := PrivKeyEd25519{pubKeyBytes, privKeyBytes}
|
||||
return &PrivValidator{
|
||||
Address: pubKey.Address(),
|
||||
PubKey: pubKey,
|
||||
PrivKey: privKey,
|
||||
LastHeight: 0,
|
||||
LastRound: 0,
|
||||
LastStep: stepNone,
|
||||
}
|
||||
}
|
||||
|
||||
type PrivValidatorJSON struct {
|
||||
Address string
|
||||
PubKey string
|
||||
PrivKey string
|
||||
LastHeight uint
|
||||
LastRound uint
|
||||
LastStep uint8
|
||||
}
|
||||
|
||||
func LoadPrivValidator() *PrivValidator {
|
||||
privValJSONBytes, err := ioutil.ReadFile(PrivValidatorFile())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
privValJSON := PrivValidatorJSON{}
|
||||
err = json.Unmarshal(privValJSONBytes, &privValJSON)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
address, err := base64.StdEncoding.DecodeString(privValJSON.Address)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
privKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PrivKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
n := new(int64)
|
||||
privVal := &PrivValidator{
|
||||
Address: address,
|
||||
PubKey: ReadBinary(PubKeyEd25519{}, bytes.NewReader(pubKeyBytes), n, &err).(PubKeyEd25519),
|
||||
PrivKey: ReadBinary(PrivKeyEd25519{}, bytes.NewReader(privKeyBytes), n, &err).(PrivKeyEd25519),
|
||||
LastHeight: privValJSON.LastHeight,
|
||||
LastRound: privValJSON.LastRound,
|
||||
LastStep: privValJSON.LastStep,
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return privVal
|
||||
}
|
||||
|
||||
func NewPrivValidator(db db_.DB, priv *state.PrivAccount) *PrivValidator {
|
||||
return &PrivValidator{db, *priv}
|
||||
func (privVal *PrivValidator) Save() {
|
||||
privValJSON := PrivValidatorJSON{
|
||||
Address: base64.StdEncoding.EncodeToString(privVal.Address),
|
||||
PubKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PubKey)),
|
||||
PrivKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PrivKey)),
|
||||
LastHeight: privVal.LastHeight,
|
||||
LastRound: privVal.LastRound,
|
||||
LastStep: privVal.LastStep,
|
||||
}
|
||||
privValJSONBytes, err := json.Marshal(privValJSON)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = ioutil.WriteFile(PrivValidatorFile(), privValJSONBytes, 0700)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignVote(vote *Vote) SignatureEd25519 {
|
||||
if privVal.LastHeight < vote.Height ||
|
||||
privVal.LastHeight == vote.Height && privVal.LastRound < vote.Round ||
|
||||
privVal.LastHeight == vote.Height && privVal.LastRound == vote.Round && privVal.LastStep < voteToStep(vote) {
|
||||
|
||||
// Persist height/round/step
|
||||
privVal.LastHeight = vote.Height
|
||||
privVal.LastRound = vote.Round
|
||||
privVal.LastStep = voteToStep(vote)
|
||||
privVal.Save()
|
||||
|
||||
// Sign
|
||||
return privVal.PrivKey.Sign(SignBytes(vote)).(SignatureEd25519)
|
||||
} else {
|
||||
panic(fmt.Sprintf("Attempt of duplicate signing of vote: Height %v, Round %v, Type %v", vote.Height, vote.Round, vote.Type))
|
||||
}
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignProposal(proposal *Proposal) SignatureEd25519 {
|
||||
if privVal.LastHeight < proposal.Height ||
|
||||
privVal.LastHeight == proposal.Height && privVal.LastRound < proposal.Round ||
|
||||
privVal.LastHeight == 0 && privVal.LastRound == 0 && privVal.LastStep == stepNone {
|
||||
|
||||
// Persist height/round/step
|
||||
privVal.LastHeight = proposal.Height
|
||||
privVal.LastRound = proposal.Round
|
||||
privVal.LastStep = stepPropose
|
||||
privVal.Save()
|
||||
|
||||
// Double signing results in a panic.
|
||||
func (pv *PrivValidator) Sign(o Signable) {
|
||||
switch o.(type) {
|
||||
case *Proposal:
|
||||
//TODO: prevent double signing && test.
|
||||
pv.PrivAccount.Sign(o.(*Proposal))
|
||||
case *Vote:
|
||||
//TODO: prevent double signing && test.
|
||||
pv.PrivAccount.Sign(o.(*Vote))
|
||||
// Sign
|
||||
return privVal.PrivKey.Sign(SignBytes(proposal)).(SignatureEd25519)
|
||||
} else {
|
||||
panic(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v, Type %v", proposal.Height, proposal.Round))
|
||||
}
|
||||
}
|
||||
|
||||
+12
-32
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
. "github.com/tendermint/tendermint/account"
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
. "github.com/tendermint/tendermint/blocks"
|
||||
)
|
||||
@@ -15,15 +16,14 @@ var (
|
||||
)
|
||||
|
||||
type Proposal struct {
|
||||
Height uint32
|
||||
Round uint16
|
||||
Height uint
|
||||
Round uint
|
||||
BlockParts PartSetHeader
|
||||
POLParts PartSetHeader
|
||||
Signature Signature
|
||||
Signature SignatureEd25519
|
||||
}
|
||||
|
||||
func NewProposal(height uint32, round uint16, blockParts, polParts PartSetHeader) *Proposal {
|
||||
|
||||
func NewProposal(height uint, round uint, blockParts, polParts PartSetHeader) *Proposal {
|
||||
return &Proposal{
|
||||
Height: height,
|
||||
Round: round,
|
||||
@@ -32,34 +32,14 @@ func NewProposal(height uint32, round uint16, blockParts, polParts PartSetHeader
|
||||
}
|
||||
}
|
||||
|
||||
func ReadProposal(r io.Reader, n *int64, err *error) *Proposal {
|
||||
return &Proposal{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
Round: ReadUInt16(r, n, err),
|
||||
BlockParts: ReadPartSetHeader(r, n, err),
|
||||
POLParts: ReadPartSetHeader(r, n, err),
|
||||
Signature: ReadSignature(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proposal) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteUInt32(w, p.Height, &n, &err)
|
||||
WriteUInt16(w, p.Round, &n, &err)
|
||||
WriteBinary(w, p.BlockParts, &n, &err)
|
||||
WriteBinary(w, p.POLParts, &n, &err)
|
||||
WriteBinary(w, p.Signature, &n, &err)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Proposal) GetSignature() Signature {
|
||||
return p.Signature
|
||||
}
|
||||
|
||||
func (p *Proposal) SetSignature(sig Signature) {
|
||||
p.Signature = sig
|
||||
}
|
||||
|
||||
func (p *Proposal) String() string {
|
||||
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
||||
p.BlockParts, p.POLParts, p.Signature)
|
||||
}
|
||||
|
||||
func (p *Proposal) WriteSignBytes(w io.Writer, n *int64, err *error) {
|
||||
WriteUVarInt(p.Height, w, n, err)
|
||||
WriteUVarInt(p.Round, w, n, err)
|
||||
WriteBinary(p.BlockParts, w, n, err)
|
||||
WriteBinary(p.POLParts, w, n, err)
|
||||
}
|
||||
|
||||
+70
-115
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -123,9 +122,9 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||
msg := msg_.(*NewRoundStepMessage)
|
||||
ps.ApplyNewRoundStepMessage(msg, rs)
|
||||
|
||||
case *CommitMessage:
|
||||
msg := msg_.(*CommitMessage)
|
||||
ps.ApplyCommitMessage(msg)
|
||||
case *CommitStepMessage:
|
||||
msg := msg_.(*CommitStepMessage)
|
||||
ps.ApplyCommitStepMessage(msg)
|
||||
|
||||
case *HasVoteMessage:
|
||||
msg := msg_.(*HasVoteMessage)
|
||||
@@ -160,10 +159,17 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||
|
||||
case VoteCh:
|
||||
switch msg_.(type) {
|
||||
case *Vote:
|
||||
vote := msg_.(*Vote)
|
||||
added, index, err := conR.conS.AddVote(vote)
|
||||
case *VoteMessage:
|
||||
voteMessage := msg_.(*VoteMessage)
|
||||
vote := voteMessage.Vote
|
||||
if rs.Height != vote.Height {
|
||||
return // Wrong height. Not necessarily a bad peer.
|
||||
}
|
||||
validatorIndex := voteMessage.ValidatorIndex
|
||||
address, _ := rs.Validators.GetByIndex(validatorIndex)
|
||||
added, index, err := conR.conS.AddVote(address, vote)
|
||||
if err != nil {
|
||||
// Probably an invalid signature. Bad peer.
|
||||
log.Warning("Error attempting to add vote: %v", err)
|
||||
}
|
||||
// Initialize Prevotes/Precommits/Commits if needed
|
||||
@@ -220,14 +226,14 @@ func (conR *ConsensusReactor) broadcastNewRoundStepRoutine() {
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Step: rs.Step,
|
||||
SecondsSinceStartTime: uint32(timeElapsed.Seconds()),
|
||||
SecondsSinceStartTime: uint(timeElapsed.Seconds()),
|
||||
}
|
||||
conR.sw.Broadcast(StateCh, msg)
|
||||
}
|
||||
|
||||
// If the step is commit, then also broadcast a CommitMessage.
|
||||
// If the step is commit, then also broadcast a CommitStepMessage.
|
||||
if rs.Step == RoundStepCommit {
|
||||
msg := &CommitMessage{
|
||||
msg := &CommitStepMessage{
|
||||
Height: rs.Height,
|
||||
BlockParts: rs.ProposalBlockParts.Header(),
|
||||
BlockBitArray: rs.ProposalBlockParts.BitArray(),
|
||||
@@ -259,10 +265,10 @@ OUTER_LOOP:
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Type: partTypeProposalBlock,
|
||||
Part: rs.ProposalBlockParts.GetPart(uint16(index)),
|
||||
Part: rs.ProposalBlockParts.GetPart(index),
|
||||
}
|
||||
peer.Send(DataCh, msg)
|
||||
ps.SetHasProposalBlockPart(rs.Height, rs.Round, uint16(index))
|
||||
ps.SetHasProposalBlockPart(rs.Height, rs.Round, index)
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
}
|
||||
@@ -289,10 +295,10 @@ OUTER_LOOP:
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Type: partTypeProposalPOL,
|
||||
Part: rs.ProposalPOLParts.GetPart(uint16(index)),
|
||||
Part: rs.ProposalPOLParts.GetPart(index),
|
||||
}
|
||||
peer.Send(DataCh, msg)
|
||||
ps.SetHasProposalPOLPart(rs.Height, rs.Round, uint16(index))
|
||||
ps.SetHasProposalPOLPart(rs.Height, rs.Round, index)
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
}
|
||||
@@ -320,7 +326,7 @@ OUTER_LOOP:
|
||||
if ok {
|
||||
vote := voteSet.GetByIndex(index)
|
||||
// NOTE: vote may be a commit.
|
||||
msg := p2p.TypedMessage{msgTypeVote, vote}
|
||||
msg := &VoteMessage{index, vote}
|
||||
peer.Send(VoteCh, msg)
|
||||
ps.SetHasVote(vote, index)
|
||||
return true
|
||||
@@ -399,7 +405,7 @@ OUTER_LOOP:
|
||||
BlockParts: header.LastBlockParts,
|
||||
Signature: rsig.Signature,
|
||||
}
|
||||
msg := p2p.TypedMessage{msgTypeVote, vote}
|
||||
msg := &VoteMessage{index, vote}
|
||||
peer.Send(VoteCh, msg)
|
||||
ps.SetHasVote(vote, index)
|
||||
continue OUTER_LOOP
|
||||
@@ -416,8 +422,8 @@ OUTER_LOOP:
|
||||
|
||||
// Read only when returned by PeerState.GetRoundState().
|
||||
type PeerRoundState struct {
|
||||
Height uint32 // Height peer is at
|
||||
Round uint16 // Round peer is at
|
||||
Height uint // Height peer is at
|
||||
Round uint // Round peer is at
|
||||
Step RoundStep // Step peer is at
|
||||
StartTime time.Time // Estimated start of round 0 at this height
|
||||
Proposal bool // True if peer has proposal for this round
|
||||
@@ -474,7 +480,7 @@ func (ps *PeerState) SetHasProposal(proposal *Proposal) {
|
||||
ps.ProposalPOLBitArray = NewBitArray(uint(proposal.POLParts.Total))
|
||||
}
|
||||
|
||||
func (ps *PeerState) SetHasProposalBlockPart(height uint32, round uint16, index uint16) {
|
||||
func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
@@ -485,7 +491,7 @@ func (ps *PeerState) SetHasProposalBlockPart(height uint32, round uint16, index
|
||||
ps.ProposalBlockBitArray.SetIndex(uint(index), true)
|
||||
}
|
||||
|
||||
func (ps *PeerState) SetHasProposalPOLPart(height uint32, round uint16, index uint16) {
|
||||
func (ps *PeerState) SetHasProposalPOLPart(height uint, round uint, index uint) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
@@ -496,7 +502,7 @@ func (ps *PeerState) SetHasProposalPOLPart(height uint32, round uint16, index ui
|
||||
ps.ProposalPOLBitArray.SetIndex(uint(index), true)
|
||||
}
|
||||
|
||||
func (ps *PeerState) EnsureVoteBitArrays(height uint32, numValidators uint) {
|
||||
func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
@@ -521,7 +527,7 @@ func (ps *PeerState) SetHasVote(vote *Vote, index uint) {
|
||||
ps.setHasVote(vote.Height, vote.Round, vote.Type, index)
|
||||
}
|
||||
|
||||
func (ps *PeerState) setHasVote(height uint32, round uint16, type_ byte, index uint) {
|
||||
func (ps *PeerState) setHasVote(height uint, round uint, type_ byte, index uint) {
|
||||
if ps.Height == height+1 && type_ == VoteTypeCommit {
|
||||
// Special case for LastCommits.
|
||||
ps.LastCommits.SetIndex(index, true)
|
||||
@@ -583,7 +589,7 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *Roun
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *PeerState) ApplyCommitMessage(msg *CommitMessage) {
|
||||
func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
@@ -614,15 +620,13 @@ func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeUnknown = byte(0x00)
|
||||
// Messages for communicating state changes
|
||||
msgTypeUnknown = byte(0x00)
|
||||
msgTypeNewRoundStep = byte(0x01)
|
||||
msgTypeCommit = byte(0x02)
|
||||
// Messages of data
|
||||
msgTypeProposal = byte(0x11)
|
||||
msgTypePart = byte(0x12) // both block & POL
|
||||
msgTypeVote = byte(0x13)
|
||||
msgTypeHasVote = byte(0x14)
|
||||
msgTypeCommitStep = byte(0x02)
|
||||
msgTypeProposal = byte(0x11)
|
||||
msgTypePart = byte(0x12) // both block & POL
|
||||
msgTypeVote = byte(0x13)
|
||||
msgTypeHasVote = byte(0x14)
|
||||
)
|
||||
|
||||
// TODO: check for unnecessary extra bytes at the end.
|
||||
@@ -634,18 +638,18 @@ func decodeMessage(bz []byte) (msgType byte, msg interface{}) {
|
||||
switch msgType {
|
||||
// Messages for communicating state changes
|
||||
case msgTypeNewRoundStep:
|
||||
msg = readNewRoundStepMessage(r, n, err)
|
||||
case msgTypeCommit:
|
||||
msg = readCommitMessage(r, n, err)
|
||||
msg = ReadBinary(&NewRoundStepMessage{}, r, n, err)
|
||||
case msgTypeCommitStep:
|
||||
msg = ReadBinary(&CommitStepMessage{}, r, n, err)
|
||||
// Messages of data
|
||||
case msgTypeProposal:
|
||||
msg = ReadProposal(r, n, err)
|
||||
msg = ReadBinary(&Proposal{}, r, n, err)
|
||||
case msgTypePart:
|
||||
msg = readPartMessage(r, n, err)
|
||||
msg = ReadBinary(&PartMessage{}, r, n, err)
|
||||
case msgTypeVote:
|
||||
msg = ReadVote(r, n, err)
|
||||
msg = ReadBinary(&VoteMessage{}, r, n, err)
|
||||
case msgTypeHasVote:
|
||||
msg = readHasVoteMessage(r, n, err)
|
||||
msg = ReadBinary(&HasVoteMessage{}, r, n, err)
|
||||
default:
|
||||
msg = nil
|
||||
}
|
||||
@@ -655,29 +659,13 @@ func decodeMessage(bz []byte) (msgType byte, msg interface{}) {
|
||||
//-------------------------------------
|
||||
|
||||
type NewRoundStepMessage struct {
|
||||
Height uint32
|
||||
Round uint16
|
||||
Height uint
|
||||
Round uint
|
||||
Step RoundStep
|
||||
SecondsSinceStartTime uint32
|
||||
SecondsSinceStartTime uint
|
||||
}
|
||||
|
||||
func readNewRoundStepMessage(r io.Reader, n *int64, err *error) *NewRoundStepMessage {
|
||||
return &NewRoundStepMessage{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
Round: ReadUInt16(r, n, err),
|
||||
Step: RoundStep(ReadUInt8(r, n, err)),
|
||||
SecondsSinceStartTime: ReadUInt32(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *NewRoundStepMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteByte(w, msgTypeNewRoundStep, &n, &err)
|
||||
WriteUInt32(w, m.Height, &n, &err)
|
||||
WriteUInt16(w, m.Round, &n, &err)
|
||||
WriteUInt8(w, uint8(m.Step), &n, &err)
|
||||
WriteUInt32(w, m.SecondsSinceStartTime, &n, &err)
|
||||
return
|
||||
}
|
||||
func (m *NewRoundStepMessage) TypeByte() byte { return msgTypeNewRoundStep }
|
||||
|
||||
func (m *NewRoundStepMessage) String() string {
|
||||
return fmt.Sprintf("[NewRoundStep %v/%v/%X]", m.Height, m.Round, m.Step)
|
||||
@@ -685,30 +673,16 @@ func (m *NewRoundStepMessage) String() string {
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type CommitMessage struct {
|
||||
Height uint32
|
||||
type CommitStepMessage struct {
|
||||
Height uint
|
||||
BlockParts PartSetHeader
|
||||
BlockBitArray BitArray
|
||||
}
|
||||
|
||||
func readCommitMessage(r io.Reader, n *int64, err *error) *CommitMessage {
|
||||
return &CommitMessage{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
BlockParts: ReadPartSetHeader(r, n, err),
|
||||
BlockBitArray: ReadBitArray(r, n, err),
|
||||
}
|
||||
}
|
||||
func (m *CommitStepMessage) TypeByte() byte { return msgTypeCommitStep }
|
||||
|
||||
func (m *CommitMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteByte(w, msgTypeCommit, &n, &err)
|
||||
WriteUInt32(w, m.Height, &n, &err)
|
||||
WriteBinary(w, m.BlockParts, &n, &err)
|
||||
WriteBinary(w, m.BlockBitArray, &n, &err)
|
||||
return
|
||||
}
|
||||
|
||||
func (m *CommitMessage) String() string {
|
||||
return fmt.Sprintf("[Commit %v %v %v]", m.Height, m.BlockParts, m.BlockBitArray)
|
||||
func (m *CommitStepMessage) String() string {
|
||||
return fmt.Sprintf("[CommitStep %v %v %v]", m.Height, m.BlockParts, m.BlockBitArray)
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
@@ -719,29 +693,13 @@ const (
|
||||
)
|
||||
|
||||
type PartMessage struct {
|
||||
Height uint32
|
||||
Round uint16
|
||||
Height uint
|
||||
Round uint
|
||||
Type byte
|
||||
Part *Part
|
||||
}
|
||||
|
||||
func readPartMessage(r io.Reader, n *int64, err *error) *PartMessage {
|
||||
return &PartMessage{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
Round: ReadUInt16(r, n, err),
|
||||
Type: ReadByte(r, n, err),
|
||||
Part: ReadPart(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *PartMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteByte(w, msgTypePart, &n, &err)
|
||||
WriteUInt32(w, m.Height, &n, &err)
|
||||
WriteUInt16(w, m.Round, &n, &err)
|
||||
WriteByte(w, m.Type, &n, &err)
|
||||
WriteBinary(w, m.Part, &n, &err)
|
||||
return
|
||||
}
|
||||
func (m *PartMessage) TypeByte() byte { return msgTypePart }
|
||||
|
||||
func (m *PartMessage) String() string {
|
||||
return fmt.Sprintf("[Part %v/%v T:%X %v]", m.Height, m.Round, m.Type, m.Part)
|
||||
@@ -749,30 +707,27 @@ func (m *PartMessage) String() string {
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type VoteMessage struct {
|
||||
ValidatorIndex uint
|
||||
Vote *Vote
|
||||
}
|
||||
|
||||
func (m *VoteMessage) TypeByte() byte { return msgTypeVote }
|
||||
|
||||
func (m *VoteMessage) String() string {
|
||||
return fmt.Sprintf("[Vote ValidatorIndex:%v Vote:%v]", m.ValidatorIndex, m.Vote)
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type HasVoteMessage struct {
|
||||
Height uint32
|
||||
Round uint16
|
||||
Height uint
|
||||
Round uint
|
||||
Type byte
|
||||
Index uint
|
||||
}
|
||||
|
||||
func readHasVoteMessage(r io.Reader, n *int64, err *error) *HasVoteMessage {
|
||||
return &HasVoteMessage{
|
||||
Height: ReadUInt32(r, n, err),
|
||||
Round: ReadUInt16(r, n, err),
|
||||
Type: ReadByte(r, n, err),
|
||||
Index: ReadUVarInt(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HasVoteMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteByte(w, msgTypeHasVote, &n, &err)
|
||||
WriteUInt32(w, m.Height, &n, &err)
|
||||
WriteUInt16(w, m.Round, &n, &err)
|
||||
WriteByte(w, m.Type, &n, &err)
|
||||
WriteUVarInt(w, m.Index, &n, &err)
|
||||
return
|
||||
}
|
||||
func (m *HasVoteMessage) TypeByte() byte { return msgTypeHasVote }
|
||||
|
||||
func (m *HasVoteMessage) String() string {
|
||||
return fmt.Sprintf("[HasVote %v/%v T:%X]", m.Height, m.Round, m.Type)
|
||||
|
||||
+57
-43
@@ -52,6 +52,7 @@ Consensus State Machine Overview:
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -59,6 +60,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
. "github.com/tendermint/tendermint/account"
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
. "github.com/tendermint/tendermint/blocks"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
@@ -82,7 +84,7 @@ const (
|
||||
RoundActionPrevote = RoundActionType(0xA1) // Prevote and goto RoundStepPrevote
|
||||
RoundActionPrecommit = RoundActionType(0xA2) // Precommit and goto RoundStepPrecommit
|
||||
RoundActionTryCommit = RoundActionType(0xC0) // Goto RoundStepCommit, or RoundStepPropose for next round.
|
||||
RoundActionCommit = RoundActionType(0xC1) // Goto RoundStepCommit
|
||||
RoundActionCommit = RoundActionType(0xC1) // Goto RoundStepCommit upon +2/3 commits
|
||||
RoundActionTryFinalize = RoundActionType(0xC2) // Maybe goto RoundStepPropose for next round.
|
||||
|
||||
roundDuration0 = 60 * time.Second // The first round is 60 seconds long.
|
||||
@@ -97,8 +99,8 @@ var (
|
||||
)
|
||||
|
||||
type RoundAction struct {
|
||||
Height uint32 // The block height for which consensus is reaching for.
|
||||
Round uint16 // The round number at given height.
|
||||
Height uint // The block height for which consensus is reaching for.
|
||||
Round uint // The round number at given height.
|
||||
Action RoundActionType // Action to perform.
|
||||
}
|
||||
|
||||
@@ -106,8 +108,8 @@ type RoundAction struct {
|
||||
|
||||
// Immutable when returned from ConsensusState.GetRoundState()
|
||||
type RoundState struct {
|
||||
Height uint32 // Height we are working on
|
||||
Round uint16
|
||||
Height uint // Height we are working on
|
||||
Round uint
|
||||
Step RoundStep
|
||||
StartTime time.Time
|
||||
CommitTime time.Time // Time when +2/3 commits were found
|
||||
@@ -347,7 +349,6 @@ ACTION_LOOP:
|
||||
if rs.Precommits.HasTwoThirdsMajority() {
|
||||
// Enter RoundStepCommit and commit.
|
||||
cs.RunActionCommit(rs.Height)
|
||||
cs.queueAction(RoundAction{rs.Height, rs.Round, RoundActionTryFinalize})
|
||||
continue ACTION_LOOP
|
||||
} else {
|
||||
// Could not commit, move onto next round.
|
||||
@@ -363,7 +364,6 @@ ACTION_LOOP:
|
||||
}
|
||||
// Enter RoundStepCommit and commit.
|
||||
cs.RunActionCommit(rs.Height)
|
||||
cs.queueAction(RoundAction{rs.Height, rs.Round, RoundActionTryFinalize})
|
||||
continue ACTION_LOOP
|
||||
|
||||
case RoundActionTryFinalize:
|
||||
@@ -435,7 +435,7 @@ func (cs *ConsensusState) updateToState(state *state.State) {
|
||||
}
|
||||
|
||||
// After the call cs.Step becomes RoundStepNewRound.
|
||||
func (cs *ConsensusState) setupNewRound(round uint16) {
|
||||
func (cs *ConsensusState) setupNewRound(round uint) {
|
||||
// Sanity check
|
||||
if round == 0 {
|
||||
panic("setupNewRound() should never be called for round 0")
|
||||
@@ -470,7 +470,7 @@ func (cs *ConsensusState) SetPrivValidator(priv *PrivValidator) {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Set up the round to desired round and set step to RoundStepNewRound
|
||||
func (cs *ConsensusState) SetupNewRound(height uint32, desiredRound uint16) bool {
|
||||
func (cs *ConsensusState) SetupNewRound(height uint, desiredRound uint) bool {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
if cs.Height != height {
|
||||
@@ -485,7 +485,7 @@ func (cs *ConsensusState) SetupNewRound(height uint32, desiredRound uint16) bool
|
||||
return true
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
||||
func (cs *ConsensusState) RunActionPropose(height uint, round uint) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
if cs.Height != height || cs.Round != round {
|
||||
@@ -497,7 +497,7 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
||||
}()
|
||||
|
||||
// Nothing to do if it's not our turn.
|
||||
if cs.PrivValidator == nil || cs.Validators.Proposer().Id != cs.PrivValidator.Id {
|
||||
if cs.PrivValidator == nil || !bytes.Equal(cs.Validators.Proposer().Address, cs.PrivValidator.Address) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
||||
|
||||
// Make proposal
|
||||
proposal := NewProposal(cs.Height, cs.Round, blockParts.Header(), polParts.Header())
|
||||
cs.PrivValidator.Sign(proposal)
|
||||
proposal.Signature = cs.PrivValidator.SignProposal(proposal)
|
||||
|
||||
// Set fields
|
||||
cs.Proposal = proposal
|
||||
@@ -572,7 +572,7 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
||||
|
||||
// Prevote for LockedBlock if we're locked, or ProposealBlock if valid.
|
||||
// Otherwise vote nil.
|
||||
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) {
|
||||
func (cs *ConsensusState) RunActionPrevote(height uint, round uint) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
if cs.Height != height || cs.Round != round {
|
||||
@@ -612,7 +612,7 @@ func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) {
|
||||
|
||||
// Lock & Precommit the ProposalBlock if we have enough prevotes for it,
|
||||
// or unlock an existing lock if +2/3 of prevotes were nil.
|
||||
func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) {
|
||||
func (cs *ConsensusState) RunActionPrecommit(height uint, round uint) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
if cs.Height != height || cs.Round != round {
|
||||
@@ -668,7 +668,11 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) {
|
||||
}
|
||||
|
||||
// Enter commit step. See the diagram for details.
|
||||
func (cs *ConsensusState) RunActionCommit(height uint32) {
|
||||
// There are two ways to enter this step:
|
||||
// * After the Precommit step with +2/3 precommits, or,
|
||||
// * Upon +2/3 commits regardless of current step
|
||||
// Either way this action is run at most once per round.
|
||||
func (cs *ConsensusState) RunActionCommit(height uint) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
if cs.Height != height {
|
||||
@@ -679,6 +683,7 @@ func (cs *ConsensusState) RunActionCommit(height uint32) {
|
||||
cs.newStepCh <- cs.getRoundState()
|
||||
}()
|
||||
|
||||
// Sanity check.
|
||||
// There are two ways to enter:
|
||||
// 1. +2/3 precommits at the end of RoundStepPrecommit
|
||||
// 2. +2/3 commits at any time
|
||||
@@ -712,15 +717,20 @@ func (cs *ConsensusState) RunActionCommit(height uint32) {
|
||||
}
|
||||
} else {
|
||||
// We have the block, so save/stage/sign-commit-vote.
|
||||
cs.saveCommitVoteBlock(cs.ProposalBlock, cs.ProposalBlockParts)
|
||||
}
|
||||
|
||||
cs.processBlockForCommit(cs.ProposalBlock, cs.ProposalBlockParts)
|
||||
// If we have the block AND +2/3 commits, queue RoundActionTryFinalize.
|
||||
// Round will immediately become finalized.
|
||||
if cs.ProposalBlock.HashesTo(hash) && cs.Commits.HasTwoThirdsMajority() {
|
||||
cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns true if Finalize happened, which increments height && sets
|
||||
// the step to RoundStepNewHeight (or RoundStepNewRound, but probably not).
|
||||
func (cs *ConsensusState) TryFinalizeCommit(height uint32) bool {
|
||||
func (cs *ConsensusState) TryFinalizeCommit(height uint) bool {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
|
||||
@@ -754,6 +764,7 @@ func (cs *ConsensusState) TryFinalizeCommit(height uint32) bool {
|
||||
return true
|
||||
} else {
|
||||
// Prevent zombies.
|
||||
// TODO: Does this ever happen?
|
||||
Panicf("+2/3 committed an invalid block: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -782,7 +793,7 @@ func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
if !cs.Validators.Proposer().Verify(proposal) {
|
||||
if !cs.Validators.Proposer().PubKey.VerifyBytes(SignBytes(proposal), proposal.Signature) {
|
||||
return ErrInvalidProposalSignature
|
||||
}
|
||||
|
||||
@@ -794,7 +805,7 @@ func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
|
||||
|
||||
// NOTE: block is not necessarily valid.
|
||||
// NOTE: This function may increment the height.
|
||||
func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
||||
func (cs *ConsensusState) AddProposalBlockPart(height uint, round uint, part *Part) (added bool, err error) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
|
||||
@@ -815,8 +826,11 @@ func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part
|
||||
if added && cs.ProposalBlockParts.IsComplete() {
|
||||
var n int64
|
||||
var err error
|
||||
cs.ProposalBlock = ReadBlock(cs.ProposalBlockParts.GetReader(), &n, &err)
|
||||
cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
|
||||
cs.ProposalBlock = ReadBinary(&Block{}, cs.ProposalBlockParts.GetReader(), &n, &err).(*Block)
|
||||
// If we're already in the commit step, try to finalize round.
|
||||
if cs.Step == RoundStepCommit {
|
||||
cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
|
||||
}
|
||||
// XXX If POL is valid, consider unlocking.
|
||||
return true, err
|
||||
}
|
||||
@@ -824,7 +838,7 @@ func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part
|
||||
}
|
||||
|
||||
// NOTE: POL is not necessarily valid.
|
||||
func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
||||
func (cs *ConsensusState) AddProposalPOLPart(height uint, round uint, part *Part) (added bool, err error) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
|
||||
@@ -844,21 +858,21 @@ func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *
|
||||
if added && cs.ProposalPOLParts.IsComplete() {
|
||||
var n int64
|
||||
var err error
|
||||
cs.ProposalPOL = ReadPOL(cs.ProposalPOLParts.GetReader(), &n, &err)
|
||||
cs.ProposalPOL = ReadBinary(&POL{}, cs.ProposalPOLParts.GetReader(), &n, &err).(*POL)
|
||||
return true, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) AddVote(vote *Vote) (added bool, index uint, err error) {
|
||||
func (cs *ConsensusState) AddVote(address []byte, vote *Vote) (added bool, index uint, err error) {
|
||||
cs.mtx.Lock()
|
||||
defer cs.mtx.Unlock()
|
||||
|
||||
return cs.addVote(vote)
|
||||
return cs.addVote(address, vote)
|
||||
}
|
||||
|
||||
// TODO: Maybe move this out of here?
|
||||
func (cs *ConsensusState) LoadHeaderValidation(height uint32) (*Header, *Validation) {
|
||||
func (cs *ConsensusState) LoadHeaderValidation(height uint) (*Header, *Validation) {
|
||||
meta := cs.blockStore.LoadBlockMeta(height)
|
||||
if meta == nil {
|
||||
return nil, nil
|
||||
@@ -869,21 +883,21 @@ func (cs *ConsensusState) LoadHeaderValidation(height uint32) (*Header, *Validat
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
func (cs *ConsensusState) addVote(vote *Vote) (added bool, index uint, err error) {
|
||||
func (cs *ConsensusState) addVote(address []byte, vote *Vote) (added bool, index uint, err error) {
|
||||
switch vote.Type {
|
||||
case VoteTypePrevote:
|
||||
// Prevotes checks for height+round match.
|
||||
return cs.Prevotes.Add(vote)
|
||||
return cs.Prevotes.Add(address, vote)
|
||||
case VoteTypePrecommit:
|
||||
// Precommits checks for height+round match.
|
||||
return cs.Precommits.Add(vote)
|
||||
return cs.Precommits.Add(address, vote)
|
||||
case VoteTypeCommit:
|
||||
if vote.Height == cs.Height {
|
||||
// No need to check if vote.Round < cs.Round ...
|
||||
// Prevotes && Precommits already checks that.
|
||||
cs.Prevotes.Add(vote)
|
||||
cs.Precommits.Add(vote)
|
||||
added, index, err = cs.Commits.Add(vote)
|
||||
cs.Prevotes.Add(address, vote)
|
||||
cs.Precommits.Add(address, vote)
|
||||
added, index, err = cs.Commits.Add(address, vote)
|
||||
if added && cs.Commits.HasTwoThirdsMajority() && cs.CommitTime.IsZero() {
|
||||
cs.CommitTime = time.Now()
|
||||
log.Debug("Set CommitTime to %v", cs.CommitTime)
|
||||
@@ -896,7 +910,7 @@ func (cs *ConsensusState) addVote(vote *Vote) (added bool, index uint, err error
|
||||
return added, index, err
|
||||
}
|
||||
if vote.Height+1 == cs.Height {
|
||||
return cs.LastCommits.Add(vote)
|
||||
return cs.LastCommits.Add(address, vote)
|
||||
}
|
||||
return false, 0, nil
|
||||
default:
|
||||
@@ -930,7 +944,7 @@ func (cs *ConsensusState) stageBlock(block *Block, blockParts *PartSet) error {
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header PartSetHeader) *Vote {
|
||||
if cs.PrivValidator == nil || !cs.Validators.HasId(cs.PrivValidator.Id) {
|
||||
if cs.PrivValidator == nil || !cs.Validators.HasAddress(cs.PrivValidator.Address) {
|
||||
return nil
|
||||
}
|
||||
vote := &Vote{
|
||||
@@ -940,12 +954,12 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header PartSetHea
|
||||
BlockHash: hash,
|
||||
BlockParts: header,
|
||||
}
|
||||
cs.PrivValidator.Sign(vote)
|
||||
cs.addVote(vote)
|
||||
vote.Signature = cs.PrivValidator.SignVote(vote)
|
||||
cs.addVote(cs.PrivValidator.Address, vote)
|
||||
return vote
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) processBlockForCommit(block *Block, blockParts *PartSet) {
|
||||
func (cs *ConsensusState) saveCommitVoteBlock(block *Block, blockParts *PartSet) {
|
||||
|
||||
// The proposal must be valid.
|
||||
if err := cs.stageBlock(block, blockParts); err != nil {
|
||||
@@ -969,19 +983,19 @@ func (cs *ConsensusState) processBlockForCommit(block *Block, blockParts *PartSe
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// total duration of given round
|
||||
func calcRoundDuration(round uint16) time.Duration {
|
||||
func calcRoundDuration(round uint) time.Duration {
|
||||
return roundDuration0 + roundDurationDelta*time.Duration(round)
|
||||
}
|
||||
|
||||
// startTime is when round zero started.
|
||||
func calcRoundStartTime(round uint16, startTime time.Time) time.Time {
|
||||
func calcRoundStartTime(round uint, startTime time.Time) time.Time {
|
||||
return startTime.Add(roundDuration0*time.Duration(round) +
|
||||
roundDurationDelta*(time.Duration((int64(round)*int64(round)-int64(round))/2)))
|
||||
}
|
||||
|
||||
// calculates the current round given startTime of round zero.
|
||||
// NOTE: round is zero if startTime is in the future.
|
||||
func calcRound(startTime time.Time) uint16 {
|
||||
func calcRound(startTime time.Time) uint {
|
||||
now := time.Now()
|
||||
if now.Before(startTime) {
|
||||
return 0
|
||||
@@ -997,18 +1011,18 @@ func calcRound(startTime time.Time) uint16 {
|
||||
if math.IsNaN(R) {
|
||||
panic("Could not calc round, should not happen")
|
||||
}
|
||||
if R > math.MaxInt16 {
|
||||
if R > math.MaxInt32 {
|
||||
Panicf("Could not calc round, round overflow: %v", R)
|
||||
}
|
||||
if R < 0 {
|
||||
return 0
|
||||
}
|
||||
return uint16(R)
|
||||
return uint(R)
|
||||
}
|
||||
|
||||
// convenience
|
||||
// NOTE: elapsedRatio can be negative if startTime is in the future.
|
||||
func calcRoundInfo(startTime time.Time) (round uint16, roundStartTime time.Time, roundDuration time.Duration,
|
||||
func calcRoundInfo(startTime time.Time) (round uint, roundStartTime time.Time, roundDuration time.Duration,
|
||||
roundElapsed time.Duration, elapsedRatio float64) {
|
||||
round = calcRound(startTime)
|
||||
roundStartTime = calcRoundStartTime(round, startTime)
|
||||
|
||||
+15
-11
@@ -6,23 +6,27 @@ import (
|
||||
|
||||
// Common test methods
|
||||
|
||||
func makeValidator(id uint64, votingPower uint64) (*state.Validator, *state.PrivAccount) {
|
||||
privAccount := state.GenPrivAccount()
|
||||
privAccount.Id = id
|
||||
func makeValidator(votingPower uint64) (*state.Validator, *PrivValidator) {
|
||||
privValidator := GenPrivValidator()
|
||||
return &state.Validator{
|
||||
Account: privAccount.Account,
|
||||
VotingPower: votingPower,
|
||||
}, privAccount
|
||||
Address: privValidator.Address,
|
||||
PubKey: privValidator.PubKey,
|
||||
BondHeight: 0,
|
||||
UnbondHeight: 0,
|
||||
LastCommitHeight: 0,
|
||||
VotingPower: votingPower,
|
||||
Accum: 0,
|
||||
}, privValidator
|
||||
}
|
||||
|
||||
func makeVoteSet(height uint32, round uint16, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*state.PrivAccount) {
|
||||
func makeVoteSet(height uint, round uint, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*PrivValidator) {
|
||||
vals := make([]*state.Validator, numValidators)
|
||||
privAccounts := make([]*state.PrivAccount, numValidators)
|
||||
privValidators := make([]*PrivValidator, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privAccount := makeValidator(uint64(i), votingPower)
|
||||
val, privValidator := makeValidator(votingPower)
|
||||
vals[i] = val
|
||||
privAccounts[i] = privAccount
|
||||
privValidators[i] = privValidator
|
||||
}
|
||||
valSet := state.NewValidatorSet(vals)
|
||||
return NewVoteSet(height, round, type_, valSet), valSet, privAccounts
|
||||
return NewVoteSet(height, round, type_, valSet), valSet, privValidators
|
||||
}
|
||||
|
||||
+112
-128
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
. "github.com/tendermint/tendermint/account"
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
. "github.com/tendermint/tendermint/blocks"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
@@ -16,17 +17,16 @@ import (
|
||||
// for a predefined vote type.
|
||||
// Note that there three kinds of votes: prevotes, precommits, and commits.
|
||||
// A commit of prior rounds can be added added in lieu of votes/precommits.
|
||||
// TODO: test majority calculations etc.
|
||||
// NOTE: assumes that the sum total of voting power does not exceed MaxUInt64.
|
||||
// NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
|
||||
type VoteSet struct {
|
||||
height uint32
|
||||
round uint16
|
||||
height uint
|
||||
round uint
|
||||
type_ byte
|
||||
|
||||
mtx sync.Mutex
|
||||
vset *state.ValidatorSet
|
||||
votes map[uint64]*Vote
|
||||
votesBitArray BitArray
|
||||
valSet *state.ValidatorSet
|
||||
votes []*Vote // validator index -> vote
|
||||
votesBitArray BitArray // validator index -> has vote?
|
||||
votesByBlock map[string]uint64 // string(blockHash)+string(blockParts) -> vote sum.
|
||||
totalVotes uint64
|
||||
maj23Hash []byte
|
||||
@@ -35,7 +35,7 @@ type VoteSet struct {
|
||||
}
|
||||
|
||||
// Constructs a new VoteSet struct used to accumulate votes for each round.
|
||||
func NewVoteSet(height uint32, round uint16, type_ byte, vset *state.ValidatorSet) *VoteSet {
|
||||
func NewVoteSet(height uint, round uint, type_ byte, valSet *state.ValidatorSet) *VoteSet {
|
||||
if height == 0 {
|
||||
panic("Cannot make VoteSet for height == 0, doesn't make sense.")
|
||||
}
|
||||
@@ -46,55 +46,55 @@ func NewVoteSet(height uint32, round uint16, type_ byte, vset *state.ValidatorSe
|
||||
height: height,
|
||||
round: round,
|
||||
type_: type_,
|
||||
vset: vset,
|
||||
votes: make(map[uint64]*Vote, vset.Size()),
|
||||
votesBitArray: NewBitArray(vset.Size()),
|
||||
valSet: valSet,
|
||||
votes: make([]*Vote, valSet.Size()),
|
||||
votesBitArray: NewBitArray(valSet.Size()),
|
||||
votesByBlock: make(map[string]uint64),
|
||||
totalVotes: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (vs *VoteSet) Size() uint {
|
||||
if vs == nil {
|
||||
func (voteSet *VoteSet) Size() uint {
|
||||
if voteSet == nil {
|
||||
return 0
|
||||
} else {
|
||||
return vs.vset.Size()
|
||||
return voteSet.valSet.Size()
|
||||
}
|
||||
}
|
||||
|
||||
// True if added, false if not.
|
||||
// Returns ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
||||
// NOTE: vote should not be mutated after adding.
|
||||
func (vs *VoteSet) Add(vote *Vote) (bool, uint, error) {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
func (voteSet *VoteSet) Add(address []byte, vote *Vote) (bool, uint, error) {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
|
||||
// Make sure the step matches. (or that vote is commit && round < vs.round)
|
||||
if vote.Height != vs.height ||
|
||||
(vote.Type != VoteTypeCommit && vote.Round != vs.round) ||
|
||||
(vote.Type != VoteTypeCommit && vote.Type != vs.type_) ||
|
||||
(vote.Type == VoteTypeCommit && vs.type_ != VoteTypeCommit && vote.Round >= vs.round) {
|
||||
// Make sure the step matches. (or that vote is commit && round < voteSet.round)
|
||||
if vote.Height != voteSet.height ||
|
||||
(vote.Type != VoteTypeCommit && vote.Round != voteSet.round) ||
|
||||
(vote.Type != VoteTypeCommit && vote.Type != voteSet.type_) ||
|
||||
(vote.Type == VoteTypeCommit && voteSet.type_ != VoteTypeCommit && vote.Round >= voteSet.round) {
|
||||
return false, 0, ErrVoteUnexpectedStep
|
||||
}
|
||||
|
||||
// Ensure that signer is a validator.
|
||||
_, val := vs.vset.GetById(vote.SignerId)
|
||||
valIndex, val := voteSet.valSet.GetByAddress(address)
|
||||
if val == nil {
|
||||
return false, 0, ErrVoteInvalidAccount
|
||||
}
|
||||
|
||||
// Check signature.
|
||||
if !val.Verify(vote) {
|
||||
if !val.PubKey.VerifyBytes(SignBytes(vote), vote.Signature) {
|
||||
// Bad signature.
|
||||
return false, 0, ErrVoteInvalidSignature
|
||||
}
|
||||
|
||||
return vs.addVote(vote)
|
||||
return voteSet.addVote(valIndex, vote)
|
||||
}
|
||||
|
||||
func (vs *VoteSet) addVote(vote *Vote) (bool, uint, error) {
|
||||
func (voteSet *VoteSet) addVote(valIndex uint, vote *Vote) (bool, uint, error) {
|
||||
// If vote already exists, return false.
|
||||
if existingVote, ok := vs.votes[vote.SignerId]; ok {
|
||||
if existingVote := voteSet.votes[valIndex]; existingVote != nil {
|
||||
if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
|
||||
return false, 0, nil
|
||||
} else {
|
||||
@@ -103,170 +103,154 @@ func (vs *VoteSet) addVote(vote *Vote) (bool, uint, error) {
|
||||
}
|
||||
|
||||
// Add vote.
|
||||
vs.votes[vote.SignerId] = vote
|
||||
voterIndex, val := vs.vset.GetById(vote.SignerId)
|
||||
_, val := voteSet.valSet.GetByIndex(valIndex)
|
||||
if val == nil {
|
||||
return false, 0, ErrVoteInvalidAccount
|
||||
panic(fmt.Sprintf("Missing validator for index %v", valIndex))
|
||||
}
|
||||
vs.votesBitArray.SetIndex(uint(voterIndex), true)
|
||||
voteSet.votes[valIndex] = vote
|
||||
voteSet.votesBitArray.SetIndex(valIndex, true)
|
||||
blockKey := string(vote.BlockHash) + string(BinaryBytes(vote.BlockParts))
|
||||
totalBlockHashVotes := vs.votesByBlock[blockKey] + val.VotingPower
|
||||
vs.votesByBlock[blockKey] = totalBlockHashVotes
|
||||
vs.totalVotes += val.VotingPower
|
||||
totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower
|
||||
voteSet.votesByBlock[blockKey] = totalBlockHashVotes
|
||||
voteSet.totalVotes += val.VotingPower
|
||||
|
||||
// If we just nudged it up to two thirds majority, add it.
|
||||
if totalBlockHashVotes > vs.vset.TotalVotingPower()*2/3 &&
|
||||
(totalBlockHashVotes-val.VotingPower) <= vs.vset.TotalVotingPower()*2/3 {
|
||||
vs.maj23Hash = vote.BlockHash
|
||||
vs.maj23Parts = vote.BlockParts
|
||||
vs.maj23Exists = true
|
||||
if totalBlockHashVotes > voteSet.valSet.TotalVotingPower()*2/3 &&
|
||||
(totalBlockHashVotes-val.VotingPower) <= voteSet.valSet.TotalVotingPower()*2/3 {
|
||||
voteSet.maj23Hash = vote.BlockHash
|
||||
voteSet.maj23Parts = vote.BlockParts
|
||||
voteSet.maj23Exists = true
|
||||
}
|
||||
|
||||
return true, voterIndex, nil
|
||||
return true, valIndex, nil
|
||||
}
|
||||
|
||||
// Assumes that commits VoteSet is valid.
|
||||
func (vs *VoteSet) AddFromCommits(commits *VoteSet) {
|
||||
commitVotes := commits.AllVotes()
|
||||
for _, commit := range commitVotes {
|
||||
if commit.Round < vs.round {
|
||||
vs.addVote(commit)
|
||||
func (voteSet *VoteSet) AddFromCommits(commits *VoteSet) {
|
||||
for valIndex, commit := range commits.votes {
|
||||
if commit.Round < voteSet.round {
|
||||
voteSet.addVote(uint(valIndex), commit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (vs *VoteSet) BitArray() BitArray {
|
||||
if vs == nil {
|
||||
func (voteSet *VoteSet) BitArray() BitArray {
|
||||
if voteSet == nil {
|
||||
return BitArray{}
|
||||
}
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
return vs.votesBitArray.Copy()
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
return voteSet.votesBitArray.Copy()
|
||||
}
|
||||
|
||||
func (vs *VoteSet) GetByIndex(index uint) *Vote {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
func (voteSet *VoteSet) GetByIndex(valIndex uint) *Vote {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
return voteSet.votes[valIndex]
|
||||
}
|
||||
|
||||
id, val := vs.vset.GetByIndex(index)
|
||||
func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
valIndex, val := voteSet.valSet.GetByAddress(address)
|
||||
if val == nil {
|
||||
panic("GetByIndex(index) returned nil")
|
||||
panic("GetByAddress(address) returned nil")
|
||||
}
|
||||
|
||||
return vs.votes[id]
|
||||
return voteSet.votes[valIndex]
|
||||
}
|
||||
|
||||
func (vs *VoteSet) GetById(id uint64) *Vote {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
return vs.votes[id]
|
||||
}
|
||||
|
||||
func (vs *VoteSet) AllVotes() []*Vote {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
votes := []*Vote{}
|
||||
for _, vote := range vs.votes {
|
||||
votes = append(votes, vote)
|
||||
}
|
||||
return votes
|
||||
}
|
||||
|
||||
func (vs *VoteSet) HasTwoThirdsMajority() bool {
|
||||
if vs == nil {
|
||||
func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
|
||||
if voteSet == nil {
|
||||
return false
|
||||
}
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
return vs.maj23Exists
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
return voteSet.maj23Exists
|
||||
}
|
||||
|
||||
// Returns either a blockhash (or nil) that received +2/3 majority.
|
||||
// If there exists no such majority, returns (nil, false).
|
||||
func (vs *VoteSet) TwoThirdsMajority() (hash []byte, parts PartSetHeader, ok bool) {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
if vs.maj23Exists {
|
||||
return vs.maj23Hash, vs.maj23Parts, true
|
||||
func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts PartSetHeader, ok bool) {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
if voteSet.maj23Exists {
|
||||
return voteSet.maj23Hash, voteSet.maj23Parts, true
|
||||
} else {
|
||||
return nil, PartSetHeader{}, false
|
||||
}
|
||||
}
|
||||
|
||||
func (vs *VoteSet) MakePOL() *POL {
|
||||
if vs.type_ != VoteTypePrevote {
|
||||
func (voteSet *VoteSet) MakePOL() *POL {
|
||||
if voteSet.type_ != VoteTypePrevote {
|
||||
panic("Cannot MakePOL() unless VoteSet.Type is VoteTypePrevote")
|
||||
}
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
if !vs.maj23Exists {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
if !voteSet.maj23Exists {
|
||||
return nil
|
||||
}
|
||||
pol := &POL{
|
||||
Height: vs.height,
|
||||
Round: vs.round,
|
||||
BlockHash: vs.maj23Hash,
|
||||
BlockParts: vs.maj23Parts,
|
||||
Height: voteSet.height,
|
||||
Round: voteSet.round,
|
||||
BlockHash: voteSet.maj23Hash,
|
||||
BlockParts: voteSet.maj23Parts,
|
||||
Votes: make([]POLVoteSignature, voteSet.valSet.Size()),
|
||||
}
|
||||
for _, vote := range vs.votes {
|
||||
if !bytes.Equal(vote.BlockHash, vs.maj23Hash) {
|
||||
for valIndex, vote := range voteSet.votes {
|
||||
if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
|
||||
continue
|
||||
}
|
||||
if !vote.BlockParts.Equals(vs.maj23Parts) {
|
||||
if !vote.BlockParts.Equals(voteSet.maj23Parts) {
|
||||
continue
|
||||
}
|
||||
if vote.Type == VoteTypePrevote {
|
||||
pol.Votes = append(pol.Votes, vote.Signature)
|
||||
} else if vote.Type == VoteTypeCommit {
|
||||
pol.Commits = append(pol.Commits, RoundSignature{vote.Round, vote.Signature})
|
||||
} else {
|
||||
Panicf("Unexpected vote type %X", vote.Type)
|
||||
pol.Votes[valIndex] = POLVoteSignature{
|
||||
Round: vote.Round,
|
||||
Signature: vote.Signature,
|
||||
}
|
||||
}
|
||||
return pol
|
||||
}
|
||||
|
||||
func (vs *VoteSet) MakeValidation() *Validation {
|
||||
if vs.type_ != VoteTypeCommit {
|
||||
func (voteSet *VoteSet) MakeValidation() *Validation {
|
||||
if voteSet.type_ != VoteTypeCommit {
|
||||
panic("Cannot MakeValidation() unless VoteSet.Type is VoteTypeCommit")
|
||||
}
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
if len(vs.maj23Hash) == 0 {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
if len(voteSet.maj23Hash) == 0 {
|
||||
panic("Cannot MakeValidation() unless a blockhash has +2/3")
|
||||
}
|
||||
rsigs := make([]RoundSignature, vs.vset.Size())
|
||||
vs.vset.Iterate(func(index uint, val *state.Validator) bool {
|
||||
vote := vs.votes[val.Id]
|
||||
|
||||
commits := make([]Commit, voteSet.valSet.Size())
|
||||
voteSet.valSet.Iterate(func(valIndex uint, val *state.Validator) bool {
|
||||
vote := voteSet.votes[valIndex]
|
||||
if vote == nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(vote.BlockHash, vs.maj23Hash) {
|
||||
if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
|
||||
return false
|
||||
}
|
||||
if !vote.BlockParts.Equals(vs.maj23Parts) {
|
||||
if !vote.BlockParts.Equals(voteSet.maj23Parts) {
|
||||
return false
|
||||
}
|
||||
rsigs[index] = RoundSignature{vote.Round, vote.Signature}
|
||||
commits[valIndex] = Commit{vote.Round, vote.Signature}
|
||||
return false
|
||||
})
|
||||
return &Validation{
|
||||
Commits: rsigs,
|
||||
Commits: commits,
|
||||
}
|
||||
}
|
||||
|
||||
func (vs *VoteSet) String() string {
|
||||
return vs.StringWithIndent("")
|
||||
func (voteSet *VoteSet) String() string {
|
||||
return voteSet.StringWithIndent("")
|
||||
}
|
||||
|
||||
func (vs *VoteSet) StringWithIndent(indent string) string {
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
func (voteSet *VoteSet) StringWithIndent(indent string) string {
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
|
||||
voteStrings := make([]string, len(vs.votes))
|
||||
voteStrings := make([]string, len(voteSet.votes))
|
||||
counter := 0
|
||||
for _, vote := range vs.votes {
|
||||
for _, vote := range voteSet.votes {
|
||||
voteStrings[counter] = vote.String()
|
||||
counter++
|
||||
}
|
||||
@@ -275,18 +259,18 @@ func (vs *VoteSet) StringWithIndent(indent string) string {
|
||||
%s %v
|
||||
%s %v
|
||||
%s}`,
|
||||
indent, vs.height, vs.round, vs.type_,
|
||||
indent, voteSet.height, voteSet.round, voteSet.type_,
|
||||
indent, strings.Join(voteStrings, "\n"+indent+" "),
|
||||
indent, vs.votesBitArray,
|
||||
indent, voteSet.votesBitArray,
|
||||
indent)
|
||||
}
|
||||
|
||||
func (vs *VoteSet) Description() string {
|
||||
if vs == nil {
|
||||
func (voteSet *VoteSet) Description() string {
|
||||
if voteSet == nil {
|
||||
return "nil-VoteSet"
|
||||
}
|
||||
vs.mtx.Lock()
|
||||
defer vs.mtx.Unlock()
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v %v}`,
|
||||
vs.height, vs.round, vs.type_, vs.votesBitArray)
|
||||
voteSet.height, voteSet.round, voteSet.type_, voteSet.votesBitArray)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user