consensus

package
v0.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2016 License: Apache-2.0 Imports: 22 Imported by: 0

README

The core consensus algorithm.

  • state.go - The state machine as detailed in the whitepaper
  • reactor.go - A reactor that connects the state machine to the gossip network

Go-routine summary

The reactor runs 2 go-routines for each added peer: gossipDataRoutine and gossipVotesRoutine.

The consensus state runs two persistent go-routines: timeoutRoutine and receiveRoutine. Go-routines are also started to trigger timeouts and to avoid blocking when the internalMsgQueue is really backed up.

Replay/WAL

A write-ahead log is used to record all messages processed by the receiveRoutine, which amounts to all inputs to the consensus state machine: messages from peers, messages from ourselves, and timeouts. They can be played back deterministically at startup or using the replay console.

Documentation

Index

Constants

View Source
const (
	StateChannel = byte(0x20)
	DataChannel  = byte(0x21)
	VoteChannel  = byte(0x22)
)
View Source
const (
	RoundStepNewHeight     = RoundStepType(0x01) // Wait til CommitTime + timeoutCommit
	RoundStepNewRound      = RoundStepType(0x02) // Setup new round and go to RoundStepPropose
	RoundStepPropose       = RoundStepType(0x03) // Did propose, gossip proposal
	RoundStepPrevote       = RoundStepType(0x04) // Did prevote, gossip prevotes
	RoundStepPrevoteWait   = RoundStepType(0x05) // Did receive any +2/3 prevotes, start timeout
	RoundStepPrecommit     = RoundStepType(0x06) // Did precommit, gossip precommits
	RoundStepPrecommitWait = RoundStepType(0x07) // Did receive any +2/3 precommits, start timeout
	RoundStepCommit        = RoundStepType(0x08) // Entered commit state machine

)

Variables

View Source
var (
	ErrPeerStateHeightRegression = errors.New("Error peer state height regression")
	ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
)
View Source
var (
	ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
	ErrInvalidProposalPOLRound  = errors.New("Error invalid proposal POL round")
	ErrAddingVote               = errors.New("Error adding vote")
	ErrVoteHeightMismatch       = errors.New("Error vote height mismatch")
)
View Source
var Major = "0" //
View Source
var Minor = "2" // replay refactor
View Source
var Revision = "2" // validation -> commit
View Source
var Spec = "1" // async

kind of arbitrary

View Source
var Version = Fmt("v%s/%s.%s.%s", Spec, Major, Minor, Revision)

Functions

func CompareHRS

func CompareHRS(h1, r1 int, s1 RoundStepType, h2, r2 int, s2 RoundStepType) int

Types

type BlockPartMessage

type BlockPartMessage struct {
	Height int
	Round  int
	Part   *types.Part
}

func (*BlockPartMessage) String

func (m *BlockPartMessage) String() string

type CommitStepMessage added in v0.7.0

type CommitStepMessage struct {
	Height           int
	BlockPartsHeader types.PartSetHeader
	BlockParts       *BitArray
}

func (*CommitStepMessage) String added in v0.7.0

func (m *CommitStepMessage) String() string

type ConsensusLogMessage added in v0.7.0

type ConsensusLogMessage struct {
	Time time.Time                    `json:"time"`
	Msg  ConsensusLogMessageInterface `json:"msg"`
}

type ConsensusLogMessageInterface added in v0.7.0

type ConsensusLogMessageInterface interface{}

type ConsensusMessage

type ConsensusMessage interface{}

func DecodeMessage added in v0.7.0

func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error)

TODO: check for unnecessary extra bytes at the end.

type ConsensusReactor

type ConsensusReactor struct {
	p2p.BaseReactor // QuitService + p2p.Switch
	// contains filtered or unexported fields
}

func NewConsensusReactor

func NewConsensusReactor(consensusState *ConsensusState, blockStore *bc.BlockStore, fastSync bool) *ConsensusReactor

func (*ConsensusReactor) AddPeer

func (conR *ConsensusReactor) AddPeer(peer *p2p.Peer)

Implements Reactor

func (*ConsensusReactor) GetChannels

func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor

Implements Reactor

func (*ConsensusReactor) OnStart

func (conR *ConsensusReactor) OnStart() error

func (*ConsensusReactor) OnStop

func (conR *ConsensusReactor) OnStop()

func (*ConsensusReactor) Receive

func (conR *ConsensusReactor) Receive(chID byte, src *p2p.Peer, msgBytes []byte)

Implements Reactor NOTE: We process these messages even when we're fast_syncing. Messages affect either a peer state or the consensus state. Peer state updates can happen in parallel, but processing of proposals, block parts, and votes are ordered by the receiveRoutine NOTE: blocks on consensus state for proposals, block parts, and votes

func (*ConsensusReactor) RemovePeer

func (conR *ConsensusReactor) RemovePeer(peer *p2p.Peer, reason interface{})

Implements Reactor

func (*ConsensusReactor) SetEventSwitch added in v0.7.0

func (conR *ConsensusReactor) SetEventSwitch(evsw *events.EventSwitch)

implements events.Eventable

func (*ConsensusReactor) SetPrivValidator added in v0.7.0

func (conR *ConsensusReactor) SetPrivValidator(priv *types.PrivValidator)

Sets our private validator account for signing votes.

func (*ConsensusReactor) SwitchToConsensus

func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State)

Switch from the fast_sync to the consensus: reset the state, turn off fast_sync, start the consensus-state-machine

type ConsensusState

type ConsensusState struct {
	QuitService

	RoundState
	// contains filtered or unexported fields
}

Tracks consensus state across block heights and rounds.

func NewConsensusState

func NewConsensusState(config cfg.Config, state *sm.State, proxyAppConn proxy.AppConnConsensus, blockStore *bc.BlockStore, mempool *mempl.Mempool) *ConsensusState

func (*ConsensusState) AddProposalBlockPart

func (cs *ConsensusState) AddProposalBlockPart(height, round int, part *types.Part, peerKey string) error

May block on send if queue is full.

func (*ConsensusState) AddVote

func (cs *ConsensusState) AddVote(valIndex int, vote *types.Vote, peerKey string) (added bool, address []byte, err error)

May block on send if queue is full.

func (*ConsensusState) GetRoundState

func (cs *ConsensusState) GetRoundState() *RoundState

func (*ConsensusState) GetState

func (cs *ConsensusState) GetState() *sm.State

func (*ConsensusState) OnStart

func (cs *ConsensusState) OnStart() error

func (*ConsensusState) OnStop

func (cs *ConsensusState) OnStop()

func (*ConsensusState) OpenWAL

func (cs *ConsensusState) OpenWAL(file string) (err error)

Open file to log all consensus messages and timeouts for deterministic accountability

func (ConsensusState) ReplayConsole added in v0.7.0

func (cs ConsensusState) ReplayConsole(file string) error

Interactive playback

func (ConsensusState) ReplayMessages added in v0.7.0

func (cs ConsensusState) ReplayMessages(file string) error

Full playback, with tests

func (*ConsensusState) SetEventSwitch added in v0.7.0

func (cs *ConsensusState) SetEventSwitch(evsw *events.EventSwitch)

implements events.Eventable

func (*ConsensusState) SetPrivValidator

func (cs *ConsensusState) SetPrivValidator(priv *types.PrivValidator)

func (*ConsensusState) SetProposal

func (cs *ConsensusState) SetProposal(proposal *types.Proposal, peerKey string) error

May block on send if queue is full.

func (*ConsensusState) SetProposalAndBlock

func (cs *ConsensusState) SetProposalAndBlock(proposal *types.Proposal, block *types.Block, parts *types.PartSet, peerKey string) error

May block on send if queue is full.

func (*ConsensusState) String

func (cs *ConsensusState) String() string

type HasVoteMessage

type HasVoteMessage struct {
	Height int
	Round  int
	Type   byte
	Index  int
}

func (*HasVoteMessage) String

func (m *HasVoteMessage) String() string

type HeightVoteSet added in v0.7.0

type HeightVoteSet struct {
	// contains filtered or unexported fields
}

Keeps track of all VoteSets from round 0 to round 'round'.

Also keeps track of up to one RoundVoteSet greater than 'round' from each peer, to facilitate catchup syncing of commits.

A commit is +2/3 precommits for a block at a round, but which round is not known in advance, so when a peer provides a precommit for a round greater than mtx.round, we create a new entry in roundVoteSets but also remember the peer to prevent abuse.

func NewHeightVoteSet added in v0.7.0

func NewHeightVoteSet(chainID string, height int, valSet *types.ValidatorSet) *HeightVoteSet

func (*HeightVoteSet) AddByIndex added in v0.7.0

func (hvs *HeightVoteSet) AddByIndex(valIndex int, vote *types.Vote, peerKey string) (added bool, address []byte, err error)

Duplicate votes return added=false, err=nil. By convention, peerKey is "" if origin is self.

func (*HeightVoteSet) Height added in v0.7.0

func (hvs *HeightVoteSet) Height() int

func (*HeightVoteSet) POLRound added in v0.7.0

func (hvs *HeightVoteSet) POLRound() int

Last round that has +2/3 prevotes for a particular block or nil. Returns -1 if no such round exists.

func (*HeightVoteSet) Precommits added in v0.7.0

func (hvs *HeightVoteSet) Precommits(round int) *types.VoteSet

func (*HeightVoteSet) Prevotes added in v0.7.0

func (hvs *HeightVoteSet) Prevotes(round int) *types.VoteSet

func (*HeightVoteSet) Reset added in v0.7.0

func (hvs *HeightVoteSet) Reset(height int, valSet *types.ValidatorSet)

func (*HeightVoteSet) Round added in v0.7.0

func (hvs *HeightVoteSet) Round() int

func (*HeightVoteSet) SetRound added in v0.7.0

func (hvs *HeightVoteSet) SetRound(round int)

Create more RoundVoteSets up to round.

func (*HeightVoteSet) String added in v0.7.0

func (hvs *HeightVoteSet) String() string

func (*HeightVoteSet) StringIndented added in v0.7.0

func (hvs *HeightVoteSet) StringIndented(indent string) string

type NewRoundStepMessage

type NewRoundStepMessage struct {
	Height                int
	Round                 int
	Step                  RoundStepType
	SecondsSinceStartTime int
	LastCommitRound       int
}

For every height/round/step transition

func (*NewRoundStepMessage) String

func (m *NewRoundStepMessage) String() string

type PeerRoundState added in v0.7.0

type PeerRoundState struct {
	Height                   int                 // Height peer is at
	Round                    int                 // Round peer is at, -1 if unknown.
	Step                     RoundStepType       // 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
	ProposalBlockPartsHeader types.PartSetHeader //
	ProposalBlockParts       *BitArray           //
	ProposalPOLRound         int                 // Proposal's POL round. -1 if none.
	ProposalPOL              *BitArray           // nil until ProposalPOLMessage received.
	Prevotes                 *BitArray           // All votes peer has for this round
	Precommits               *BitArray           // All precommits peer has for this round
	LastCommitRound          int                 // Round of commit for last height. -1 if none.
	LastCommit               *BitArray           // All commit precommits of commit for last height.
	CatchupCommitRound       int                 // Round that we have commit for. Not necessarily unique. -1 if none.
	CatchupCommit            *BitArray           // All commit precommits peer has for this height & CatchupCommitRound
}

Read only when returned by PeerState.GetRoundState().

type PeerState

type PeerState struct {
	Peer *p2p.Peer

	PeerRoundState
	// contains filtered or unexported fields
}

func NewPeerState

func NewPeerState(peer *p2p.Peer) *PeerState

func (*PeerState) ApplyCommitStepMessage added in v0.7.0

func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage)

func (*PeerState) ApplyHasVoteMessage

func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage)

func (*PeerState) ApplyNewRoundStepMessage

func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage)

func (*PeerState) ApplyProposalPOLMessage

func (ps *PeerState) ApplyProposalPOLMessage(msg *ProposalPOLMessage)

func (*PeerState) EnsureVoteBitArrays

func (ps *PeerState) EnsureVoteBitArrays(height int, numValidators int)

NOTE: It's important to make sure that numValidators actually matches what the node sees as the number of validators for height.

func (*PeerState) GetHeight

func (ps *PeerState) GetHeight() int

Returns an atomic snapshot of the PeerRoundState's height used by the mempool to ensure peers are caught up before broadcasting new txs

func (*PeerState) GetRoundState

func (ps *PeerState) GetRoundState() *PeerRoundState

Returns an atomic snapshot of the PeerRoundState. There's no point in mutating it since it won't change PeerState.

func (*PeerState) PickSendVote

func (ps *PeerState) PickSendVote(votes types.VoteSetReader) (ok bool)

Convenience function to send vote to peer. Returns true if vote was sent.

func (*PeerState) PickVoteToSend

func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (index int, vote *types.Vote, ok bool)

votes: Must be the correct Size() for the Height().

func (*PeerState) SetHasProposal

func (ps *PeerState) SetHasProposal(proposal *types.Proposal)

func (*PeerState) SetHasProposalBlockPart

func (ps *PeerState) SetHasProposalBlockPart(height int, round int, index int)

func (*PeerState) SetHasVote

func (ps *PeerState) SetHasVote(vote *types.Vote, index int)

type ProposalMessage

type ProposalMessage struct {
	Proposal *types.Proposal
}

func (*ProposalMessage) String

func (m *ProposalMessage) String() string

type ProposalPOLMessage

type ProposalPOLMessage struct {
	Height           int
	ProposalPOLRound int
	ProposalPOL      *BitArray
}

func (*ProposalPOLMessage) String

func (m *ProposalPOLMessage) String() string

type RoundState added in v0.7.0

type RoundState struct {
	Height             int // Height we are working on
	Round              int
	Step               RoundStepType
	StartTime          time.Time
	CommitTime         time.Time // Subjective time when +2/3 precommits for Block at Round were found
	Validators         *types.ValidatorSet
	Proposal           *types.Proposal
	ProposalBlock      *types.Block
	ProposalBlockParts *types.PartSet
	LockedRound        int
	LockedBlock        *types.Block
	LockedBlockParts   *types.PartSet
	Votes              *HeightVoteSet
	CommitRound        int            //
	LastCommit         *types.VoteSet // Last precommits at Height-1
	LastValidators     *types.ValidatorSet
}

Immutable when returned from ConsensusState.GetRoundState()

func (*RoundState) RoundStateEvent added in v0.7.0

func (rs *RoundState) RoundStateEvent() types.EventDataRoundState

func (*RoundState) String added in v0.7.0

func (rs *RoundState) String() string

func (*RoundState) StringIndented added in v0.7.0

func (rs *RoundState) StringIndented(indent string) string

func (*RoundState) StringShort added in v0.7.0

func (rs *RoundState) StringShort() string

type RoundStepType added in v0.7.0

type RoundStepType uint8 // These must be numeric, ordered.

func (RoundStepType) String added in v0.7.0

func (rs RoundStepType) String() string

type RoundVoteSet added in v0.7.0

type RoundVoteSet struct {
	Prevotes   *types.VoteSet
	Precommits *types.VoteSet
}

type TimeoutParams added in v0.7.0

type TimeoutParams struct {
	Propose0       int
	ProposeDelta   int
	Prevote0       int
	PrevoteDelta   int
	Precommit0     int
	PrecommitDelta int
	Commit0        int
}

All in milliseconds

func InitTimeoutParamsFromConfig added in v0.7.0

func InitTimeoutParamsFromConfig(config cfg.Config) *TimeoutParams

Initialize parameters from config

func (*TimeoutParams) Commit added in v0.7.0

func (tp *TimeoutParams) Commit(t time.Time) time.Time

After receiving +2/3 precommits for a single block (a commit), wait this long for stragglers in the next height's RoundStepNewHeight

func (*TimeoutParams) Precommit added in v0.7.0

func (tp *TimeoutParams) Precommit(round int) time.Duration

After receiving any +2/3 precommits, wait this long for stragglers

func (*TimeoutParams) Prevote added in v0.7.0

func (tp *TimeoutParams) Prevote(round int) time.Duration

After receiving any +2/3 prevote, wait this long for stragglers

func (*TimeoutParams) Propose added in v0.7.0

func (tp *TimeoutParams) Propose(round int) time.Duration

Wait this long for a proposal

type VoteMessage

type VoteMessage struct {
	ValidatorIndex int
	Vote           *types.Vote
}

func (*VoteMessage) String

func (m *VoteMessage) String() string

type WAL

type WAL struct {
	// contains filtered or unexported fields
}

Write ahead logger writes msgs to disk before they are processed. Can be used for crash-recovery and deterministic replay TODO: currently the wal is overwritten during replay catchup

give it a mode so it's either reading or appending - must read to end to start appending again

func NewWAL

func NewWAL(file string, light bool) (*WAL, error)

func (*WAL) Close added in v0.7.0

func (wal *WAL) Close()

Must not be called concurrently with a write.

func (*WAL) Exists added in v0.7.1

func (wal *WAL) Exists() bool

func (*WAL) Save added in v0.7.0

func (wal *WAL) Save(clm ConsensusLogMessageInterface)

called in newStep and for each pass in receiveRoutine

func (*WAL) SeekFromEnd added in v0.7.0

func (wal *WAL) SeekFromEnd(found func([]byte) bool) (nLines int, err error)

func (*WAL) Wait

func (wal *WAL) Wait()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL