mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-29 06:01:21 +00:00
Merge pull request #724 from tendermint/708-leaving-out-params-crashes-tm-rpc
Leaving out params crashes tm rpc
This commit is contained in:
commit
a458da8f92
@ -15,6 +15,7 @@ import (
|
|||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
bc "github.com/tendermint/tendermint/blockchain"
|
bc "github.com/tendermint/tendermint/blockchain"
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
mempl "github.com/tendermint/tendermint/mempool"
|
mempl "github.com/tendermint/tendermint/mempool"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
@ -456,7 +457,7 @@ func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) {
|
|||||||
if m.onlyOnce && m.fired {
|
if m.onlyOnce && m.fired {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ti.Step == RoundStepNewHeight {
|
if ti.Step == cstypes.RoundStepNewHeight {
|
||||||
m.c <- ti
|
m.c <- ti
|
||||||
m.fired = true
|
m.fired = true
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
@ -321,7 +322,7 @@ func (conR *ConsensusReactor) FastSync() bool {
|
|||||||
func (conR *ConsensusReactor) registerEventCallbacks() {
|
func (conR *ConsensusReactor) registerEventCallbacks() {
|
||||||
|
|
||||||
types.AddListenerForEvent(conR.evsw, "conR", types.EventStringNewRoundStep(), func(data types.TMEventData) {
|
types.AddListenerForEvent(conR.evsw, "conR", types.EventStringNewRoundStep(), func(data types.TMEventData) {
|
||||||
rs := data.Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := data.Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
conR.broadcastNewRoundStep(rs)
|
conR.broadcastNewRoundStep(rs)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -344,7 +345,7 @@ func (conR *ConsensusReactor) broadcastProposalHeartbeatMessage(heartbeat types.
|
|||||||
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
|
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conR *ConsensusReactor) broadcastNewRoundStep(rs *RoundState) {
|
func (conR *ConsensusReactor) broadcastNewRoundStep(rs *cstypes.RoundState) {
|
||||||
|
|
||||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||||
if nrsMsg != nil {
|
if nrsMsg != nil {
|
||||||
@ -381,7 +382,7 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
func makeRoundStepMessages(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
||||||
nrsMsg = &NewRoundStepMessage{
|
nrsMsg = &NewRoundStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
Round: rs.Round,
|
Round: rs.Round,
|
||||||
@ -389,7 +390,7 @@ func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *
|
|||||||
SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
|
SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
|
||||||
LastCommitRound: rs.LastCommit.Round(),
|
LastCommitRound: rs.LastCommit.Round(),
|
||||||
}
|
}
|
||||||
if rs.Step == RoundStepCommit {
|
if rs.Step == cstypes.RoundStepCommit {
|
||||||
csMsg = &CommitStepMessage{
|
csMsg = &CommitStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
||||||
@ -491,8 +492,8 @@ OUTER_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conR *ConsensusReactor) gossipDataForCatchup(logger log.Logger, rs *RoundState,
|
func (conR *ConsensusReactor) gossipDataForCatchup(logger log.Logger, rs *cstypes.RoundState,
|
||||||
prs *PeerRoundState, ps *PeerState, peer p2p.Peer) {
|
prs *cstypes.PeerRoundState, ps *PeerState, peer p2p.Peer) {
|
||||||
|
|
||||||
if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
|
if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
|
||||||
// Ensure that the peer's PartSetHeader is correct
|
// Ensure that the peer's PartSetHeader is correct
|
||||||
@ -606,24 +607,24 @@ OUTER_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conR *ConsensusReactor) gossipVotesForHeight(logger log.Logger, rs *RoundState, prs *PeerRoundState, ps *PeerState) bool {
|
func (conR *ConsensusReactor) gossipVotesForHeight(logger log.Logger, rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState) bool {
|
||||||
|
|
||||||
// If there are lastCommits to send...
|
// If there are lastCommits to send...
|
||||||
if prs.Step == RoundStepNewHeight {
|
if prs.Step == cstypes.RoundStepNewHeight {
|
||||||
if ps.PickSendVote(rs.LastCommit) {
|
if ps.PickSendVote(rs.LastCommit) {
|
||||||
logger.Debug("Picked rs.LastCommit to send")
|
logger.Debug("Picked rs.LastCommit to send")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are prevotes to send...
|
// If there are prevotes to send...
|
||||||
if prs.Step <= RoundStepPrevote && prs.Round != -1 && prs.Round <= rs.Round {
|
if prs.Step <= cstypes.RoundStepPrevote && prs.Round != -1 && prs.Round <= rs.Round {
|
||||||
if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
|
if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
|
||||||
logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
|
logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are precommits to send...
|
// If there are precommits to send...
|
||||||
if prs.Step <= RoundStepPrecommit && prs.Round != -1 && prs.Round <= rs.Round {
|
if prs.Step <= cstypes.RoundStepPrecommit && prs.Round != -1 && prs.Round <= rs.Round {
|
||||||
if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) {
|
if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) {
|
||||||
logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round)
|
logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round)
|
||||||
return true
|
return true
|
||||||
@ -752,54 +753,6 @@ func (conR *ConsensusReactor) StringIndented(indent string) string {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// PeerRoundState contains the known state of a peer.
|
|
||||||
// NOTE: Read-only when returned by PeerState.GetRoundState().
|
|
||||||
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 *cmn.BitArray //
|
|
||||||
ProposalPOLRound int // Proposal's POL round. -1 if none.
|
|
||||||
ProposalPOL *cmn.BitArray // nil until ProposalPOLMessage received.
|
|
||||||
Prevotes *cmn.BitArray // All votes peer has for this round
|
|
||||||
Precommits *cmn.BitArray // All precommits peer has for this round
|
|
||||||
LastCommitRound int // Round of commit for last height. -1 if none.
|
|
||||||
LastCommit *cmn.BitArray // All commit precommits of commit for last height.
|
|
||||||
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none.
|
|
||||||
CatchupCommit *cmn.BitArray // All commit precommits peer has for this height & CatchupCommitRound
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of the PeerRoundState
|
|
||||||
func (prs PeerRoundState) String() string {
|
|
||||||
return prs.StringIndented("")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringIndented returns a string representation of the PeerRoundState
|
|
||||||
func (prs PeerRoundState) StringIndented(indent string) string {
|
|
||||||
return fmt.Sprintf(`PeerRoundState{
|
|
||||||
%s %v/%v/%v @%v
|
|
||||||
%s Proposal %v -> %v
|
|
||||||
%s POL %v (round %v)
|
|
||||||
%s Prevotes %v
|
|
||||||
%s Precommits %v
|
|
||||||
%s LastCommit %v (round %v)
|
|
||||||
%s Catchup %v (round %v)
|
|
||||||
%s}`,
|
|
||||||
indent, prs.Height, prs.Round, prs.Step, prs.StartTime,
|
|
||||||
indent, prs.ProposalBlockPartsHeader, prs.ProposalBlockParts,
|
|
||||||
indent, prs.ProposalPOL, prs.ProposalPOLRound,
|
|
||||||
indent, prs.Prevotes,
|
|
||||||
indent, prs.Precommits,
|
|
||||||
indent, prs.LastCommit, prs.LastCommitRound,
|
|
||||||
indent, prs.CatchupCommit, prs.CatchupCommitRound,
|
|
||||||
indent)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrPeerStateHeightRegression = errors.New("Error peer state height regression")
|
ErrPeerStateHeightRegression = errors.New("Error peer state height regression")
|
||||||
ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
|
ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
|
||||||
@ -812,7 +765,7 @@ type PeerState struct {
|
|||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
PeerRoundState
|
cstypes.PeerRoundState
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeerState returns a new PeerState for the given Peer
|
// NewPeerState returns a new PeerState for the given Peer
|
||||||
@ -820,7 +773,7 @@ func NewPeerState(peer p2p.Peer) *PeerState {
|
|||||||
return &PeerState{
|
return &PeerState{
|
||||||
Peer: peer,
|
Peer: peer,
|
||||||
logger: log.NewNopLogger(),
|
logger: log.NewNopLogger(),
|
||||||
PeerRoundState: PeerRoundState{
|
PeerRoundState: cstypes.PeerRoundState{
|
||||||
Round: -1,
|
Round: -1,
|
||||||
ProposalPOLRound: -1,
|
ProposalPOLRound: -1,
|
||||||
LastCommitRound: -1,
|
LastCommitRound: -1,
|
||||||
@ -836,7 +789,7 @@ func (ps *PeerState) SetLogger(logger log.Logger) *PeerState {
|
|||||||
|
|
||||||
// GetRoundState returns an atomic snapshot of the PeerRoundState.
|
// GetRoundState returns an atomic snapshot of the PeerRoundState.
|
||||||
// There's no point in mutating it since it won't change PeerState.
|
// There's no point in mutating it since it won't change PeerState.
|
||||||
func (ps *PeerState) GetRoundState() *PeerRoundState {
|
func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
@ -1227,7 +1180,7 @@ func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error) {
|
|||||||
type NewRoundStepMessage struct {
|
type NewRoundStepMessage struct {
|
||||||
Height int
|
Height int
|
||||||
Round int
|
Round int
|
||||||
Step RoundStepType
|
Step cstypes.RoundStepType
|
||||||
SecondsSinceStartTime int
|
SecondsSinceStartTime int
|
||||||
LastCommitRound int
|
LastCommitRound int
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
@ -39,124 +40,6 @@ var (
|
|||||||
ErrVoteHeightMismatch = errors.New("Error vote height mismatch")
|
ErrVoteHeightMismatch = errors.New("Error vote height mismatch")
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// RoundStepType enum type
|
|
||||||
|
|
||||||
// RoundStepType enumerates the state of the consensus state machine
|
|
||||||
type RoundStepType uint8 // These must be numeric, ordered.
|
|
||||||
|
|
||||||
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
|
|
||||||
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
|
|
||||||
)
|
|
||||||
|
|
||||||
// String returns a string
|
|
||||||
func (rs RoundStepType) String() string {
|
|
||||||
switch rs {
|
|
||||||
case RoundStepNewHeight:
|
|
||||||
return "RoundStepNewHeight"
|
|
||||||
case RoundStepNewRound:
|
|
||||||
return "RoundStepNewRound"
|
|
||||||
case RoundStepPropose:
|
|
||||||
return "RoundStepPropose"
|
|
||||||
case RoundStepPrevote:
|
|
||||||
return "RoundStepPrevote"
|
|
||||||
case RoundStepPrevoteWait:
|
|
||||||
return "RoundStepPrevoteWait"
|
|
||||||
case RoundStepPrecommit:
|
|
||||||
return "RoundStepPrecommit"
|
|
||||||
case RoundStepPrecommitWait:
|
|
||||||
return "RoundStepPrecommitWait"
|
|
||||||
case RoundStepCommit:
|
|
||||||
return "RoundStepCommit"
|
|
||||||
default:
|
|
||||||
return "RoundStepUnknown" // Cannot panic.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// RoundState defines the internal consensus state.
|
|
||||||
// It is Immutable when returned from ConsensusState.GetRoundState()
|
|
||||||
// TODO: Actually, only the top pointer is copied,
|
|
||||||
// so access to field pointers is still racey
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundStateEvent returns the H/R/S of the RoundState as an event.
|
|
||||||
func (rs *RoundState) RoundStateEvent() types.EventDataRoundState {
|
|
||||||
edrs := types.EventDataRoundState{
|
|
||||||
Height: rs.Height,
|
|
||||||
Round: rs.Round,
|
|
||||||
Step: rs.Step.String(),
|
|
||||||
RoundState: rs,
|
|
||||||
}
|
|
||||||
return edrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string
|
|
||||||
func (rs *RoundState) String() string {
|
|
||||||
return rs.StringIndented("")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringIndented returns a string
|
|
||||||
func (rs *RoundState) StringIndented(indent string) string {
|
|
||||||
return fmt.Sprintf(`RoundState{
|
|
||||||
%s H:%v R:%v S:%v
|
|
||||||
%s StartTime: %v
|
|
||||||
%s CommitTime: %v
|
|
||||||
%s Validators: %v
|
|
||||||
%s Proposal: %v
|
|
||||||
%s ProposalBlock: %v %v
|
|
||||||
%s LockedRound: %v
|
|
||||||
%s LockedBlock: %v %v
|
|
||||||
%s Votes: %v
|
|
||||||
%s LastCommit: %v
|
|
||||||
%s LastValidators: %v
|
|
||||||
%s}`,
|
|
||||||
indent, rs.Height, rs.Round, rs.Step,
|
|
||||||
indent, rs.StartTime,
|
|
||||||
indent, rs.CommitTime,
|
|
||||||
indent, rs.Validators.StringIndented(indent+" "),
|
|
||||||
indent, rs.Proposal,
|
|
||||||
indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
|
|
||||||
indent, rs.LockedRound,
|
|
||||||
indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
|
|
||||||
indent, rs.Votes.StringIndented(indent+" "),
|
|
||||||
indent, rs.LastCommit.StringShort(),
|
|
||||||
indent, rs.LastValidators.StringIndented(indent+" "),
|
|
||||||
indent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringShort returns a string
|
|
||||||
func (rs *RoundState) StringShort() string {
|
|
||||||
return fmt.Sprintf(`RoundState{H:%v R:%v S:%v ST:%v}`,
|
|
||||||
rs.Height, rs.Round, rs.Step, rs.StartTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -171,10 +54,10 @@ type msgInfo struct {
|
|||||||
|
|
||||||
// internally generated messages which may update the state
|
// internally generated messages which may update the state
|
||||||
type timeoutInfo struct {
|
type timeoutInfo struct {
|
||||||
Duration time.Duration `json:"duration"`
|
Duration time.Duration `json:"duration"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
Round int `json:"round"`
|
Round int `json:"round"`
|
||||||
Step RoundStepType `json:"step"`
|
Step cstypes.RoundStepType `json:"step"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ti *timeoutInfo) String() string {
|
func (ti *timeoutInfo) String() string {
|
||||||
@ -199,7 +82,7 @@ type ConsensusState struct {
|
|||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
RoundState
|
cstypes.RoundState
|
||||||
state *sm.State // State until height-1.
|
state *sm.State // State until height-1.
|
||||||
|
|
||||||
// state changes may be triggered by msgs from peers,
|
// state changes may be triggered by msgs from peers,
|
||||||
@ -282,13 +165,13 @@ func (cs *ConsensusState) GetState() *sm.State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRoundState returns a copy of the internal consensus state.
|
// GetRoundState returns a copy of the internal consensus state.
|
||||||
func (cs *ConsensusState) GetRoundState() *RoundState {
|
func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
return cs.getRoundState()
|
return cs.getRoundState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) getRoundState() *RoundState {
|
func (cs *ConsensusState) getRoundState() *cstypes.RoundState {
|
||||||
rs := cs.RoundState // copy
|
rs := cs.RoundState // copy
|
||||||
return &rs
|
return &rs
|
||||||
}
|
}
|
||||||
@ -469,20 +352,20 @@ func (cs *ConsensusState) updateHeight(height int) {
|
|||||||
cs.Height = height
|
cs.Height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) updateRoundStep(round int, step RoundStepType) {
|
func (cs *ConsensusState) updateRoundStep(round int, step cstypes.RoundStepType) {
|
||||||
cs.Round = round
|
cs.Round = round
|
||||||
cs.Step = step
|
cs.Step = step
|
||||||
}
|
}
|
||||||
|
|
||||||
// enterNewRound(height, 0) at cs.StartTime.
|
// enterNewRound(height, 0) at cs.StartTime.
|
||||||
func (cs *ConsensusState) scheduleRound0(rs *RoundState) {
|
func (cs *ConsensusState) scheduleRound0(rs *cstypes.RoundState) {
|
||||||
//cs.Logger.Info("scheduleRound0", "now", time.Now(), "startTime", cs.StartTime)
|
//cs.Logger.Info("scheduleRound0", "now", time.Now(), "startTime", cs.StartTime)
|
||||||
sleepDuration := rs.StartTime.Sub(time.Now())
|
sleepDuration := rs.StartTime.Sub(time.Now())
|
||||||
cs.scheduleTimeout(sleepDuration, rs.Height, 0, RoundStepNewHeight)
|
cs.scheduleTimeout(sleepDuration, rs.Height, 0, cstypes.RoundStepNewHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to schedule a timeout (by sending timeoutInfo on the tickChan)
|
// Attempt to schedule a timeout (by sending timeoutInfo on the tickChan)
|
||||||
func (cs *ConsensusState) scheduleTimeout(duration time.Duration, height, round int, step RoundStepType) {
|
func (cs *ConsensusState) scheduleTimeout(duration time.Duration, height, round int, step cstypes.RoundStepType) {
|
||||||
cs.timeoutTicker.ScheduleTimeout(timeoutInfo{duration, height, round, step})
|
cs.timeoutTicker.ScheduleTimeout(timeoutInfo{duration, height, round, step})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +407,7 @@ func (cs *ConsensusState) reconstructLastCommit(state *sm.State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Updates ConsensusState and increments height to match that of state.
|
// Updates ConsensusState and increments height to match that of state.
|
||||||
// The round becomes 0 and cs.Step becomes RoundStepNewHeight.
|
// The round becomes 0 and cs.Step becomes cstypes.RoundStepNewHeight.
|
||||||
func (cs *ConsensusState) updateToState(state *sm.State) {
|
func (cs *ConsensusState) updateToState(state *sm.State) {
|
||||||
if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight {
|
if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight {
|
||||||
cmn.PanicSanity(cmn.Fmt("updateToState() expected state height of %v but found %v",
|
cmn.PanicSanity(cmn.Fmt("updateToState() expected state height of %v but found %v",
|
||||||
@ -560,7 +443,7 @@ func (cs *ConsensusState) updateToState(state *sm.State) {
|
|||||||
|
|
||||||
// RoundState fields
|
// RoundState fields
|
||||||
cs.updateHeight(height)
|
cs.updateHeight(height)
|
||||||
cs.updateRoundStep(0, RoundStepNewHeight)
|
cs.updateRoundStep(0, cstypes.RoundStepNewHeight)
|
||||||
if cs.CommitTime.IsZero() {
|
if cs.CommitTime.IsZero() {
|
||||||
// "Now" makes it easier to sync up dev nodes.
|
// "Now" makes it easier to sync up dev nodes.
|
||||||
// We add timeoutCommit to allow transactions
|
// We add timeoutCommit to allow transactions
|
||||||
@ -578,7 +461,7 @@ func (cs *ConsensusState) updateToState(state *sm.State) {
|
|||||||
cs.LockedRound = 0
|
cs.LockedRound = 0
|
||||||
cs.LockedBlock = nil
|
cs.LockedBlock = nil
|
||||||
cs.LockedBlockParts = nil
|
cs.LockedBlockParts = nil
|
||||||
cs.Votes = NewHeightVoteSet(state.ChainID, height, validators)
|
cs.Votes = cstypes.NewHeightVoteSet(state.ChainID, height, validators)
|
||||||
cs.CommitRound = -1
|
cs.CommitRound = -1
|
||||||
cs.LastCommit = lastPrecommits
|
cs.LastCommit = lastPrecommits
|
||||||
cs.LastValidators = state.LastValidators
|
cs.LastValidators = state.LastValidators
|
||||||
@ -699,7 +582,7 @@ func (cs *ConsensusState) handleMsg(mi msgInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs RoundState) {
|
func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) {
|
||||||
cs.Logger.Debug("Received tock", "timeout", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
|
cs.Logger.Debug("Received tock", "timeout", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
|
||||||
|
|
||||||
// timeouts must be for current height, round, step
|
// timeouts must be for current height, round, step
|
||||||
@ -713,19 +596,19 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs RoundState) {
|
|||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
|
|
||||||
switch ti.Step {
|
switch ti.Step {
|
||||||
case RoundStepNewHeight:
|
case cstypes.RoundStepNewHeight:
|
||||||
// NewRound event fired from enterNewRound.
|
// NewRound event fired from enterNewRound.
|
||||||
// XXX: should we fire timeout here (for timeout commit)?
|
// XXX: should we fire timeout here (for timeout commit)?
|
||||||
cs.enterNewRound(ti.Height, 0)
|
cs.enterNewRound(ti.Height, 0)
|
||||||
case RoundStepNewRound:
|
case cstypes.RoundStepNewRound:
|
||||||
cs.enterPropose(ti.Height, 0)
|
cs.enterPropose(ti.Height, 0)
|
||||||
case RoundStepPropose:
|
case cstypes.RoundStepPropose:
|
||||||
types.FireEventTimeoutPropose(cs.evsw, cs.RoundStateEvent())
|
types.FireEventTimeoutPropose(cs.evsw, cs.RoundStateEvent())
|
||||||
cs.enterPrevote(ti.Height, ti.Round)
|
cs.enterPrevote(ti.Height, ti.Round)
|
||||||
case RoundStepPrevoteWait:
|
case cstypes.RoundStepPrevoteWait:
|
||||||
types.FireEventTimeoutWait(cs.evsw, cs.RoundStateEvent())
|
types.FireEventTimeoutWait(cs.evsw, cs.RoundStateEvent())
|
||||||
cs.enterPrecommit(ti.Height, ti.Round)
|
cs.enterPrecommit(ti.Height, ti.Round)
|
||||||
case RoundStepPrecommitWait:
|
case cstypes.RoundStepPrecommitWait:
|
||||||
types.FireEventTimeoutWait(cs.evsw, cs.RoundStateEvent())
|
types.FireEventTimeoutWait(cs.evsw, cs.RoundStateEvent())
|
||||||
cs.enterNewRound(ti.Height, ti.Round+1)
|
cs.enterNewRound(ti.Height, ti.Round+1)
|
||||||
default:
|
default:
|
||||||
@ -752,7 +635,7 @@ func (cs *ConsensusState) handleTxsAvailable(height int) {
|
|||||||
// Enter: +2/3 prevotes any or +2/3 precommits for block or any from (height, round)
|
// Enter: +2/3 prevotes any or +2/3 precommits for block or any from (height, round)
|
||||||
// NOTE: cs.StartTime was already set for height.
|
// NOTE: cs.StartTime was already set for height.
|
||||||
func (cs *ConsensusState) enterNewRound(height int, round int) {
|
func (cs *ConsensusState) enterNewRound(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != RoundStepNewHeight) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != cstypes.RoundStepNewHeight) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -773,7 +656,7 @@ func (cs *ConsensusState) enterNewRound(height int, round int) {
|
|||||||
// Setup new round
|
// Setup new round
|
||||||
// we don't fire newStep for this step,
|
// we don't fire newStep for this step,
|
||||||
// but we fire an event, so update the round step first
|
// but we fire an event, so update the round step first
|
||||||
cs.updateRoundStep(round, RoundStepNewRound)
|
cs.updateRoundStep(round, cstypes.RoundStepNewRound)
|
||||||
cs.Validators = validators
|
cs.Validators = validators
|
||||||
if round == 0 {
|
if round == 0 {
|
||||||
// We've already reset these upon new height,
|
// We've already reset these upon new height,
|
||||||
@ -794,7 +677,7 @@ func (cs *ConsensusState) enterNewRound(height int, round int) {
|
|||||||
waitForTxs := cs.config.WaitForTxs() && round == 0 && !cs.needProofBlock(height)
|
waitForTxs := cs.config.WaitForTxs() && round == 0 && !cs.needProofBlock(height)
|
||||||
if waitForTxs {
|
if waitForTxs {
|
||||||
if cs.config.CreateEmptyBlocksInterval > 0 {
|
if cs.config.CreateEmptyBlocksInterval > 0 {
|
||||||
cs.scheduleTimeout(cs.config.EmptyBlocksInterval(), height, round, RoundStepNewRound)
|
cs.scheduleTimeout(cs.config.EmptyBlocksInterval(), height, round, cstypes.RoundStepNewRound)
|
||||||
}
|
}
|
||||||
go cs.proposalHeartbeat(height, round)
|
go cs.proposalHeartbeat(height, round)
|
||||||
} else {
|
} else {
|
||||||
@ -827,7 +710,7 @@ func (cs *ConsensusState) proposalHeartbeat(height, round int) {
|
|||||||
for {
|
for {
|
||||||
rs := cs.GetRoundState()
|
rs := cs.GetRoundState()
|
||||||
// if we've already moved on, no need to send more heartbeats
|
// if we've already moved on, no need to send more heartbeats
|
||||||
if rs.Step > RoundStepNewRound || rs.Round > round || rs.Height > height {
|
if rs.Step > cstypes.RoundStepNewRound || rs.Round > round || rs.Height > height {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
heartbeat := &types.Heartbeat{
|
heartbeat := &types.Heartbeat{
|
||||||
@ -849,7 +732,7 @@ func (cs *ConsensusState) proposalHeartbeat(height, round int) {
|
|||||||
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
|
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
|
||||||
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
|
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
|
||||||
func (cs *ConsensusState) enterPropose(height int, round int) {
|
func (cs *ConsensusState) enterPropose(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPropose <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPropose <= cs.Step) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -857,7 +740,7 @@ func (cs *ConsensusState) enterPropose(height int, round int) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPropose:
|
// Done enterPropose:
|
||||||
cs.updateRoundStep(round, RoundStepPropose)
|
cs.updateRoundStep(round, cstypes.RoundStepPropose)
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
|
|
||||||
// If we have the whole proposal + POL, then goto Prevote now.
|
// If we have the whole proposal + POL, then goto Prevote now.
|
||||||
@ -869,7 +752,7 @@ func (cs *ConsensusState) enterPropose(height int, round int) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// If we don't get the proposal and all block parts quick enough, enterPrevote
|
// If we don't get the proposal and all block parts quick enough, enterPrevote
|
||||||
cs.scheduleTimeout(cs.config.Propose(round), height, round, RoundStepPropose)
|
cs.scheduleTimeout(cs.config.Propose(round), height, round, cstypes.RoundStepPropose)
|
||||||
|
|
||||||
// Nothing more to do if we're not a validator
|
// Nothing more to do if we're not a validator
|
||||||
if cs.privValidator == nil {
|
if cs.privValidator == nil {
|
||||||
@ -986,14 +869,14 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
|
|||||||
// Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
|
// Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
|
||||||
// Otherwise vote nil.
|
// Otherwise vote nil.
|
||||||
func (cs *ConsensusState) enterPrevote(height int, round int) {
|
func (cs *ConsensusState) enterPrevote(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevote <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPrevote:
|
// Done enterPrevote:
|
||||||
cs.updateRoundStep(round, RoundStepPrevote)
|
cs.updateRoundStep(round, cstypes.RoundStepPrevote)
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1048,7 +931,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int, round int) {
|
|||||||
|
|
||||||
// Enter: any +2/3 prevotes at next round.
|
// Enter: any +2/3 prevotes at next round.
|
||||||
func (cs *ConsensusState) enterPrevoteWait(height int, round int) {
|
func (cs *ConsensusState) enterPrevoteWait(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevoteWait <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1059,12 +942,12 @@ func (cs *ConsensusState) enterPrevoteWait(height int, round int) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPrevoteWait:
|
// Done enterPrevoteWait:
|
||||||
cs.updateRoundStep(round, RoundStepPrevoteWait)
|
cs.updateRoundStep(round, cstypes.RoundStepPrevoteWait)
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for some more prevotes; enterPrecommit
|
// Wait for some more prevotes; enterPrecommit
|
||||||
cs.scheduleTimeout(cs.config.Prevote(round), height, round, RoundStepPrevoteWait)
|
cs.scheduleTimeout(cs.config.Prevote(round), height, round, cstypes.RoundStepPrevoteWait)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter: `timeoutPrevote` after any +2/3 prevotes.
|
// Enter: `timeoutPrevote` after any +2/3 prevotes.
|
||||||
@ -1074,7 +957,7 @@ func (cs *ConsensusState) enterPrevoteWait(height int, round int) {
|
|||||||
// else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
|
// else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
|
||||||
// else, precommit nil otherwise.
|
// else, precommit nil otherwise.
|
||||||
func (cs *ConsensusState) enterPrecommit(height int, round int) {
|
func (cs *ConsensusState) enterPrecommit(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommit <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1083,7 +966,7 @@ func (cs *ConsensusState) enterPrecommit(height int, round int) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPrecommit:
|
// Done enterPrecommit:
|
||||||
cs.updateRoundStep(round, RoundStepPrecommit)
|
cs.updateRoundStep(round, cstypes.RoundStepPrecommit)
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1167,7 +1050,7 @@ func (cs *ConsensusState) enterPrecommit(height int, round int) {
|
|||||||
|
|
||||||
// Enter: any +2/3 precommits for next round.
|
// Enter: any +2/3 precommits for next round.
|
||||||
func (cs *ConsensusState) enterPrecommitWait(height int, round int) {
|
func (cs *ConsensusState) enterPrecommitWait(height int, round int) {
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommitWait <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommitWait <= cs.Step) {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1178,18 +1061,18 @@ func (cs *ConsensusState) enterPrecommitWait(height int, round int) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPrecommitWait:
|
// Done enterPrecommitWait:
|
||||||
cs.updateRoundStep(round, RoundStepPrecommitWait)
|
cs.updateRoundStep(round, cstypes.RoundStepPrecommitWait)
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for some more precommits; enterNewRound
|
// Wait for some more precommits; enterNewRound
|
||||||
cs.scheduleTimeout(cs.config.Precommit(round), height, round, RoundStepPrecommitWait)
|
cs.scheduleTimeout(cs.config.Precommit(round), height, round, cstypes.RoundStepPrecommitWait)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter: +2/3 precommits for block
|
// Enter: +2/3 precommits for block
|
||||||
func (cs *ConsensusState) enterCommit(height int, commitRound int) {
|
func (cs *ConsensusState) enterCommit(height int, commitRound int) {
|
||||||
if cs.Height != height || RoundStepCommit <= cs.Step {
|
if cs.Height != height || cstypes.RoundStepCommit <= cs.Step {
|
||||||
cs.Logger.Debug(cmn.Fmt("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1198,7 +1081,7 @@ func (cs *ConsensusState) enterCommit(height int, commitRound int) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
// Done enterCommit:
|
// Done enterCommit:
|
||||||
// keep cs.Round the same, commitRound points to the right Precommits set.
|
// keep cs.Round the same, commitRound points to the right Precommits set.
|
||||||
cs.updateRoundStep(cs.Round, RoundStepCommit)
|
cs.updateRoundStep(cs.Round, cstypes.RoundStepCommit)
|
||||||
cs.CommitRound = commitRound
|
cs.CommitRound = commitRound
|
||||||
cs.CommitTime = time.Now()
|
cs.CommitTime = time.Now()
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
@ -1255,9 +1138,9 @@ func (cs *ConsensusState) tryFinalizeCommit(height int) {
|
|||||||
cs.finalizeCommit(height)
|
cs.finalizeCommit(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment height and goto RoundStepNewHeight
|
// Increment height and goto cstypes.RoundStepNewHeight
|
||||||
func (cs *ConsensusState) finalizeCommit(height int) {
|
func (cs *ConsensusState) finalizeCommit(height int) {
|
||||||
if cs.Height != height || cs.Step != RoundStepCommit {
|
if cs.Height != height || cs.Step != cstypes.RoundStepCommit {
|
||||||
cs.Logger.Debug(cmn.Fmt("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
|
cs.Logger.Debug(cmn.Fmt("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1351,7 +1234,7 @@ func (cs *ConsensusState) finalizeCommit(height int) {
|
|||||||
|
|
||||||
// By here,
|
// By here,
|
||||||
// * cs.Height has been increment to height+1
|
// * cs.Height has been increment to height+1
|
||||||
// * cs.Step is now RoundStepNewHeight
|
// * cs.Step is now cstypes.RoundStepNewHeight
|
||||||
// * cs.StartTime is set to when we will start round0.
|
// * cs.StartTime is set to when we will start round0.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1369,8 +1252,8 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't care about the proposal if we're already in RoundStepCommit.
|
// We don't care about the proposal if we're already in cstypes.RoundStepCommit.
|
||||||
if RoundStepCommit <= cs.Step {
|
if cstypes.RoundStepCommit <= cs.Step {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1415,10 +1298,10 @@ func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, ver
|
|||||||
cs.state.Params().BlockSizeParams.MaxBytes, &n, &err).(*types.Block)
|
cs.state.Params().BlockSizeParams.MaxBytes, &n, &err).(*types.Block)
|
||||||
// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
|
// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
|
||||||
cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
|
cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
|
||||||
if cs.Step == RoundStepPropose && cs.isProposalComplete() {
|
if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() {
|
||||||
// Move onto the next step
|
// Move onto the next step
|
||||||
cs.enterPrevote(height, cs.Round)
|
cs.enterPrevote(height, cs.Round)
|
||||||
} else if cs.Step == RoundStepCommit {
|
} else if cs.Step == cstypes.RoundStepCommit {
|
||||||
// If we're waiting on the proposal block...
|
// If we're waiting on the proposal block...
|
||||||
cs.tryFinalizeCommit(height)
|
cs.tryFinalizeCommit(height)
|
||||||
}
|
}
|
||||||
@ -1463,7 +1346,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool,
|
|||||||
// A precommit for the previous height?
|
// A precommit for the previous height?
|
||||||
// These come in while we wait timeoutCommit
|
// These come in while we wait timeoutCommit
|
||||||
if vote.Height+1 == cs.Height {
|
if vote.Height+1 == cs.Height {
|
||||||
if !(cs.Step == RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
|
if !(cs.Step == cstypes.RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
|
||||||
// TODO: give the reason ..
|
// TODO: give the reason ..
|
||||||
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
|
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
|
||||||
return added, ErrVoteHeightMismatch
|
return added, ErrVoteHeightMismatch
|
||||||
@ -1476,7 +1359,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool,
|
|||||||
// if we can skip timeoutCommit and have all the votes now,
|
// if we can skip timeoutCommit and have all the votes now,
|
||||||
if cs.config.SkipTimeoutCommit && cs.LastCommit.HasAll() {
|
if cs.config.SkipTimeoutCommit && cs.LastCommit.HasAll() {
|
||||||
// go straight to new round (skip timeout commit)
|
// go straight to new round (skip timeout commit)
|
||||||
// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, RoundStepNewHeight)
|
// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, cstypes.RoundStepNewHeight)
|
||||||
cs.enterNewRound(cs.Height, 0)
|
cs.enterNewRound(cs.Height, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1540,7 +1423,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool,
|
|||||||
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
||||||
// if we have all the votes now,
|
// if we have all the votes now,
|
||||||
// go straight to new round (skip timeout commit)
|
// go straight to new round (skip timeout commit)
|
||||||
// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, RoundStepNewHeight)
|
// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, cstypes.RoundStepNewHeight)
|
||||||
cs.enterNewRound(cs.Height, 0)
|
cs.enterNewRound(cs.Height, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1601,7 +1484,7 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.Part
|
|||||||
|
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
|
||||||
func CompareHRS(h1, r1 int, s1 RoundStepType, h2, r2 int, s2 RoundStepType) int {
|
func CompareHRS(h1, r1 int, s1 cstypes.RoundStepType, h2, r2 int, s2 cstypes.RoundStepType) int {
|
||||||
if h1 < h2 {
|
if h1 < h2 {
|
||||||
return -1
|
return -1
|
||||||
} else if h1 > h2 {
|
} else if h1 > h2 {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
@ -247,7 +248,7 @@ func TestFullRound1(t *testing.T) {
|
|||||||
|
|
||||||
// grab proposal
|
// grab proposal
|
||||||
re := <-propCh
|
re := <-propCh
|
||||||
propBlockHash := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState).ProposalBlock.Hash()
|
propBlockHash := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState).ProposalBlock.Hash()
|
||||||
|
|
||||||
<-voteCh // wait for prevote
|
<-voteCh // wait for prevote
|
||||||
// NOTE: voteChan cap of 0 ensures we can complete this
|
// NOTE: voteChan cap of 0 ensures we can complete this
|
||||||
@ -344,7 +345,7 @@ func TestLockNoPOL(t *testing.T) {
|
|||||||
cs1.startRoutines(0)
|
cs1.startRoutines(0)
|
||||||
|
|
||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
theBlockHash := rs.ProposalBlock.Hash()
|
theBlockHash := rs.ProposalBlock.Hash()
|
||||||
|
|
||||||
<-voteCh // prevote
|
<-voteCh // prevote
|
||||||
@ -384,7 +385,7 @@ func TestLockNoPOL(t *testing.T) {
|
|||||||
|
|
||||||
// now we're on a new round and not the proposer, so wait for timeout
|
// now we're on a new round and not the proposer, so wait for timeout
|
||||||
re = <-timeoutProposeCh
|
re = <-timeoutProposeCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
if rs.ProposalBlock != nil {
|
if rs.ProposalBlock != nil {
|
||||||
panic("Expected proposal block to be nil")
|
panic("Expected proposal block to be nil")
|
||||||
@ -428,7 +429,7 @@ func TestLockNoPOL(t *testing.T) {
|
|||||||
incrementRound(vs2)
|
incrementRound(vs2)
|
||||||
|
|
||||||
re = <-proposalCh
|
re = <-proposalCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
// now we're on a new round and are the proposer
|
// now we're on a new round and are the proposer
|
||||||
if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
|
if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
|
||||||
@ -515,7 +516,7 @@ func TestLockPOLRelock(t *testing.T) {
|
|||||||
|
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
theBlockHash := rs.ProposalBlock.Hash()
|
theBlockHash := rs.ProposalBlock.Hash()
|
||||||
|
|
||||||
<-voteCh // prevote
|
<-voteCh // prevote
|
||||||
@ -591,7 +592,7 @@ func TestLockPOLRelock(t *testing.T) {
|
|||||||
be := <-newBlockCh
|
be := <-newBlockCh
|
||||||
b := be.(types.TMEventData).Unwrap().(types.EventDataNewBlockHeader)
|
b := be.(types.TMEventData).Unwrap().(types.EventDataNewBlockHeader)
|
||||||
re = <-newRoundCh
|
re = <-newRoundCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
if rs.Height != 2 {
|
if rs.Height != 2 {
|
||||||
panic("Expected height to increment")
|
panic("Expected height to increment")
|
||||||
}
|
}
|
||||||
@ -627,7 +628,7 @@ func TestLockPOLUnlock(t *testing.T) {
|
|||||||
startTestRound(cs1, cs1.Height, 0)
|
startTestRound(cs1, cs1.Height, 0)
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
theBlockHash := rs.ProposalBlock.Hash()
|
theBlockHash := rs.ProposalBlock.Hash()
|
||||||
|
|
||||||
<-voteCh // prevote
|
<-voteCh // prevote
|
||||||
@ -653,7 +654,7 @@ func TestLockPOLUnlock(t *testing.T) {
|
|||||||
|
|
||||||
// timeout to new round
|
// timeout to new round
|
||||||
re = <-timeoutWaitCh
|
re = <-timeoutWaitCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
lockedBlockHash := rs.LockedBlock.Hash()
|
lockedBlockHash := rs.LockedBlock.Hash()
|
||||||
|
|
||||||
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
|
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
|
||||||
@ -713,7 +714,7 @@ func TestLockPOLSafety1(t *testing.T) {
|
|||||||
startTestRound(cs1, cs1.Height, 0)
|
startTestRound(cs1, cs1.Height, 0)
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
propBlock := rs.ProposalBlock
|
propBlock := rs.ProposalBlock
|
||||||
|
|
||||||
<-voteCh // prevote
|
<-voteCh // prevote
|
||||||
@ -761,7 +762,7 @@ func TestLockPOLSafety1(t *testing.T) {
|
|||||||
re = <-proposalCh
|
re = <-proposalCh
|
||||||
}
|
}
|
||||||
|
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
if rs.LockedBlock != nil {
|
if rs.LockedBlock != nil {
|
||||||
panic("we should not be locked!")
|
panic("we should not be locked!")
|
||||||
@ -848,7 +849,7 @@ func TestLockPOLSafety2(t *testing.T) {
|
|||||||
|
|
||||||
incrementRound(vs2, vs3, vs4)
|
incrementRound(vs2, vs3, vs4)
|
||||||
|
|
||||||
cs1.updateRoundStep(0, RoundStepPrecommitWait)
|
cs1.updateRoundStep(0, cstypes.RoundStepPrecommitWait)
|
||||||
|
|
||||||
t.Log("### ONTO Round 1")
|
t.Log("### ONTO Round 1")
|
||||||
// jump in at round 1
|
// jump in at round 1
|
||||||
@ -929,7 +930,7 @@ func TestSlashingPrevotes(t *testing.T) {
|
|||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
<-voteCh // prevote
|
<-voteCh // prevote
|
||||||
|
|
||||||
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
// we should now be stuck in limbo forever, waiting for more prevotes
|
// we should now be stuck in limbo forever, waiting for more prevotes
|
||||||
// add one for a different block should cause us to go into prevote wait
|
// add one for a different block should cause us to go into prevote wait
|
||||||
@ -1009,7 +1010,7 @@ func TestHalt1(t *testing.T) {
|
|||||||
startTestRound(cs1, cs1.Height, 0)
|
startTestRound(cs1, cs1.Height, 0)
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
re := <-proposalCh
|
re := <-proposalCh
|
||||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
propBlock := rs.ProposalBlock
|
propBlock := rs.ProposalBlock
|
||||||
propBlockParts := propBlock.MakePartSet(partSize)
|
propBlockParts := propBlock.MakePartSet(partSize)
|
||||||
|
|
||||||
@ -1032,7 +1033,7 @@ func TestHalt1(t *testing.T) {
|
|||||||
// timeout to new round
|
// timeout to new round
|
||||||
<-timeoutWaitCh
|
<-timeoutWaitCh
|
||||||
re = <-newRoundCh
|
re = <-newRoundCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
t.Log("### ONTO ROUND 1")
|
t.Log("### ONTO ROUND 1")
|
||||||
/*Round2
|
/*Round2
|
||||||
@ -1050,7 +1051,7 @@ func TestHalt1(t *testing.T) {
|
|||||||
// receiving that precommit should take us straight to commit
|
// receiving that precommit should take us straight to commit
|
||||||
<-newBlockCh
|
<-newBlockCh
|
||||||
re = <-newRoundCh
|
re = <-newRoundCh
|
||||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*RoundState)
|
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||||
|
|
||||||
if rs.Height != 2 {
|
if rs.Height != 2 {
|
||||||
panic("expected height to increment")
|
panic("expected height to increment")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package consensus
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
@ -1,14 +1,17 @@
|
|||||||
package consensus
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
config = ResetConfig("consensus_height_vote_set_test")
|
config = cfg.ResetTestRoot("consensus_height_vote_set_test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerCatchupRounds(t *testing.T) {
|
func TestPeerCatchupRounds(t *testing.T) {
|
57
consensus/types/reactor.go
Normal file
57
consensus/types/reactor.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/types"
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// PeerRoundState contains the known state of a peer.
|
||||||
|
// NOTE: Read-only when returned by PeerState.GetRoundState().
|
||||||
|
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 *cmn.BitArray //
|
||||||
|
ProposalPOLRound int // Proposal's POL round. -1 if none.
|
||||||
|
ProposalPOL *cmn.BitArray // nil until ProposalPOLMessage received.
|
||||||
|
Prevotes *cmn.BitArray // All votes peer has for this round
|
||||||
|
Precommits *cmn.BitArray // All precommits peer has for this round
|
||||||
|
LastCommitRound int // Round of commit for last height. -1 if none.
|
||||||
|
LastCommit *cmn.BitArray // All commit precommits of commit for last height.
|
||||||
|
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none.
|
||||||
|
CatchupCommit *cmn.BitArray // All commit precommits peer has for this height & CatchupCommitRound
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the PeerRoundState
|
||||||
|
func (prs PeerRoundState) String() string {
|
||||||
|
return prs.StringIndented("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringIndented returns a string representation of the PeerRoundState
|
||||||
|
func (prs PeerRoundState) StringIndented(indent string) string {
|
||||||
|
return fmt.Sprintf(`PeerRoundState{
|
||||||
|
%s %v/%v/%v @%v
|
||||||
|
%s Proposal %v -> %v
|
||||||
|
%s POL %v (round %v)
|
||||||
|
%s Prevotes %v
|
||||||
|
%s Precommits %v
|
||||||
|
%s LastCommit %v (round %v)
|
||||||
|
%s Catchup %v (round %v)
|
||||||
|
%s}`,
|
||||||
|
indent, prs.Height, prs.Round, prs.Step, prs.StartTime,
|
||||||
|
indent, prs.ProposalBlockPartsHeader, prs.ProposalBlockParts,
|
||||||
|
indent, prs.ProposalPOL, prs.ProposalPOLRound,
|
||||||
|
indent, prs.Prevotes,
|
||||||
|
indent, prs.Precommits,
|
||||||
|
indent, prs.LastCommit, prs.LastCommitRound,
|
||||||
|
indent, prs.CatchupCommit, prs.CatchupCommitRound,
|
||||||
|
indent)
|
||||||
|
}
|
126
consensus/types/state.go
Normal file
126
consensus/types/state.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// RoundStepType enum type
|
||||||
|
|
||||||
|
// RoundStepType enumerates the state of the consensus state machine
|
||||||
|
type RoundStepType uint8 // These must be numeric, ordered.
|
||||||
|
|
||||||
|
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
|
||||||
|
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns a string
|
||||||
|
func (rs RoundStepType) String() string {
|
||||||
|
switch rs {
|
||||||
|
case RoundStepNewHeight:
|
||||||
|
return "RoundStepNewHeight"
|
||||||
|
case RoundStepNewRound:
|
||||||
|
return "RoundStepNewRound"
|
||||||
|
case RoundStepPropose:
|
||||||
|
return "RoundStepPropose"
|
||||||
|
case RoundStepPrevote:
|
||||||
|
return "RoundStepPrevote"
|
||||||
|
case RoundStepPrevoteWait:
|
||||||
|
return "RoundStepPrevoteWait"
|
||||||
|
case RoundStepPrecommit:
|
||||||
|
return "RoundStepPrecommit"
|
||||||
|
case RoundStepPrecommitWait:
|
||||||
|
return "RoundStepPrecommitWait"
|
||||||
|
case RoundStepCommit:
|
||||||
|
return "RoundStepCommit"
|
||||||
|
default:
|
||||||
|
return "RoundStepUnknown" // Cannot panic.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// RoundState defines the internal consensus state.
|
||||||
|
// It is Immutable when returned from ConsensusState.GetRoundState()
|
||||||
|
// TODO: Actually, only the top pointer is copied,
|
||||||
|
// so access to field pointers is still racey
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundStateEvent returns the H/R/S of the RoundState as an event.
|
||||||
|
func (rs *RoundState) RoundStateEvent() types.EventDataRoundState {
|
||||||
|
edrs := types.EventDataRoundState{
|
||||||
|
Height: rs.Height,
|
||||||
|
Round: rs.Round,
|
||||||
|
Step: rs.Step.String(),
|
||||||
|
RoundState: rs,
|
||||||
|
}
|
||||||
|
return edrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string
|
||||||
|
func (rs *RoundState) String() string {
|
||||||
|
return rs.StringIndented("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringIndented returns a string
|
||||||
|
func (rs *RoundState) StringIndented(indent string) string {
|
||||||
|
return fmt.Sprintf(`RoundState{
|
||||||
|
%s H:%v R:%v S:%v
|
||||||
|
%s StartTime: %v
|
||||||
|
%s CommitTime: %v
|
||||||
|
%s Validators: %v
|
||||||
|
%s Proposal: %v
|
||||||
|
%s ProposalBlock: %v %v
|
||||||
|
%s LockedRound: %v
|
||||||
|
%s LockedBlock: %v %v
|
||||||
|
%s Votes: %v
|
||||||
|
%s LastCommit: %v
|
||||||
|
%s LastValidators: %v
|
||||||
|
%s}`,
|
||||||
|
indent, rs.Height, rs.Round, rs.Step,
|
||||||
|
indent, rs.StartTime,
|
||||||
|
indent, rs.CommitTime,
|
||||||
|
indent, rs.Validators.StringIndented(indent+" "),
|
||||||
|
indent, rs.Proposal,
|
||||||
|
indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
|
||||||
|
indent, rs.LockedRound,
|
||||||
|
indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
|
||||||
|
indent, rs.Votes.StringIndented(indent+" "),
|
||||||
|
indent, rs.LastCommit.StringShort(),
|
||||||
|
indent, rs.LastValidators.StringIndented(indent+" "),
|
||||||
|
indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringShort returns a string
|
||||||
|
func (rs *RoundState) StringShort() string {
|
||||||
|
return fmt.Sprintf(`RoundState{H:%v R:%v S:%v ST:%v}`,
|
||||||
|
rs.Height, rs.Round, rs.Step, rs.StartTime)
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
wire "github.com/tendermint/go-wire"
|
|
||||||
cm "github.com/tendermint/tendermint/consensus"
|
cm "github.com/tendermint/tendermint/consensus"
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
@ -82,14 +82,11 @@ func Validators(heightPtr *int) (*ctypes.ResultValidators, error) {
|
|||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
|
func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
|
||||||
roundState := consensusState.GetRoundState()
|
peerRoundStates := make(map[string]*cstypes.PeerRoundState)
|
||||||
peerRoundStates := []string{}
|
|
||||||
for _, peer := range p2pSwitch.Peers().List() {
|
for _, peer := range p2pSwitch.Peers().List() {
|
||||||
// TODO: clean this up?
|
|
||||||
peerState := peer.Get(types.PeerStateKey).(*cm.PeerState)
|
peerState := peer.Get(types.PeerStateKey).(*cm.PeerState)
|
||||||
peerRoundState := peerState.GetRoundState()
|
peerRoundState := peerState.GetRoundState()
|
||||||
peerRoundStateStr := peer.Key() + ":" + string(wire.JSONBytes(peerRoundState))
|
peerRoundStates[peer.Key()] = peerRoundState
|
||||||
peerRoundStates = append(peerRoundStates, peerRoundStateStr)
|
|
||||||
}
|
}
|
||||||
return &ctypes.ResultDumpConsensusState{roundState.String(), peerRoundStates}, nil
|
return &ctypes.ResultDumpConsensusState{consensusState.GetRoundState(), peerRoundStates}, nil
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
"github.com/tendermint/tendermint/consensus"
|
"github.com/tendermint/tendermint/consensus"
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
p2p "github.com/tendermint/tendermint/p2p"
|
p2p "github.com/tendermint/tendermint/p2p"
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
@ -17,7 +18,7 @@ import (
|
|||||||
type Consensus interface {
|
type Consensus interface {
|
||||||
GetState() *sm.State
|
GetState() *sm.State
|
||||||
GetValidators() (int, []*types.Validator)
|
GetValidators() (int, []*types.Validator)
|
||||||
GetRoundState() *consensus.RoundState
|
GetRoundState() *cstypes.RoundState
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2P interface {
|
type P2P interface {
|
||||||
|
@ -4,8 +4,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
"github.com/tendermint/go-wire/data"
|
"github.com/tendermint/go-wire/data"
|
||||||
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
@ -75,8 +76,8 @@ type ResultValidators struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResultDumpConsensusState struct {
|
type ResultDumpConsensusState struct {
|
||||||
RoundState string `json:"round_state"`
|
RoundState *cstypes.RoundState `json:"round_state"`
|
||||||
PeerRoundStates []string `json:"peer_round_states"`
|
PeerRoundStates map[string]*cstypes.PeerRoundState `json:"peer_round_states"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResultBroadcastTx struct {
|
type ResultBroadcastTx struct {
|
||||||
|
@ -100,3 +100,4 @@ Each route is available as a GET request, as a JSONRPCv2 POST request, and via J
|
|||||||
* [Tendermint](https://github.com/tendermint/tendermint/blob/master/rpc/core/routes.go)
|
* [Tendermint](https://github.com/tendermint/tendermint/blob/master/rpc/core/routes.go)
|
||||||
* [tm-monitor](https://github.com/tendermint/tools/blob/master/tm-monitor/rpc.go)
|
* [tm-monitor](https://github.com/tendermint/tools/blob/master/tm-monitor/rpc.go)
|
||||||
*/
|
*/
|
||||||
|
package rpc
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -116,6 +117,7 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han
|
|||||||
// A Notification is a Request object without an "id" member.
|
// A Notification is a Request object without an "id" member.
|
||||||
// The Server MUST NOT reply to a Notification, including those that are within a batch request.
|
// The Server MUST NOT reply to a Notification, including those that are within a batch request.
|
||||||
if request.ID == "" {
|
if request.ID == "" {
|
||||||
|
logger.Debug("HTTPJSONRPC received a notification, skipping... (please send a non-empty ID if you want to call a method)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(r.URL.Path) > 1 {
|
if len(r.URL.Path) > 1 {
|
||||||
@ -127,10 +129,13 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han
|
|||||||
WriteRPCResponseHTTP(w, types.RPCMethodNotFoundError(request.ID))
|
WriteRPCResponseHTTP(w, types.RPCMethodNotFoundError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
args, err := jsonParamsToArgsRPC(rpcFunc, request.Params)
|
var args []reflect.Value
|
||||||
if err != nil {
|
if len(request.Params) > 0 {
|
||||||
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID, errors.Wrap(err, "Error converting json params to arguments")))
|
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||||
return
|
if err != nil {
|
||||||
|
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID, errors.Wrap(err, "Error converting json params to arguments")))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
returns := rpcFunc.f.Call(args)
|
returns := rpcFunc.f.Call(args)
|
||||||
logger.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
|
logger.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
|
||||||
@ -208,13 +213,13 @@ func jsonParamsToArgs(rpcFunc *RPCFunc, raw []byte, argsOffset int) ([]reflect.V
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert a []interface{} OR a map[string]interface{} to properly typed values
|
// Convert a []interface{} OR a map[string]interface{} to properly typed values
|
||||||
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, params *json.RawMessage) ([]reflect.Value, error) {
|
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, params json.RawMessage) ([]reflect.Value, error) {
|
||||||
return jsonParamsToArgs(rpcFunc, *params, 0)
|
return jsonParamsToArgs(rpcFunc, params, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as above, but with the first param the websocket connection
|
// Same as above, but with the first param the websocket connection
|
||||||
func jsonParamsToArgsWS(rpcFunc *RPCFunc, params *json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
|
func jsonParamsToArgsWS(rpcFunc *RPCFunc, params json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
|
||||||
values, err := jsonParamsToArgs(rpcFunc, *params, 1)
|
values, err := jsonParamsToArgs(rpcFunc, params, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -485,7 +490,17 @@ func (wsc *wsConnection) TryWriteRPCResponse(resp types.RPCResponse) bool {
|
|||||||
// Read from the socket and subscribe to or unsubscribe from events
|
// Read from the socket and subscribe to or unsubscribe from events
|
||||||
func (wsc *wsConnection) readRoutine() {
|
func (wsc *wsConnection) readRoutine() {
|
||||||
defer func() {
|
defer func() {
|
||||||
wsc.baseConn.Close()
|
if r := recover(); r != nil {
|
||||||
|
err, ok := r.(error)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("WSJSONRPC: %v", r)
|
||||||
|
}
|
||||||
|
wsc.Logger.Error("Panic in WSJSONRPC handler", "err", err, "stack", string(debug.Stack()))
|
||||||
|
wsc.WriteRPCResponse(types.RPCInternalError("unknown", err))
|
||||||
|
go wsc.readRoutine()
|
||||||
|
} else {
|
||||||
|
wsc.baseConn.Close()
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wsc.baseConn.SetPongHandler(func(m string) error {
|
wsc.baseConn.SetPongHandler(func(m string) error {
|
||||||
@ -521,6 +536,7 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
// A Notification is a Request object without an "id" member.
|
// A Notification is a Request object without an "id" member.
|
||||||
// The Server MUST NOT reply to a Notification, including those that are within a batch request.
|
// The Server MUST NOT reply to a Notification, including those that are within a batch request.
|
||||||
if request.ID == "" {
|
if request.ID == "" {
|
||||||
|
wsc.Logger.Debug("WSJSONRPC received a notification, skipping... (please send a non-empty ID if you want to call a method)")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,9 +550,13 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
var args []reflect.Value
|
var args []reflect.Value
|
||||||
if rpcFunc.ws {
|
if rpcFunc.ws {
|
||||||
wsCtx := types.WSRPCContext{Request: request, WSRPCConnection: wsc}
|
wsCtx := types.WSRPCContext{Request: request, WSRPCConnection: wsc}
|
||||||
args, err = jsonParamsToArgsWS(rpcFunc, request.Params, wsCtx)
|
if len(request.Params) > 0 {
|
||||||
|
args, err = jsonParamsToArgsWS(rpcFunc, request.Params, wsCtx)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
if len(request.Params) > 0 {
|
||||||
|
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wsc.WriteRPCResponse(types.RPCInternalError(request.ID, errors.Wrap(err, "Error converting json params to arguments")))
|
wsc.WriteRPCResponse(types.RPCInternalError(request.ID, errors.Wrap(err, "Error converting json params to arguments")))
|
||||||
|
@ -14,10 +14,10 @@ import (
|
|||||||
// REQUEST
|
// REQUEST
|
||||||
|
|
||||||
type RPCRequest struct {
|
type RPCRequest struct {
|
||||||
JSONRPC string `json:"jsonrpc"`
|
JSONRPC string `json:"jsonrpc"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Params *json.RawMessage `json:"params"` // must be map[string]interface{} or []interface{}
|
Params json.RawMessage `json:"params"` // must be map[string]interface{} or []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest {
|
func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest {
|
||||||
@ -25,7 +25,7 @@ func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest
|
|||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: id,
|
ID: id,
|
||||||
Method: method,
|
Method: method,
|
||||||
Params: ¶ms,
|
Params: params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user