Unverified Commit 7ea03fb2 authored by vipwzw's avatar vipwzw Committed by GitHub

Merge pull request #674 from caopingcp/issue615_tendermint

tendermint save local state
parents a413a97a 152ba70e
...@@ -83,13 +83,13 @@ powLimitBits = "0x1f2fffff" ...@@ -83,13 +83,13 @@ powLimitBits = "0x1f2fffff"
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394 genesisBlockTime=1514533394
timeoutTxAvail=1000 timeoutTxAvail=1000
timeoutPropose=3000 timeoutPropose=1000
timeoutProposeDelta=500 timeoutProposeDelta=500
timeoutPrevote=1000 timeoutPrevote=1000
timeoutPrevoteDelta=500 timeoutPrevoteDelta=500
timeoutPrecommit=1000 timeoutPrecommit=1000
timeoutPrecommitDelta=500 timeoutPrecommitDelta=500
timeoutCommit=1000 timeoutCommit=500
skipTimeoutCommit=false skipTimeoutCommit=false
createEmptyBlocks=false createEmptyBlocks=false
createEmptyBlocksInterval=0 createEmptyBlocksInterval=0
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"reflect"
"runtime/debug" "runtime/debug"
"sync" "sync"
"sync/atomic" "sync/atomic"
...@@ -66,8 +65,6 @@ type ConsensusState struct { ...@@ -66,8 +65,6 @@ type ConsensusState struct {
// TODO: encapsulate all of this in one "BlockManager" // TODO: encapsulate all of this in one "BlockManager"
blockExec *BlockExecutor blockExec *BlockExecutor
evpool ttypes.EvidencePool
// internal state // internal state
mtx sync.Mutex mtx sync.Mutex
ttypes.RoundState ttypes.RoundState
...@@ -89,8 +86,7 @@ type ConsensusState struct { ...@@ -89,8 +86,7 @@ type ConsensusState struct {
broadcastChannel chan<- MsgInfo broadcastChannel chan<- MsgInfo
ourID ID ourID ID
started uint32 // atomic status uint32 // 0-stop, 1-start
stopped uint32 // atomic
Quit chan struct{} Quit chan struct{}
txsAvailable chan int64 txsAvailable chan int64
...@@ -99,19 +95,19 @@ type ConsensusState struct { ...@@ -99,19 +95,19 @@ type ConsensusState struct {
} }
// NewConsensusState returns a new ConsensusState. // NewConsensusState returns a new ConsensusState.
func NewConsensusState(client *Client, state State, blockExec *BlockExecutor, evpool ttypes.EvidencePool) *ConsensusState { func NewConsensusState(client *Client, state State, blockExec *BlockExecutor) *ConsensusState {
cs := &ConsensusState{ cs := &ConsensusState{
client: client, client: client,
blockExec: blockExec, blockExec: blockExec,
peerMsgQueue: make(chan MsgInfo, msgQueueSize), peerMsgQueue: make(chan MsgInfo, msgQueueSize),
internalMsgQueue: make(chan MsgInfo, msgQueueSize), internalMsgQueue: make(chan MsgInfo, msgQueueSize),
timeoutTicker: NewTimeoutTicker(), timeoutTicker: NewTimeoutTicker(),
evpool: evpool,
Quit: make(chan struct{}), Quit: make(chan struct{}),
txsAvailable: make(chan int64, 1), txsAvailable: make(chan int64, 1),
begCons: time.Time{}, begCons: time.Time{},
} }
atomic.CompareAndSwapUint32(&cs.status, 0, 0)
// set function defaults (may be overwritten before calling Start) // set function defaults (may be overwritten before calling Start)
cs.decideProposal = cs.defaultDecideProposal cs.decideProposal = cs.defaultDecideProposal
cs.doPrevote = cs.defaultDoPrevote cs.doPrevote = cs.defaultDoPrevote
...@@ -137,15 +133,10 @@ func (cs *ConsensusState) SetBroadcastChannel(broadcastChannel chan<- MsgInfo) { ...@@ -137,15 +133,10 @@ func (cs *ConsensusState) SetBroadcastChannel(broadcastChannel chan<- MsgInfo) {
// IsRunning method // IsRunning method
func (cs *ConsensusState) IsRunning() bool { func (cs *ConsensusState) IsRunning() bool {
return atomic.LoadUint32(&cs.started) == 1 && atomic.LoadUint32(&cs.stopped) == 0 return atomic.LoadUint32(&cs.status) == 1
} }
//---------------------------------------- //----------------------------------------
// String returns a string.
func (cs *ConsensusState) String() string {
// better not to access shared variables
return fmt.Sprintf("ConsensusState") //(H:%v R:%v S:%v", cs.Height, cs.Round, cs.Step)
}
// GetState returns a copy of the chain state. // GetState returns a copy of the chain state.
func (cs *ConsensusState) GetState() State { func (cs *ConsensusState) GetState() State {
...@@ -189,18 +180,15 @@ func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) { ...@@ -189,18 +180,15 @@ func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) {
func (cs *ConsensusState) LoadCommit(height int64) *tmtypes.TendermintCommit { func (cs *ConsensusState) LoadCommit(height int64) *tmtypes.TendermintCommit {
cs.mtx.Lock() cs.mtx.Lock()
defer cs.mtx.Unlock() defer cs.mtx.Unlock()
if height == cs.client.GetCurrentHeight() { if height == cs.client.csStore.LoadStateHeight() {
return cs.client.LoadSeenCommit(height) return cs.client.csStore.LoadSeenCommit(height)
} }
return cs.client.LoadBlockCommit(height + 1) return cs.client.LoadBlockCommit(height + 1)
} }
// Start It start first time starts the timeout checkTxsAvailable routine and receive routines. // Start It start first time starts the timeout checkTxsAvailable routine and receive routines.
func (cs *ConsensusState) Start() { func (cs *ConsensusState) Start() {
if atomic.CompareAndSwapUint32(&cs.started, 0, 1) { if atomic.CompareAndSwapUint32(&cs.status, 0, 1) {
if atomic.LoadUint32(&cs.stopped) == 1 {
tendermintlog.Error("ConsensusState already stoped")
}
cs.timeoutTicker.Start() cs.timeoutTicker.Start()
go cs.checkTxsAvailable() go cs.checkTxsAvailable()
...@@ -215,6 +203,7 @@ func (cs *ConsensusState) Start() { ...@@ -215,6 +203,7 @@ func (cs *ConsensusState) Start() {
// Stop timer and receive routine // Stop timer and receive routine
func (cs *ConsensusState) Stop() { func (cs *ConsensusState) Stop() {
atomic.CompareAndSwapUint32(&cs.status, 1, 0)
cs.timeoutTicker.Stop() cs.timeoutTicker.Stop()
cs.Quit <- struct{}{} cs.Quit <- struct{}{}
} }
...@@ -262,7 +251,7 @@ func (cs *ConsensusState) reconstructLastCommit(state State) { ...@@ -262,7 +251,7 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
if state.LastBlockHeight == 0 { if state.LastBlockHeight == 0 {
return return
} }
seenCommit := cs.client.LoadSeenCommit(state.LastBlockHeight) seenCommit := cs.client.csStore.LoadSeenCommit(state.LastBlockHeight)
seenCommitC := ttypes.Commit{TendermintCommit: seenCommit} seenCommitC := ttypes.Commit{TendermintCommit: seenCommit}
lastPrecommits := ttypes.NewVoteSet(state.ChainID, state.LastBlockHeight, seenCommitC.Round(), ttypes.VoteTypePrecommit, state.LastValidators) lastPrecommits := ttypes.NewVoteSet(state.ChainID, state.LastBlockHeight, seenCommitC.Round(), ttypes.VoteTypePrecommit, state.LastValidators)
for _, item := range seenCommit.Precommits { for _, item := range seenCommit.Precommits {
...@@ -272,11 +261,11 @@ func (cs *ConsensusState) reconstructLastCommit(state State) { ...@@ -272,11 +261,11 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
precommit := &ttypes.Vote{Vote: item} precommit := &ttypes.Vote{Vote: item}
added, err := lastPrecommits.AddVote(precommit) added, err := lastPrecommits.AddVote(precommit)
if !added || err != nil { if !added || err != nil {
panic(fmt.Sprintf("Panicked on a Crisis: %v", fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))) panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))
} }
} }
if !lastPrecommits.HasTwoThirdsMajority() { if !lastPrecommits.HasTwoThirdsMajority() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", "Failed to reconstruct LastCommit: Does not have +2/3 maj")) panic("Failed to reconstruct LastCommit: Does not have +2/3 maj")
} }
cs.LastCommit = lastPrecommits cs.LastCommit = lastPrecommits
} }
...@@ -285,14 +274,12 @@ func (cs *ConsensusState) reconstructLastCommit(state State) { ...@@ -285,14 +274,12 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
// The round becomes 0 and cs.Step becomes ttypes.RoundStepNewHeight. // The round becomes 0 and cs.Step becomes ttypes.RoundStepNewHeight.
func (cs *ConsensusState) updateToState(state State) { func (cs *ConsensusState) updateToState(state State) {
if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight { if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("updateToState() expected state height of %v but found %v", panic(fmt.Sprintf("updateToState expected state height of %v but found %v", cs.Height, state.LastBlockHeight))
cs.Height, state.LastBlockHeight)))
} }
if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height { if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height {
// This might happen when someone else is mutating cs.state. // This might happen when someone else is mutating cs.state.
// Someone forgot to pass in state.Copy() somewhere?! // Someone forgot to pass in state.Copy() somewhere?!
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v", panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v", cs.state.LastBlockHeight+1, cs.Height))
cs.state.LastBlockHeight+1, cs.Height)))
} }
// If state isn't further out than cs.state, just ignore. // If state isn't further out than cs.state, just ignore.
...@@ -308,7 +295,7 @@ func (cs *ConsensusState) updateToState(state State) { ...@@ -308,7 +295,7 @@ func (cs *ConsensusState) updateToState(state State) {
lastPrecommits := (*ttypes.VoteSet)(nil) lastPrecommits := (*ttypes.VoteSet)(nil)
if cs.CommitRound > -1 && cs.Votes != nil { if cs.CommitRound > -1 && cs.Votes != nil {
if !cs.Votes.Precommits(cs.CommitRound).HasTwoThirdsMajority() { if !cs.Votes.Precommits(cs.CommitRound).HasTwoThirdsMajority() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", "updateToState(state) called but last Precommit round didn't have +2/3")) panic("updateToState called but last Precommit round didn't have +2/3")
} }
lastPrecommits = cs.Votes.Precommits(cs.CommitRound) lastPrecommits = cs.Votes.Precommits(cs.CommitRound)
} }
...@@ -333,8 +320,10 @@ func (cs *ConsensusState) updateToState(state State) { ...@@ -333,8 +320,10 @@ func (cs *ConsensusState) updateToState(state State) {
cs.Proposal = nil cs.Proposal = nil
cs.ProposalBlock = nil cs.ProposalBlock = nil
cs.ProposalBlockHash = nil cs.ProposalBlockHash = nil
cs.LockedRound = 0 cs.LockedRound = -1
cs.LockedBlock = nil cs.LockedBlock = nil
cs.ValidRound = -1
cs.ValidBlock = nil
cs.Votes = ttypes.NewHeightVoteSet(state.ChainID, height, validators) cs.Votes = ttypes.NewHeightVoteSet(state.ChainID, height, validators)
cs.CommitRound = -1 cs.CommitRound = -1
cs.LastCommit = lastPrecommits cs.LastCommit = lastPrecommits
...@@ -428,10 +417,11 @@ func (cs *ConsensusState) handleMsg(mi MsgInfo) { ...@@ -428,10 +417,11 @@ func (cs *ConsensusState) handleMsg(mi MsgInfo) {
case *tmtypes.Vote: case *tmtypes.Vote:
// attempt to add the vote and dupeout the validator if its a duplicate signature // attempt to add the vote and dupeout the validator if its a duplicate signature
// if the vote gives us a 2/3-any or 2/3-one, we transition // if the vote gives us a 2/3-any or 2/3-one, we transition
err := cs.tryAddVote(msg, peerID, peerIP) err = cs.tryAddVote(msg, peerID, peerIP)
if err == ErrAddingVote {
// TODO: punish peer //if err == ErrAddingVote {
} // TODO: punish peer
//}
// NOTE: the vote is broadcast to peers by the reactor listening // NOTE: the vote is broadcast to peers by the reactor listening
// for vote events // for vote events
...@@ -443,12 +433,12 @@ func (cs *ConsensusState) handleMsg(mi MsgInfo) { ...@@ -443,12 +433,12 @@ func (cs *ConsensusState) handleMsg(mi MsgInfo) {
tendermintlog.Error("Unknown msg type", msg.String(), "peerid", peerID, "peerip", peerIP) tendermintlog.Error("Unknown msg type", msg.String(), "peerid", peerID, "peerip", peerIP)
} }
if err != nil { if err != nil {
tendermintlog.Error("Error with msg", "type", reflect.TypeOf(msg), "peerid", peerID, "peerip", peerIP, "err", err, "msg", msg) //tendermintlog.Error("Error with msg", "type", reflect.TypeOf(msg), "peerid", peerID, "peerip", peerIP, "err", err, "msg", msg)
} }
} }
func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs ttypes.RoundState) { func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs ttypes.RoundState) {
tendermintlog.Debug("Received tock", "timeout", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step) tendermintlog.Debug("Received tock", "timeout", ti.String())
// timeouts must be for current height, round, step // timeouts must be for current height, round, step
if ti.Height != rs.Height || ti.Round < rs.Round || (ti.Round == rs.Round && ti.Step < rs.Step) { if ti.Height != rs.Height || ti.Round < rs.Round || (ti.Round == rs.Round && ti.Step < rs.Step) {
...@@ -472,6 +462,7 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs ttypes.RoundState) { ...@@ -472,6 +462,7 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs ttypes.RoundState) {
case ttypes.RoundStepPrevoteWait: case ttypes.RoundStepPrevoteWait:
cs.enterPrecommit(ti.Height, ti.Round) cs.enterPrecommit(ti.Height, ti.Round)
case ttypes.RoundStepPrecommitWait: case ttypes.RoundStepPrecommitWait:
cs.enterPrecommit(ti.Height, ti.Round)
cs.enterNewRound(ti.Height, ti.Round+1) cs.enterNewRound(ti.Height, ti.Round+1)
default: default:
panic(fmt.Sprintf("Invalid timeout step: %v", ti.Step)) panic(fmt.Sprintf("Invalid timeout step: %v", ti.Step))
...@@ -543,9 +534,9 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) { ...@@ -543,9 +534,9 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
if cs.Round < round { if cs.Round < round {
validators = validators.Copy() validators = validators.Copy()
validators.IncrementAccum(round - cs.Round) validators.IncrementAccum(round - cs.Round)
tendermintlog.Debug("enterNewRound validator changed", "csr", cs.Round, "round", round) tendermintlog.Debug("enterNewRound validator changed", "cs.Round", cs.Round, "round", round)
} }
tendermintlog.Debug("enterNewRound proposer ", "proposer", validators.Proposer, "validators", validators) tendermintlog.Debug("enterNewRound proposer", "proposer", validators.Proposer, "validators", validators)
// 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
...@@ -615,7 +606,7 @@ func (cs *ConsensusState) proposalHeartbeat(height int64, round int) { ...@@ -615,7 +606,7 @@ func (cs *ConsensusState) proposalHeartbeat(height int64, round int) {
// 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 int64, round int) { func (cs *ConsensusState) enterPropose(height int64, round int) {
if cs.Height != height || round < cs.Round || (cs.Round == round && ttypes.RoundStepPropose <= cs.Step) { if cs.Height != height || round < cs.Round || (cs.Round == round && ttypes.RoundStepPropose <= cs.Step) {
tendermintlog.Info(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) tendermintlog.Debug(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return return
} }
tendermintlog.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) tendermintlog.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
...@@ -647,16 +638,22 @@ func (cs *ConsensusState) enterPropose(height int64, round int) { ...@@ -647,16 +638,22 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
// if not a validator, we're done // if not a validator, we're done
if !cs.Validators.HasAddress(cs.privValidator.GetAddress()) { if !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
tendermintlog.Debug("This node is not a validator", "addr", cs.privValidator.GetAddress(), "vals", cs.Validators) tendermintlog.Debug("This node is not a validator",
"privValidator", fmt.Sprintf("%X", ttypes.Fingerprint(cs.privValidator.GetAddress())),
"Validators", cs.Validators.String())
return return
} }
tendermintlog.Debug("This node is a validator") tendermintlog.Debug("This node is a validator")
if cs.isProposer() { if cs.isProposer() {
tendermintlog.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator) tendermintlog.Info("enterPropose: Our turn to propose",
"proposer", fmt.Sprintf("%X", ttypes.Fingerprint(cs.Validators.GetProposer().Address)),
"privValidator", fmt.Sprintf("%X", ttypes.Fingerprint(cs.privValidator.GetAddress())))
cs.decideProposal(height, round) cs.decideProposal(height, round)
} else { } else {
tendermintlog.Info("enterPropose: Not our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator) tendermintlog.Info("enterPropose: Not our turn to propose",
"proposer", fmt.Sprintf("%X", ttypes.Fingerprint(cs.Validators.GetProposer().Address)),
"privValidator", fmt.Sprintf("%X", ttypes.Fingerprint(cs.privValidator.GetAddress())))
} }
} }
...@@ -669,9 +666,9 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) { ...@@ -669,9 +666,9 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
var block *ttypes.TendermintBlock var block *ttypes.TendermintBlock
// Decide on block // Decide on block
if cs.LockedBlock != nil { if cs.ValidBlock != nil {
// If we're locked onto a block, just choose that. // If there is valid block, choose that.
block = cs.LockedBlock block = cs.ValidBlock
} else { } else {
// Create a new proposal block from state/txs from the mempool. // Create a new proposal block from state/txs from the mempool.
block = cs.createProposalBlock() block = cs.createProposalBlock()
...@@ -681,8 +678,8 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) { ...@@ -681,8 +678,8 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
} }
// Make proposal // Make proposal
polRound, polBlockID := cs.Votes.POLInfo() propBlockID := tmtypes.BlockID{Hash: block.Hash()}
proposal := ttypes.NewProposal(height, round, block.Hash(), polRound, polBlockID.BlockID) proposal := ttypes.NewProposal(height, round, block.Hash(), cs.ValidRound, propBlockID)
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal); err == nil { if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal); err == nil {
// send proposal and block on internal msg queue // send proposal and block on internal msg queue
cs.sendInternalMessage(MsgInfo{ttypes.ProposalID, &proposal.Proposal, cs.ourID, ""}) cs.sendInternalMessage(MsgInfo{ttypes.ProposalID, &proposal.Proposal, cs.ourID, ""})
...@@ -723,7 +720,7 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock) ...@@ -723,7 +720,7 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock)
} else { } else {
// This shouldn't happen. // This shouldn't happen.
tendermintlog.Error("enterPropose: Cannot propose anything: No commit for the previous block.") tendermintlog.Error("enterPropose: Cannot propose anything: No commit for the previous block.")
return return nil
} }
// Mempool validated transactions // Mempool validated transactions
...@@ -734,18 +731,37 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock) ...@@ -734,18 +731,37 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock)
if pblock.Height != cs.Height { if pblock.Height != cs.Height {
tendermintlog.Error("pblock.Height is not equal to cs.Height") tendermintlog.Error("pblock.Height is not equal to cs.Height")
return return nil
} }
block = cs.state.MakeBlock(cs.Height, int64(cs.Round), pblock.Txs, commit) proposerAddr := cs.privValidator.GetAddress()
tendermintlog.Info("createProposalBlock block", "txs-len", len(block.Txs)) block = cs.state.MakeBlock(cs.Height, int64(cs.Round), pblock, commit, proposerAddr)
block.ProposerAddr = cs.privValidator.GetAddress() baseTx := cs.createBaseTx(block.TendermintBlock)
evidence := cs.evpool.PendingEvidence() block.Data.Txs[0] = baseTx
block.AddEvidence(evidence) block.Data.TxHash = merkle.CalcMerkleRoot(block.Data.Txs)
pblockNew := cs.client.PreExecBlock(block.Data, false)
if pblockNew == nil {
tendermintlog.Error("createProposalBlock PreExecBlock fail")
return nil
}
block.Data = pblockNew
return block return block
} }
func (cs *ConsensusState) createBaseTx(block *tmtypes.TendermintBlock) (tx *types.Transaction) {
var state *tmtypes.State
if cs.Height == 1 {
state = &tmtypes.State{}
} else {
state = cs.client.csStore.LoadStateFromStore()
if state == nil {
panic("createBaseTx LoadStateFromStore fail")
}
}
tx = CreateBlockInfoTx(cs.client.pubKey, state, block)
return tx
}
// Enter: `timeoutPropose` after entering Propose. // Enter: `timeoutPropose` after entering Propose.
// Enter: proposal block and POL is ready. // Enter: proposal block and POL is ready.
// Enter: any +2/3 prevotes for future round. // Enter: any +2/3 prevotes for future round.
...@@ -763,14 +779,6 @@ func (cs *ConsensusState) enterPrevote(height int64, round int) { ...@@ -763,14 +779,6 @@ func (cs *ConsensusState) enterPrevote(height int64, round int) {
cs.newStep() cs.newStep()
}() }()
// fire event for how we got here
if cs.isProposalComplete() {
//cs.eventBus.PublishEventCompleteProposal(cs.RoundStateEvent())
} else {
// we received +2/3 prevotes for a future round
// TODO: catchup event?
}
tendermintlog.Info(fmt.Sprintf("enterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step), "cost", types.Since(cs.begCons)) tendermintlog.Info(fmt.Sprintf("enterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step), "cost", types.Since(cs.begCons))
// Sign and broadcast vote as necessary // Sign and broadcast vote as necessary
...@@ -804,6 +812,20 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) { ...@@ -804,6 +812,20 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
return return
} }
// PreExec proposal block
blockCopy := *cs.ProposalBlock.Data
blockNew := cs.client.PreExecBlock(&blockCopy, true)
if blockNew == nil {
tendermintlog.Error("enterPrevote: PreExec ProposalBlock fail")
cs.signAddVote(ttypes.VoteTypePrevote, nil)
return
}
if !bytes.Equal(blockNew.Hash(), cs.ProposalBlock.Data.Hash()) {
tendermintlog.Error("enterPrevote: PreExec ProposalBlock has change")
cs.signAddVote(ttypes.VoteTypePrevote, nil)
return
}
// Prevote cs.ProposalBlock // Prevote cs.ProposalBlock
// NOTE: the proposal signature is validated when it is received, // NOTE: the proposal signature is validated when it is received,
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal) // and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
...@@ -818,7 +840,7 @@ func (cs *ConsensusState) enterPrevoteWait(height int64, round int) { ...@@ -818,7 +840,7 @@ func (cs *ConsensusState) enterPrevoteWait(height int64, round int) {
return return
} }
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() { if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))) panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))
} }
tendermintlog.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) tendermintlog.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
...@@ -868,7 +890,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { ...@@ -868,7 +890,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
// the latest POLRound should be this round // the latest POLRound should be this round
polRound, _ := cs.Votes.POLInfo() polRound, _ := cs.Votes.POLInfo()
if polRound < round { if polRound < round {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("This POLRound should be %v but got %v", round, polRound))) panic(fmt.Sprintf("This POLRound should be %v but got %v", round, polRound))
} }
// +2/3 prevoted nil. Unlock and precommit nil. // +2/3 prevoted nil. Unlock and precommit nil.
...@@ -877,7 +899,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { ...@@ -877,7 +899,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
tendermintlog.Info("enterPrecommit: +2/3 prevoted for nil.") tendermintlog.Info("enterPrecommit: +2/3 prevoted for nil.")
} else { } else {
tendermintlog.Info("enterPrecommit: +2/3 prevoted for nil. Unlocking") tendermintlog.Info("enterPrecommit: +2/3 prevoted for nil. Unlocking")
cs.LockedRound = 0 cs.LockedRound = -1
cs.LockedBlock = nil cs.LockedBlock = nil
} }
cs.signAddVote(ttypes.VoteTypePrecommit, nil) cs.signAddVote(ttypes.VoteTypePrecommit, nil)
...@@ -899,7 +921,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { ...@@ -899,7 +921,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
tendermintlog.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", fmt.Sprintf("%X", blockID.Hash)) tendermintlog.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", fmt.Sprintf("%X", blockID.Hash))
// Validate the block. // Validate the block.
if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil { if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
panic(fmt.Sprintf("Panicked on a Consensus Failure: %v", fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))) panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
} }
cs.LockedRound = round cs.LockedRound = round
cs.LockedBlock = cs.ProposalBlock cs.LockedBlock = cs.ProposalBlock
...@@ -911,7 +933,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { ...@@ -911,7 +933,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
// Fetch that block, unlock, and precommit nil. // Fetch that block, unlock, and precommit nil.
// The +2/3 prevotes for this round is the POL for our unlock. // The +2/3 prevotes for this round is the POL for our unlock.
// TODO: In the future save the POL prevotes for justification. // TODO: In the future save the POL prevotes for justification.
cs.LockedRound = 0 cs.LockedRound = -1
cs.LockedBlock = nil cs.LockedBlock = nil
if !bytes.Equal(cs.ProposalBlockHash, blockID.Hash) { if !bytes.Equal(cs.ProposalBlockHash, blockID.Hash) {
cs.ProposalBlock = nil cs.ProposalBlock = nil
...@@ -927,7 +949,7 @@ func (cs *ConsensusState) enterPrecommitWait(height int64, round int) { ...@@ -927,7 +949,7 @@ func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
return return
} }
if !cs.Votes.Precommits(round).HasTwoThirdsAny() { if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round))) panic(fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round))
} }
tendermintlog.Info(fmt.Sprintf("enterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) tendermintlog.Info(fmt.Sprintf("enterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
...@@ -964,7 +986,7 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) { ...@@ -964,7 +986,7 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
blockID, ok := cs.Votes.Precommits(commitRound).TwoThirdsMajority() blockID, ok := cs.Votes.Precommits(commitRound).TwoThirdsMajority()
if !ok { if !ok {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", "RunActionCommit() expects +2/3 precommits")) panic("RunActionCommit() expects +2/3 precommits")
} }
// The Locked* fields no longer matter. // The Locked* fields no longer matter.
...@@ -985,16 +1007,25 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) { ...@@ -985,16 +1007,25 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
// Set up ProposalBlockHash and keep waiting. // Set up ProposalBlockHash and keep waiting.
cs.ProposalBlock = nil cs.ProposalBlock = nil
cs.ProposalBlockHash = blockID.Hash cs.ProposalBlockHash = blockID.Hash
} else {
// We just need to keep waiting. validBlockMsg := &tmtypes.ValidBlockMsg{
Height: cs.Height,
Round: int32(cs.Round),
Blockhash: cs.ProposalBlockHash,
IsCommit: false,
}
cs.broadcastChannel <- MsgInfo{TypeID: ttypes.ValidBlockID, Msg: validBlockMsg, PeerID: cs.ourID, PeerIP: ""}
} }
//else {
// We just need to keep waiting.
//}
} }
} }
// If we have the block AND +2/3 commits for it, finalize. // If we have the block AND +2/3 commits for it, finalize.
func (cs *ConsensusState) tryFinalizeCommit(height int64) { func (cs *ConsensusState) tryFinalizeCommit(height int64) {
if cs.Height != height { if cs.Height != height {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height))) panic(fmt.Sprintf("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height))
} }
blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority() blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority()
...@@ -1027,14 +1058,14 @@ func (cs *ConsensusState) finalizeCommit(height int64) { ...@@ -1027,14 +1058,14 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
block := cs.ProposalBlock block := cs.ProposalBlock
if !ok { if !ok {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("Cannot finalizeCommit, commit does not have two thirds majority"))) panic(fmt.Sprintf("Cannot finalizeCommit, commit does not have two thirds majority"))
} }
if !block.HashesTo(blockID.Hash) { if !block.HashesTo(blockID.Hash) {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("Cannot finalizeCommit, ProposalBlock does not hash to commit hash"))) panic(fmt.Sprintf("Cannot finalizeCommit, ProposalBlock does not hash to commit hash"))
} }
if err := cs.blockExec.ValidateBlock(cs.state, block); err != nil { if err := cs.blockExec.ValidateBlock(cs.state, block); err != nil {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("+2/3 committed an invalid block: %v", err))) panic(fmt.Sprintf("+2/3 committed an invalid block: %v", err))
} }
stateCopy := cs.state.Copy() stateCopy := cs.state.Copy()
...@@ -1043,55 +1074,21 @@ func (cs *ConsensusState) finalizeCommit(height int64) { ...@@ -1043,55 +1074,21 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
var err error var err error
stateCopy, err = cs.blockExec.ApplyBlock(stateCopy, ttypes.BlockID{BlockID: tmtypes.BlockID{Hash: block.Hash()}}, block) stateCopy, err = cs.blockExec.ApplyBlock(stateCopy, ttypes.BlockID{BlockID: tmtypes.BlockID{Hash: block.Hash()}}, block)
if err != nil { if err != nil {
tendermintlog.Error("Error on ApplyBlock", "err", err) panic(fmt.Sprintf("finalizeCommit ApplyBlock fail: %v", err))
cs.enterNewRound(cs.Height, cs.CommitRound+1)
return
} }
newState := SaveState(stateCopy) // commit block
tendermintlog.Info(fmt.Sprintf("Save consensus state. Current: %v/%v/%v", cs.Height, cs.CommitRound, cs.Step), "cost", types.Since(cs.begCons)) commitBlock := cs.ProposalBlock.Data
// original proposer commit block err = cs.client.CommitBlock(commitBlock)
if bytes.Equal(cs.privValidator.GetAddress(), block.TendermintBlock.ProposerAddr) { if err != nil {
newProposal := cs.Proposal panic(fmt.Sprintf("finalizeCommit CommitBlock fail: %v", err))
tendermintlog.Debug("finalizeCommit proposal block txs hash", "height", block.Header.Height, "tx-hash", fmt.Sprintf("%X", merkle.CalcMerkleRoot(block.Txs))) }
commitBlock := &types.Block{} if bytes.Equal(cs.privValidator.GetAddress(), block.TendermintBlock.Header.ProposerAddr) {
commitBlock.Height = block.Header.Height
commitBlock.Txs = make([]*types.Transaction, 1, len(block.Txs)+1)
commitBlock.Txs = append(commitBlock.Txs, block.Txs...)
lastCommit := block.LastCommit
precommits := cs.Votes.Precommits(cs.CommitRound)
seenCommit := precommits.MakeCommit()
tx0 := CreateBlockInfoTx(cs.client.pubKey, lastCommit, seenCommit, newState, newProposal, cs.ProposalBlock.TendermintBlock)
commitBlock.Txs[0] = tx0
cs.mtx.Unlock()
err = cs.client.CommitBlock(commitBlock)
cs.mtx.Lock()
if err != nil {
cs.LockedRound = 0
cs.LockedBlock = nil
tendermintlog.Info(fmt.Sprintf("Proposer continue consensus. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step),
"CommitRound", cs.CommitRound, "cost", types.Since(cs.begCons))
cs.enterNewRound(cs.Height, cs.CommitRound+1)
return
}
tendermintlog.Info(fmt.Sprintf("Proposer reach consensus. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), "CommitRound", cs.CommitRound, tendermintlog.Info(fmt.Sprintf("Proposer reach consensus. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), "CommitRound", cs.CommitRound,
"tx-len", len(commitBlock.Txs), "cost", types.Since(cs.begCons), "proposer-addr", fmt.Sprintf("%X", ttypes.Fingerprint(block.TendermintBlock.ProposerAddr))) "tx-len", len(commitBlock.Txs), "cost", types.Since(cs.begCons), "proposer-addr", fmt.Sprintf("%X", ttypes.Fingerprint(block.TendermintBlock.Header.ProposerAddr)))
} else { } else {
cs.mtx.Unlock()
reachCons := cs.client.CheckCommit(block.Header.Height)
cs.mtx.Lock()
if !reachCons {
cs.LockedRound = 0
cs.LockedBlock = nil
tendermintlog.Info(fmt.Sprintf("Not-Proposer continue consensus, will catchup. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step),
"CommitRound", cs.CommitRound, "cost", types.Since(cs.begCons))
cs.enterNewRound(cs.Height, cs.CommitRound+1)
return
}
tendermintlog.Info(fmt.Sprintf("Not-Proposer reach consensus. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), "CommitRound", cs.CommitRound, tendermintlog.Info(fmt.Sprintf("Not-Proposer reach consensus. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), "CommitRound", cs.CommitRound,
"tx-len", block.Header.NumTxs+1, "cost", types.Since(cs.begCons), "proposer-addr", fmt.Sprintf("%X", ttypes.Fingerprint(block.TendermintBlock.ProposerAddr))) "tx-len", len(commitBlock.Txs), "cost", types.Since(cs.begCons), "proposer-addr", fmt.Sprintf("%X", ttypes.Fingerprint(block.TendermintBlock.Header.ProposerAddr)))
} }
//check whether need update validator nodes //check whether need update validator nodes
...@@ -1111,7 +1108,18 @@ func (cs *ConsensusState) finalizeCommit(height int64) { ...@@ -1111,7 +1108,18 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
stateCopy.Validators = nextValSet stateCopy.Validators = nextValSet
} }
} }
tendermintlog.Debug("finalizeCommit validators of statecopy", "validators", stateCopy.Validators) tendermintlog.Debug("finalizeCommit validators of statecopy", "validators", stateCopy.Validators.String())
// save local state and seen commit
precommits := cs.Votes.Precommits(cs.CommitRound)
seenCommit := precommits.MakeCommit()
newState := SaveState(stateCopy)
err = cs.client.csStore.SaveConsensusState(height, newState, seenCommit)
if err != nil {
panic(fmt.Sprintf("finalizeCommit SaveSeenCommit fail: %v", err))
}
tendermintlog.Info(fmt.Sprintf("Save consensus state. Current: %v/%v/%v", cs.Height, cs.CommitRound, cs.Step), "cost", types.Since(cs.begCons))
// NewHeightStep! // NewHeightStep!
cs.updateToState(stateCopy) cs.updateToState(stateCopy)
...@@ -1150,15 +1158,9 @@ func (cs *ConsensusState) defaultSetProposal(proposal *tmtypes.Proposal) error { ...@@ -1150,15 +1158,9 @@ func (cs *ConsensusState) defaultSetProposal(proposal *tmtypes.Proposal) error {
cs.begCons = time.Now() cs.begCons = time.Now()
} }
// We don't care about the proposal if we're already in ttypes.RoundStepCommit. // Verify POLRound, which must be -1 or in range [0, proposal.Round).
if ttypes.RoundStepCommit <= cs.Step { if proposal.POLRound != -1 ||
tendermintlog.Error("defaultSetProposal: already in RoundStepCommit") (proposal.POLRound >= 0 && proposal.Round >= proposal.POLRound) {
return nil
}
// Verify POLRound, which must be -1 or between 0 and proposal.Round exclusive.
if proposal.POLRound != -1 &&
(proposal.POLRound < 0 || proposal.Round <= proposal.POLRound) {
return ErrInvalidProposalPOLRound return ErrInvalidProposalPOLRound
} }
...@@ -1221,9 +1223,29 @@ func (cs *ConsensusState) addProposalBlock(proposalBlock *tmtypes.TendermintBloc ...@@ -1221,9 +1223,29 @@ func (cs *ConsensusState) addProposalBlock(proposalBlock *tmtypes.TendermintBloc
tendermintlog.Info(fmt.Sprintf("Consensus set proposal block. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), tendermintlog.Info(fmt.Sprintf("Consensus set proposal block. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step),
"ProposalBlockHash", fmt.Sprintf("%X", cs.ProposalBlockHash), "cost", types.Since(cs.begCons)) "ProposalBlockHash", fmt.Sprintf("%X", cs.ProposalBlockHash), "cost", types.Since(cs.begCons))
if cs.Step <= ttypes.RoundStepPropose { // Update Valid* if we can.
prevotes := cs.Votes.Prevotes(cs.Round)
blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
if hasTwoThirds && len(blockID.Hash) == 0 && (cs.ValidRound < cs.Round) {
if cs.ProposalBlock.HashesTo(blockID.Hash) {
tendermintlog.Info("Updating valid block to new proposal block",
"valid-round", cs.Round, "valid-block-hash", cs.ProposalBlock.Hash())
cs.ValidRound = cs.Round
cs.ValidBlock = cs.ProposalBlock
}
// TODO: In case there is +2/3 majority in Prevotes set for some
// block and cs.ProposalBlock contains different block, either
// proposer is faulty or voting power of faulty processes is more
// than 1/3. We should trigger in the future accountability
// procedure at this point.
}
if cs.Step <= ttypes.RoundStepPropose && cs.isProposalComplete() {
// Move onto the next step // Move onto the next step
cs.enterPrevote(cs.Height, cs.Round) cs.enterPrevote(cs.Height, cs.Round)
if hasTwoThirds { // this is optimisation as this will be triggered when prevote is added
cs.enterPrecommit(cs.Height, cs.Round)
}
} else if cs.Step == ttypes.RoundStepCommit { } else if cs.Step == ttypes.RoundStepCommit {
// If we're waiting on the proposal block... // If we're waiting on the proposal block...
cs.tryFinalizeCommit(cs.Height) cs.tryFinalizeCommit(cs.Height)
...@@ -1241,13 +1263,11 @@ func (cs *ConsensusState) tryAddVote(voteRaw *tmtypes.Vote, peerID string, peerI ...@@ -1241,13 +1263,11 @@ func (cs *ConsensusState) tryAddVote(voteRaw *tmtypes.Vote, peerID string, peerI
// If it's otherwise invalid, punish peer. // If it's otherwise invalid, punish peer.
if err == ErrVoteHeightMismatch { if err == ErrVoteHeightMismatch {
return err return err
} else if voteErr, ok := err.(*ttypes.ErrVoteConflictingVotes); ok { } else if err == ttypes.ErrVoteConflict {
if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) { if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) {
tendermintlog.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type) tendermintlog.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type)
return err return err
} }
err = cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence)
return err
} else { } else {
// Probably an invalid signature / Bad peer. // Probably an invalid signature / Bad peer.
// Seems this can also err sometimes with "Unexpected step" - perhaps not from a bad peer ? // Seems this can also err sometimes with "Unexpected step" - perhaps not from a bad peer ?
...@@ -1264,104 +1284,161 @@ func (cs *ConsensusState) addVote(vote *ttypes.Vote, peerID string, peerIP strin ...@@ -1264,104 +1284,161 @@ func (cs *ConsensusState) addVote(vote *ttypes.Vote, peerID string, peerIP strin
tendermintlog.Debug(fmt.Sprintf("Consensus receive vote. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step), tendermintlog.Debug(fmt.Sprintf("Consensus receive vote. Current: %v/%v/%v", cs.Height, cs.Round, cs.Step),
"vote", fmt.Sprintf("{%v:%X %v/%02d/%v}", vote.ValidatorIndex, ttypes.Fingerprint(vote.ValidatorAddress), vote.Height, vote.Round, vote.Type), "peerip", peerIP) "vote", fmt.Sprintf("{%v:%X %v/%02d/%v}", vote.ValidatorIndex, ttypes.Fingerprint(vote.ValidatorAddress), vote.Height, vote.Round, vote.Type), "peerip", peerIP)
// A prevote/precommit for this height? // A precommit for the previous height
if vote.Height == cs.Height { // These come in while we wait timeoutCommit
if cs.begCons.IsZero() { if vote.Height+1 == cs.Height {
cs.begCons = time.Now() if !(cs.Step == ttypes.RoundStepNewHeight && vote.Type == uint32(ttypes.VoteTypePrecommit)) {
// TODO: give the reason ..
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
return added, ErrVoteHeightMismatch
}
added, err = cs.LastCommit.AddVote(vote)
if !added {
return added, err
}
tendermintlog.Info(fmt.Sprintf("Added to lastPrecommits: %v", cs.LastCommit.StringShort()))
hasVoteMsg := &tmtypes.HasVoteMsg{
Height: vote.Height,
Round: vote.Round,
Type: int32(vote.Type),
Index: vote.ValidatorIndex,
} }
cs.broadcastChannel <- MsgInfo{TypeID: ttypes.HasVoteID, Msg: hasVoteMsg, PeerID: cs.ourID, PeerIP: ""}
height := cs.Height // if we can skip timeoutCommit and have all the votes now,
added, err = cs.Votes.AddVote(vote, peerID) if skipTimeoutCommit && cs.LastCommit.HasAll() {
if added { // go straight to new round (skip timeout commit)
//cs.broadcastChannel <- MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: cs.ourID, PeerIP: ""} // cs.scheduleTimeout(time.Duration(0), cs.Height, 0, cstypes.RoundStepNewHeight)
hasVoteMsg := &tmtypes.HasVoteMsg{ cs.enterNewRound(cs.Height, 0)
Height: vote.Height, }
Round: vote.Round, return
Type: int32(vote.Type), }
Index: vote.ValidatorIndex,
// Height mismatch is ignored.
// Not necessarily a bad peer, but not favourable behaviour.
if vote.Height != cs.Height {
err = ErrVoteHeightMismatch
tendermintlog.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "peerID", peerID)
return
}
if cs.begCons.IsZero() {
cs.begCons = time.Now()
}
height := cs.Height
added, err = cs.Votes.AddVote(vote, peerID)
if !added {
// Either duplicate, or error upon cs.Votes.AddByIndex()
return
}
//cs.broadcastChannel <- MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: cs.ourID, PeerIP: ""}
hasVoteMsg := &tmtypes.HasVoteMsg{
Height: vote.Height,
Round: vote.Round,
Type: int32(vote.Type),
Index: vote.ValidatorIndex,
}
cs.broadcastChannel <- MsgInfo{TypeID: ttypes.HasVoteID, Msg: hasVoteMsg, PeerID: cs.ourID, PeerIP: ""}
switch vote.Type {
case uint32(ttypes.VoteTypePrevote):
prevotes := cs.Votes.Prevotes(int(vote.Round))
tendermintlog.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())
// If +2/3 prevotes for a block or nil for *any* round:
if blockID, ok := prevotes.TwoThirdsMajority(); ok {
// There was a polka!
// If we're locked but this is a recent polka, unlock.
// If it matches our ProposalBlock, update the ValidBlock
// Unlock if `cs.LockedRound < vote.Round <= cs.Round`
// NOTE: If vote.Round > cs.Round, we'll deal with it when we get to vote.Round
if (cs.LockedBlock != nil) &&
(cs.LockedRound < int(vote.Round)) &&
(int(vote.Round) <= cs.Round) &&
!cs.LockedBlock.HashesTo(blockID.Hash) {
tendermintlog.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round)
cs.LockedRound = -1
cs.LockedBlock = nil
} }
cs.broadcastChannel <- MsgInfo{TypeID: ttypes.HasVoteID, Msg: hasVoteMsg, PeerID: cs.ourID, PeerIP: ""}
switch vote.Type {
case uint32(ttypes.VoteTypePrevote):
prevotes := cs.Votes.Prevotes(int(vote.Round))
tendermintlog.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())
// If +2/3 prevotes for a block or nil for *any* round:
if blockID, ok := prevotes.TwoThirdsMajority(); ok {
// There was a polka!
// If we're locked but this is a recent polka, unlock.
// If it matches our ProposalBlock, update the ValidBlock
// Unlock if `cs.LockedRound < vote.Round <= cs.Round`
// NOTE: If vote.Round > cs.Round, we'll deal with it when we get to vote.Round
if (cs.LockedBlock != nil) &&
(cs.LockedRound < int(vote.Round)) &&
(int(vote.Round) <= cs.Round) &&
!cs.LockedBlock.HashesTo(blockID.Hash) {
tendermintlog.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round)
cs.LockedRound = 0
cs.LockedBlock = nil
}
}
// If +2/3 prevotes for *anything* for this or future round: // Update Valid* if we can.
if cs.Round <= int(vote.Round) && prevotes.HasTwoThirdsAny() { // NOTE: our proposal block may be nil or not what received a polka..
// Round-skip over to PrevoteWait or goto Precommit. if len(blockID.Hash) != 0 && (cs.ValidRound < int(vote.Round)) && (int(vote.Round) == cs.Round) {
cs.enterNewRound(height, int(vote.Round)) // if the vote is ahead of us
if prevotes.HasTwoThirdsMajority() { if cs.ProposalBlock.HashesTo(blockID.Hash) {
cs.enterPrecommit(height, int(vote.Round)) tendermintlog.Info("Updating ValidBlock because of POL.", "validRound", cs.ValidRound, "POLRound", vote.Round)
} else { cs.ValidRound = int(vote.Round)
cs.enterPrevote(height, int(vote.Round)) // if the vote is ahead of us cs.ValidBlock = cs.ProposalBlock
cs.enterPrevoteWait(height, int(vote.Round)) } else {
} tendermintlog.Info(
} else if cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round { "Valid block we don't know about. Set ProposalBlock=nil",
// If the proposal is now complete, enter prevote of cs.Round. "proposal", fmt.Sprintf("%X", cs.ProposalBlock.Hash()), "blockId", fmt.Sprintf("%X", blockID.Hash))
if cs.isProposalComplete() { // We're getting the wrong block.
cs.enterPrevote(height, cs.Round) cs.ProposalBlock = nil
}
} }
cs.ProposalBlockHash = blockID.Hash
case uint32(ttypes.VoteTypePrecommit): validBlockMsg := &tmtypes.ValidBlockMsg{
precommits := cs.Votes.Precommits(int(vote.Round)) Height: vote.Height,
tendermintlog.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort()) Round: vote.Round,
blockID, ok := precommits.TwoThirdsMajority() Blockhash: cs.ProposalBlockHash,
if ok { IsCommit: false,
if len(blockID.Hash) == 0 {
cs.enterNewRound(height, int(vote.Round)+1)
} else {
cs.enterNewRound(height, int(vote.Round))
cs.enterPrecommit(height, int(vote.Round))
cs.enterCommit(height, int(vote.Round))
if skipTimeoutCommit && precommits.HasAll() {
// if we have all the votes now,
// go straight to new round (skip timeout commit)
cs.enterNewRound(cs.Height, 0)
}
}
} else if cs.Round <= int(vote.Round) && precommits.HasTwoThirdsAny() {
cs.enterNewRound(height, int(vote.Round))
cs.enterPrecommit(height, int(vote.Round))
cs.enterPrecommitWait(height, int(vote.Round))
} }
cs.broadcastChannel <- MsgInfo{TypeID: ttypes.ValidBlockID, Msg: validBlockMsg, PeerID: cs.ourID, PeerIP: ""}
}
}
default: // If +2/3 prevotes for *anything* for this or future round:
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("Unexpected vote type %X", vote.Type))) // Should not happen. switch {
case cs.Round < int(vote.Round) && prevotes.HasTwoThirdsAny():
// Round-skip if there is any 2/3+ of votes ahead of us
cs.enterNewRound(height, int(vote.Round))
case cs.Round == int(vote.Round) && ttypes.RoundStepPrevote <= cs.Step: // current round
blockID, ok := prevotes.TwoThirdsMajority()
if ok && (cs.isProposalComplete() || len(blockID.Hash) == 0) {
cs.enterPrecommit(height, int(vote.Round))
} else if prevotes.HasTwoThirdsAny() {
cs.enterPrevoteWait(height, int(vote.Round))
}
case cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round:
// If the proposal is now complete, enter prevote of cs.Round.
if cs.isProposalComplete() {
cs.enterPrevote(height, cs.Round)
} }
} }
// Either duplicate, or error upon cs.Votes.AddByIndex()
// return case uint32(ttypes.VoteTypePrecommit):
} else { precommits := cs.Votes.Precommits(int(vote.Round))
err = ErrVoteHeightMismatch tendermintlog.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())
blockID, ok := precommits.TwoThirdsMajority()
if ok {
// Executed as TwoThirdsMajority could be from a higher round
cs.enterNewRound(height, int(vote.Round))
cs.enterPrecommit(height, int(vote.Round))
if len(blockID.Hash) != 0 {
cs.enterCommit(height, int(vote.Round))
if skipTimeoutCommit && precommits.HasAll() {
cs.enterNewRound(cs.Height, 0)
}
} else {
cs.enterPrecommitWait(height, int(vote.Round))
}
} else if cs.Round <= int(vote.Round) && precommits.HasTwoThirdsAny() {
cs.enterNewRound(height, int(vote.Round))
cs.enterPrecommitWait(height, int(vote.Round))
}
default:
panic(fmt.Sprintf("Unexpected vote type %X", vote.Type)) // Should not happen.
} }
// Height mismatch, bad peer? return added, err
tendermintlog.Debug("Vote ignored and not added", "voteType", vote.Type, "voteHeight", vote.Height, "csHeight", cs.Height, "err", err)
return
} }
func (cs *ConsensusState) signVote(voteType byte, hash []byte) (*ttypes.Vote, error) { func (cs *ConsensusState) signVote(voteType byte, hash []byte) (*ttypes.Vote, error) {
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tendermint
import (
"encoding/json"
"fmt"
"reflect"
"sync"
dbm "github.com/33cn/chain33/common/db"
ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/pkg/errors"
)
/*
Requirements:
- Valid new evidence must be persisted immediately and never forgotten
- Uncommitted evidence must be continuously broadcast
- Uncommitted evidence has a partial order, the evidence's priority
Impl:
- First commit atomically in outqueue, pending, lookup.
- Once broadcast, remove from outqueue. No need to sync
- Once committed, atomically remove from pending and update lookup.
- TODO: If we crash after committed but before removing/updating,
we'll be stuck broadcasting evidence we never know we committed.
so either share the state db and atomically MarkCommitted
with ApplyBlock, or check all outqueue/pending on Start to see if its committed
Schema for indexing evidence (note you need both height and hash to find a piece of evidence):
"evidence-lookup"/<evidence-height>/<evidence-hash> -> EvidenceInfo
"evidence-outqueue"/<priority>/<evidence-height>/<evidence-hash> -> EvidenceInfo
"evidence-pending"/<evidence-height>/<evidence-hash> -> EvidenceInfo
*/
type envelope struct {
Kind string `json:"type"`
Data *json.RawMessage `json:"data"`
}
// EvidenceInfo struct
type EvidenceInfo struct {
Committed bool `json:"committed"`
Priority int64 `json:"priority"`
Evidence envelope `json:"evidence"`
}
const (
baseKeyLookup = "evidence-lookup" // all evidence
baseKeyOutqueue = "evidence-outqueue" // not-yet broadcast
baseKeyPending = "evidence-pending" // broadcast but not committed
)
func keyLookup(evidence ttypes.Evidence) []byte {
return keyLookupFromHeightAndHash(evidence.Height(), evidence.Hash())
}
// big endian padded hex
func bE(h int64) string {
return fmt.Sprintf("%0.16X", h)
}
func keyLookupFromHeightAndHash(height int64, hash []byte) []byte {
return _key("%s/%s/%X", baseKeyLookup, bE(height), hash)
}
func keyOutqueue(evidence ttypes.Evidence, priority int64) []byte {
return _key("%s/%s/%s/%X", baseKeyOutqueue, bE(priority), bE(evidence.Height()), evidence.Hash())
}
func keyPending(evidence ttypes.Evidence) []byte {
return _key("%s/%s/%X", baseKeyPending, bE(evidence.Height()), evidence.Hash())
}
func _key(s string, o ...interface{}) []byte {
return []byte(fmt.Sprintf(s, o...))
}
// EvidenceStore is a store of all the evidence we've seen, including
// evidence that has been committed, evidence that has been verified but not broadcast,
// and evidence that has been broadcast but not yet committed.
type EvidenceStore struct {
db dbm.DB
}
// NewEvidenceStore method
func NewEvidenceStore(db dbm.DB) *EvidenceStore {
if len(ttypes.EvidenceType2Type) == 0 {
ttypes.EvidenceType2Type = map[string]reflect.Type{
ttypes.DuplicateVote: reflect.TypeOf(tmtypes.DuplicateVoteEvidence{}),
}
}
if len(ttypes.EvidenceType2Obj) == 0 {
ttypes.EvidenceType2Obj = map[string]ttypes.Evidence{
ttypes.DuplicateVote: &ttypes.DuplicateVoteEvidence{},
}
}
return &EvidenceStore{
db: db,
}
}
// PriorityEvidence returns the evidence from the outqueue, sorted by highest priority.
func (store *EvidenceStore) PriorityEvidence() (evidence []ttypes.Evidence) {
// reverse the order so highest priority is first
l := store.ListEvidence(baseKeyOutqueue)
l2 := make([]ttypes.Evidence, len(l))
for i := range l {
l2[i] = l[len(l)-1-i]
}
return l2
}
// PendingEvidence returns all known uncommitted evidence.
func (store *EvidenceStore) PendingEvidence() (evidence []ttypes.Evidence) {
return store.ListEvidence(baseKeyPending)
}
// ListEvidence lists the evidence for the given prefix key.
// It is wrapped by PriorityEvidence and PendingEvidence for convenience.
func (store *EvidenceStore) ListEvidence(prefixKey string) (evidence []ttypes.Evidence) {
iter := store.db.Iterator([]byte(prefixKey), nil, false)
for iter.Next() {
val := iter.Value()
evi, err := store.EvidenceFromInfoBytes(val)
if err != nil {
fmt.Printf("ListEvidence evidence info unmarshal failed:%v", err)
} else {
evidence = append(evidence, evi)
}
}
return evidence
}
// GetEvidence fetches the evidence with the given height and hash.
func (store *EvidenceStore) GetEvidence(height int64, hash []byte) *EvidenceInfo {
key := keyLookupFromHeightAndHash(height, hash)
val, e := store.db.Get(key)
if e != nil {
fmt.Printf(fmt.Sprintf(`GetEvidence: db get key %v failed:%v\n`, key, e))
}
if len(val) == 0 {
return nil
}
var ei EvidenceInfo
err := json.Unmarshal(val, &ei)
if err != nil {
fmt.Printf(fmt.Sprintf(`GetEvidence: unmarshal failed:%v\n`, err))
}
return &ei
}
// AddNewEvidence adds the given evidence to the database.
// It returns false if the evidence is already stored.
func (store *EvidenceStore) AddNewEvidence(evidence ttypes.Evidence, priority int64) bool {
// check if we already have seen it
ei := store.GetEvidence(evidence.Height(), evidence.Hash())
if ei != nil && len(ei.Evidence.Kind) == 0 {
return false
}
eiBytes, err := EvidenceToInfoBytes(evidence, priority)
if err != nil {
fmt.Printf("AddNewEvidence failed:%v\n", err)
return false
}
// add it to the store
key := keyOutqueue(evidence, priority)
if err = store.db.Set(key, eiBytes); err != nil {
fmt.Printf("AddNewEvidence Set failed:%v\n", err)
return false
}
key = keyPending(evidence)
if err = store.db.Set(key, eiBytes); err != nil {
fmt.Printf("AddNewEvidence Set failed:%v\n", err)
return false
}
key = keyLookup(evidence)
if err = store.db.SetSync(key, eiBytes); err != nil {
fmt.Printf("AddNewEvidence SetSync failed:%v\n", err)
return false
}
return true
}
// MarkEvidenceAsBroadcasted removes evidence from Outqueue.
func (store *EvidenceStore) MarkEvidenceAsBroadcasted(evidence ttypes.Evidence) {
ei := store.getEvidenceInfo(evidence)
key := keyOutqueue(evidence, ei.Priority)
if err := store.db.Delete(key); err != nil {
fmt.Printf("MarkEvidenceAsBroadcasted Delete failed:%v", err)
}
}
// MarkEvidenceAsCommitted removes evidence from pending and outqueue and sets the state to committed.
func (store *EvidenceStore) MarkEvidenceAsCommitted(evidence ttypes.Evidence) {
// if its committed, its been broadcast
store.MarkEvidenceAsBroadcasted(evidence)
pendingKey := keyPending(evidence)
if err := store.db.Delete(pendingKey); err != nil {
fmt.Printf("MarkEvidenceAsCommitted Delete failed:%v", err)
}
ei := store.getEvidenceInfo(evidence)
ei.Committed = true
lookupKey := keyLookup(evidence)
eiBytes, err := json.Marshal(ei)
if err != nil {
fmt.Printf("MarkEvidenceAsCommitted marshal failed:%v", err)
}
if err = store.db.SetSync(lookupKey, eiBytes); err != nil {
fmt.Printf("MarkEvidenceAsCommitted SetSync failed:%v", err)
}
}
//---------------------------------------------------
// utils
func (store *EvidenceStore) getEvidenceInfo(evidence ttypes.Evidence) EvidenceInfo {
key := keyLookup(evidence)
var ei EvidenceInfo
b, e := store.db.Get(key)
if e != nil {
fmt.Printf(fmt.Sprintf(`getEvidenceInfo: db get key %v failed:%v\n`, key, e))
}
err := json.Unmarshal(b, &ei)
if err != nil {
fmt.Printf(fmt.Sprintf(`getEvidenceInfo: Unmarshal failed:%v\n`, err))
}
return ei
}
// EvidenceToInfoBytes method
func EvidenceToInfoBytes(evidence ttypes.Evidence, priority int64) ([]byte, error) {
evi, err := json.Marshal(evidence)
if err != nil {
return nil, errors.Errorf("EvidenceToBytes marshal evidence failed:%v\n", err)
}
msg := json.RawMessage(evi)
env := envelope{
Kind: evidence.TypeName(),
Data: &msg,
}
ei := EvidenceInfo{
Committed: false,
Priority: priority,
Evidence: env,
}
eiBytes, err := json.Marshal(ei)
if err != nil {
return nil, errors.Errorf("EvidenceToBytes marshal evidence info failed:%v\n", err)
}
return eiBytes, nil
}
// EvidenceFromInfoBytes method
func (store *EvidenceStore) EvidenceFromInfoBytes(data []byte) (ttypes.Evidence, error) {
vote2 := EvidenceInfo{}
err := json.Unmarshal(data, &vote2)
if err != nil {
return nil, errors.Errorf("BytesToEvidence Unmarshal evidence info failed:%v\n", err)
}
if v, ok := ttypes.EvidenceType2Type[vote2.Evidence.Kind]; ok {
tmp := v.(ttypes.Evidence).Copy()
err = json.Unmarshal(*vote2.Evidence.Data, &tmp)
if err != nil {
return nil, errors.Errorf("BytesToEvidence Unmarshal evidence failed:%v\n", err)
}
return tmp, nil
}
return nil, errors.Errorf("BytesToEvidence not find evidence kind:%v\n", vote2.Evidence.Kind)
}
// EvidencePool maintains a pool of valid evidence
// in an EvidenceStore.
type EvidencePool struct {
evidenceStore *EvidenceStore
// needed to load validators to verify evidence
stateDB *CSStateDB
// latest state
mtx sync.Mutex
state State
// never close
evidenceChan chan ttypes.Evidence
}
// NewEvidencePool method
func NewEvidencePool(stateDB *CSStateDB, state State, evidenceStore *EvidenceStore) *EvidencePool {
evpool := &EvidencePool{
stateDB: stateDB,
state: state,
evidenceStore: evidenceStore,
evidenceChan: make(chan ttypes.Evidence),
}
return evpool
}
// EvidenceChan returns an unbuffered channel on which new evidence can be received.
func (evpool *EvidencePool) EvidenceChan() <-chan ttypes.Evidence {
return evpool.evidenceChan
}
// PriorityEvidence returns the priority evidence.
func (evpool *EvidencePool) PriorityEvidence() []ttypes.Evidence {
return evpool.evidenceStore.PriorityEvidence()
}
// PendingEvidence returns all uncommitted evidence.
func (evpool *EvidencePool) PendingEvidence() []ttypes.Evidence {
return evpool.evidenceStore.PendingEvidence()
}
// State returns the current state of the evpool.
func (evpool *EvidencePool) State() State {
evpool.mtx.Lock()
defer evpool.mtx.Unlock()
return evpool.state
}
// Update loads the latest
func (evpool *EvidencePool) Update(block *ttypes.TendermintBlock) {
evpool.mtx.Lock()
defer evpool.mtx.Unlock()
state := evpool.stateDB.LoadState()
if state.LastBlockHeight != block.Header.Height {
panic(fmt.Sprintf("EvidencePool.Update: loaded state with height %d when block.Height=%d", state.LastBlockHeight, block.Header.Height))
}
evpool.state = state
// NOTE: shouldn't need the mutex
evpool.MarkEvidenceAsCommitted(block.Evidence.Evidence)
}
// AddEvidence checks the evidence is valid and adds it to the pool.
// Blocks on the EvidenceChan.
func (evpool *EvidencePool) AddEvidence(evidence ttypes.Evidence) error {
// TODO: check if we already have evidence for this
// validator at this height so we dont get spammed
if err := VerifyEvidence(evpool.stateDB, evpool.State(), evidence); err != nil {
return err
}
// fetch the validator and return its voting power as its priority
// TODO: something better ?
valset, err := evpool.stateDB.LoadValidators(evidence.Height())
if err != nil {
return err
}
_, val := valset.GetByAddress(evidence.Address())
priority := val.VotingPower
added := evpool.evidenceStore.AddNewEvidence(evidence, priority)
if !added {
// evidence already known, just ignore
return nil
}
tendermintlog.Info("Verified new evidence of byzantine behaviour", "evidence", evidence)
// never closes. always safe to send on
evpool.evidenceChan <- evidence
return nil
}
// MarkEvidenceAsCommitted marks all the evidence as committed.
func (evpool *EvidencePool) MarkEvidenceAsCommitted(evidence []*tmtypes.EvidenceEnvelope) {
for _, ev := range evidence {
tmp := ttypes.EvidenceEnvelope2Evidence(ev)
if tmp != nil {
evpool.evidenceStore.MarkEvidenceAsCommitted(tmp)
}
}
}
// VerifyEvidence verifies the evidence fully by checking it is internally
// consistent and sufficiently recent.
func VerifyEvidence(stateDB *CSStateDB, s State, evidence ttypes.Evidence) error {
height := s.LastBlockHeight
evidenceAge := height - evidence.Height()
maxAge := s.ConsensusParams.EvidenceParams.MaxAge
if evidenceAge > maxAge {
return fmt.Errorf("Evidence from height %d is too old. Min height is %d",
evidence.Height(), height-maxAge)
}
if err := evidence.Verify(s.ChainID); err != nil {
return err
}
valset, err := stateDB.LoadValidators(evidence.Height())
if err != nil {
// TODO: if err is just that we cant find it cuz we pruned, ignore.
// TODO: if its actually bad evidence, punish peer
return err
}
// The address must have been an active validator at the height
ev := evidence
height, addr, idx := ev.Height(), ev.Address(), ev.Index()
valIdx, val := valset.GetByAddress(addr)
if val == nil {
return fmt.Errorf("Address %X was not a validator at height %d", addr, height)
} else if idx != valIdx {
return fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx)
}
return nil
}
...@@ -21,16 +21,14 @@ import ( ...@@ -21,16 +21,14 @@ import (
// BlockExecutor provides the context and accessories for properly executing a block. // BlockExecutor provides the context and accessories for properly executing a block.
type BlockExecutor struct { type BlockExecutor struct {
// save state, validators, consensus params, abci responses here // save state, validators, consensus params, abci responses here
db *CSStateDB db *CSStateDB
evpool ttypes.EvidencePool
} }
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus. // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
// Call SetEventBus to provide one. // Call SetEventBus to provide one.
func NewBlockExecutor(db *CSStateDB, evpool ttypes.EvidencePool) *BlockExecutor { func NewBlockExecutor(db *CSStateDB) *BlockExecutor {
return &BlockExecutor{ return &BlockExecutor{
db: db, db: db,
evpool: evpool,
} }
} }
...@@ -59,12 +57,6 @@ func (blockExec *BlockExecutor) ApplyBlock(s State, blockID ttypes.BlockID, bloc ...@@ -59,12 +57,6 @@ func (blockExec *BlockExecutor) ApplyBlock(s State, blockID ttypes.BlockID, bloc
} }
blockExec.db.SaveState(s) blockExec.db.SaveState(s)
// Update evpool now that state is saved
// TODO: handle the crash/recover scenario
// ie. (may need to call Update for last block)
blockExec.evpool.Update(block)
return s, nil return s, nil
} }
...@@ -191,7 +183,10 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *ttypes.ValidatorSet, u ...@@ -191,7 +183,10 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *ttypes.ValidatorSet, u
} }
func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error { func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error {
newTxs := b.Header.NumTxs // Validate internal consistency.
if err := b.ValidateBasic(); err != nil {
return err
}
// validate basic info // validate basic info
if b.Header.ChainID != s.ChainID { if b.Header.ChainID != s.ChainID {
...@@ -206,6 +201,7 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error ...@@ -206,6 +201,7 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.Header.LastBlockID) return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.Header.LastBlockID)
} }
newTxs := b.Header.NumTxs
if b.Header.TotalTxs != s.LastBlockTotalTx+newTxs { if b.Header.TotalTxs != s.LastBlockTotalTx+newTxs {
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.Header.TotalTxs) return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.Header.TotalTxs)
} }
...@@ -242,13 +238,5 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error ...@@ -242,13 +238,5 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error
} }
} }
for _, ev := range b.Evidence.Evidence {
evidence := ttypes.EvidenceEnvelope2Evidence(ev)
if evidence != nil {
if err := VerifyEvidence(stateDB, s, evidence); err != nil {
return ttypes.NewEvidenceInvalidErr(evidence, err)
}
}
}
return nil return nil
} }
...@@ -17,8 +17,6 @@ import ( ...@@ -17,8 +17,6 @@ import (
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types" ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/golang/protobuf/proto"
) )
const ( const (
...@@ -44,8 +42,6 @@ const ( ...@@ -44,8 +42,6 @@ const (
minReadBufferSize = 1024 minReadBufferSize = 1024
minWriteBufferSize = 65536 minWriteBufferSize = 65536
broadcastEvidenceIntervalS = 60 // broadcast uncommitted evidence this often
) )
// Parallel method // Parallel method
...@@ -132,7 +128,6 @@ type Node struct { ...@@ -132,7 +128,6 @@ type Node struct {
lAddr string lAddr string
state *ConsensusState state *ConsensusState
evpool *EvidencePool
broadcastChannel chan MsgInfo broadcastChannel chan MsgInfo
started uint32 // atomic started uint32 // atomic
stopped uint32 // atomic stopped uint32 // atomic
...@@ -140,7 +135,7 @@ type Node struct { ...@@ -140,7 +135,7 @@ type Node struct {
} }
// NewNode method // NewNode method
func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState, evpool *EvidencePool) *Node { func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState) *Node {
address := GenAddressByPubKey(privKey.PubKey()) address := GenAddressByPubKey(privKey.PubKey())
node := &Node{ node := &Node{
...@@ -158,7 +153,6 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK ...@@ -158,7 +153,6 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK
reconnecting: NewMutexMap(), reconnecting: NewMutexMap(),
broadcastChannel: make(chan MsgInfo, maxSendQueueSize), broadcastChannel: make(chan MsgInfo, maxSendQueueSize),
state: state, state: state,
evpool: evpool,
localIPs: make(map[string]net.IP), localIPs: make(map[string]net.IP),
} }
...@@ -219,7 +213,6 @@ func (node *Node) Start() { ...@@ -219,7 +213,6 @@ func (node *Node) Start() {
go node.StartConsensusRoutine() go node.StartConsensusRoutine()
go node.BroadcastRoutine() go node.BroadcastRoutine()
go node.evidenceBroadcastRoutine()
} }
} }
...@@ -234,7 +227,7 @@ func (node *Node) DialPeerWithAddress(addr string) error { ...@@ -234,7 +227,7 @@ func (node *Node) DialPeerWithAddress(addr string) error {
func (node *Node) addOutboundPeerWithConfig(addr string) error { func (node *Node) addOutboundPeerWithConfig(addr string) error {
tendermintlog.Info("Dialing peer", "address", addr) tendermintlog.Info("Dialing peer", "address", addr)
peerConn, err := newOutboundPeerConn(addr, node.privKey, node.StopPeerForError, node.state, node.evpool) peerConn, err := newOutboundPeerConn(addr, node.privKey, node.StopPeerForError, node.state)
if err != nil { if err != nil {
go node.reconnectToPeer(addr) go node.reconnectToPeer(addr)
return err return err
...@@ -307,66 +300,6 @@ func (node *Node) StartConsensusRoutine() { ...@@ -307,66 +300,6 @@ func (node *Node) StartConsensusRoutine() {
} }
} }
func (node *Node) evidenceBroadcastRoutine() {
ticker := time.NewTicker(time.Second * broadcastEvidenceIntervalS)
for {
select {
case evidence := <-node.evpool.EvidenceChan():
// broadcast some new evidence
data, err := proto.Marshal(evidence.Child())
if err != nil {
msg := MsgInfo{TypeID: ttypes.EvidenceListID,
Msg: &tmtypes.EvidenceData{
Evidence: []*tmtypes.EvidenceEnvelope{
{
TypeName: evidence.TypeName(),
Data: data,
},
},
},
PeerID: node.ID, PeerIP: node.IP,
}
node.Broadcast(msg)
// TODO: Broadcast runs asynchronously, so this should wait on the successChan
// in another routine before marking to be proper.
node.evpool.evidenceStore.MarkEvidenceAsBroadcasted(evidence)
}
case <-ticker.C:
// broadcast all pending evidence
var eData tmtypes.EvidenceData
evidence := node.evpool.PendingEvidence()
for _, item := range evidence {
ev := item.Child()
if ev != nil {
data, err := proto.Marshal(ev)
if err != nil {
panic("AddEvidence marshal failed")
}
env := &tmtypes.EvidenceEnvelope{
TypeName: item.TypeName(),
Data: data,
}
eData.Evidence = append(eData.Evidence, env)
}
}
msg := MsgInfo{TypeID: ttypes.EvidenceListID,
Msg: &eData,
PeerID: node.ID,
PeerIP: node.IP,
}
node.Broadcast(msg)
case _, ok := <-node.quit:
if !ok {
node.quit = nil
tendermintlog.Info("evidenceBroadcastRoutine quit")
return
}
}
}
}
// BroadcastRoutine receive to broadcast // BroadcastRoutine receive to broadcast
func (node *Node) BroadcastRoutine() { func (node *Node) BroadcastRoutine() {
for { for {
...@@ -413,7 +346,7 @@ func (node *Node) StopPeerForError(peer Peer, reason interface{}) { ...@@ -413,7 +346,7 @@ func (node *Node) StopPeerForError(peer Peer, reason interface{}) {
} }
func (node *Node) addInboundPeer(conn net.Conn) error { func (node *Node) addInboundPeer(conn net.Conn) error {
peerConn, err := newInboundPeerConn(conn, node.privKey, node.StopPeerForError, node.state, node.evpool) peerConn, err := newInboundPeerConn(conn, node.privKey, node.StopPeerForError, node.state)
if err != nil { if err != nil {
if er := conn.Close(); er != nil { if er := conn.Close(); er != nil {
tendermintlog.Error("addInboundPeer close conn failed", "er", er) tendermintlog.Error("addInboundPeer close conn failed", "er", er)
...@@ -481,11 +414,6 @@ func (node *Node) addPeer(pc *peerConn) error { ...@@ -481,11 +414,6 @@ func (node *Node) addPeer(pc *peerConn) error {
return fmt.Errorf("get remote ip failed:%v", rErr) return fmt.Errorf("get remote ip failed:%v", rErr)
} }
// Filter peer against ID white list
//if err := node.FilterConnByID(peerID); err != nil {
//return err
//}
// Check version, chain id // Check version, chain id
if err := node.CompatibleWith(peerNodeInfo); err != nil { if err := node.CompatibleWith(peerNodeInfo); err != nil {
return err return err
...@@ -507,7 +435,6 @@ func (node *Node) addPeer(pc *peerConn) error { ...@@ -507,7 +435,6 @@ func (node *Node) addPeer(pc *peerConn) error {
if err := node.peerSet.Add(pc); err != nil { if err := node.peerSet.Add(pc); err != nil {
return err return err
} }
//node.metrics.Peers.Add(float64(1))
tendermintlog.Info("Added peer", "peer", pc.ip) tendermintlog.Info("Added peer", "peer", pc.ip)
return nil return nil
...@@ -710,13 +637,13 @@ func dial(addr string) (net.Conn, error) { ...@@ -710,13 +637,13 @@ func dial(addr string) (net.Conn, error) {
return conn, nil return conn, nil
} }
func newOutboundPeerConn(addr string, ourNodePrivKey crypto.PrivKey, onPeerError func(Peer, interface{}), state *ConsensusState, evpool *EvidencePool) (*peerConn, error) { func newOutboundPeerConn(addr string, ourNodePrivKey crypto.PrivKey, onPeerError func(Peer, interface{}), state *ConsensusState) (*peerConn, error) {
conn, err := dial(addr) conn, err := dial(addr)
if err != nil { if err != nil {
return &peerConn{}, fmt.Errorf("Error creating peer:%v", err) return &peerConn{}, fmt.Errorf("Error creating peer:%v", err)
} }
pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state, evpool) pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state)
if err != nil { if err != nil {
if cerr := conn.Close(); cerr != nil { if cerr := conn.Close(); cerr != nil {
return &peerConn{}, fmt.Errorf("newPeerConn failed:%v, connection close failed:%v", err, cerr) return &peerConn{}, fmt.Errorf("newPeerConn failed:%v, connection close failed:%v", err, cerr)
...@@ -732,12 +659,11 @@ func newInboundPeerConn( ...@@ -732,12 +659,11 @@ func newInboundPeerConn(
ourNodePrivKey crypto.PrivKey, ourNodePrivKey crypto.PrivKey,
onPeerError func(Peer, interface{}), onPeerError func(Peer, interface{}),
state *ConsensusState, state *ConsensusState,
evpool *EvidencePool,
) (*peerConn, error) { ) (*peerConn, error) {
// TODO: issue PoW challenge // TODO: issue PoW challenge
return newPeerConn(conn, false, false, ourNodePrivKey, onPeerError, state, evpool) return newPeerConn(conn, false, false, ourNodePrivKey, onPeerError, state)
} }
func newPeerConn( func newPeerConn(
...@@ -746,7 +672,6 @@ func newPeerConn( ...@@ -746,7 +672,6 @@ func newPeerConn(
ourNodePrivKey crypto.PrivKey, ourNodePrivKey crypto.PrivKey,
onPeerError func(Peer, interface{}), onPeerError func(Peer, interface{}),
state *ConsensusState, state *ConsensusState,
evpool *EvidencePool,
) (pc *peerConn, err error) { ) (pc *peerConn, err error) {
conn := rawConn conn := rawConn
...@@ -769,6 +694,5 @@ func newPeerConn( ...@@ -769,6 +694,5 @@ func newPeerConn(
conn: conn, conn: conn,
onPeerError: onPeerError, onPeerError: onPeerError,
myState: state, myState: state,
myevpool: evpool,
}, nil }, nil
} }
package tendermint
import (
"encoding/hex"
"fmt"
"sync"
"testing"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
var (
secureConnCrypto crypto.Crypto
sum = 0
mutx sync.Mutex
privKey = "B3DC4C0725884EBB7264B92F1D8D37584A64ADE1799D997EC64B4FE3973E08DE220ACBE680DF2473A0CB48987A00FCC1812F106A7390BE6B8E2D31122C992A19"
expectAddress = "02A13174B92727C4902DB099E51A3339F48BD45E"
)
func init() {
cr2, err := crypto.New(types.GetSignName("", types.ED25519))
if err != nil {
fmt.Println("crypto.New failed for types.ED25519")
return
}
secureConnCrypto = cr2
}
func TestParallel(t *testing.T) {
Parallel(
func() {
mutx.Lock()
sum++
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 2
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 3
mutx.Unlock()
},
)
fmt.Println("TestParallel ok")
assert.Equal(t, 6, sum)
}
func TestGenAddressByPubKey(t *testing.T) {
tmp, err := hex.DecodeString(privKey)
assert.Nil(t, err)
priv, err := secureConnCrypto.PrivKeyFromBytes(tmp)
assert.Nil(t, err)
addr := GenAddressByPubKey(priv.PubKey())
strAddr := fmt.Sprintf("%X", addr)
assert.Equal(t, expectAddress, strAddr)
fmt.Println("TestGenAddressByPubKey ok")
}
func TestIP2IPPort(t *testing.T) {
testMap := NewMutexMap()
assert.Equal(t, false, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.1", "1.1.1.1:80")
assert.Equal(t, true, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.2", "1.1.1.2:80")
assert.Equal(t, true, testMap.Has("1.1.1.2"))
testMap.Delete("1.1.1.1")
assert.Equal(t, false, testMap.Has("1.1.1.1"))
fmt.Println("TestIP2IPPort ok")
}
func TestPeerSet(t *testing.T) {
testSet := NewPeerSet()
assert.Equal(t, false, testSet.Has("1"))
peer1 := &peerConn{id: "1", ip: []byte("1.1.1.1")}
testSet.Add(peer1)
assert.Equal(t, true, testSet.Has("1"))
assert.Equal(t, true, testSet.HasIP([]byte("1.1.1.1")))
err := testSet.Add(peer1)
assert.NotNil(t, err)
peer2 := &peerConn{id: "2", ip: []byte("1.1.1.2")}
testSet.Add(peer2)
assert.Equal(t, true, testSet.Has("2"))
assert.Equal(t, 2, testSet.Size())
testSet.Remove(peer1)
assert.Equal(t, 1, testSet.Size())
assert.Equal(t, false, testSet.Has("1"))
assert.Equal(t, false, testSet.HasIP([]byte("1.1.1.1")))
fmt.Println("TestPeerSet ok")
}
...@@ -6,6 +6,7 @@ package tendermint ...@@ -6,6 +6,7 @@ package tendermint
import ( import (
"bufio" "bufio"
"bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
...@@ -93,8 +94,7 @@ type peerConn struct { ...@@ -93,8 +94,7 @@ type peerConn struct {
onPeerError func(Peer, interface{}) onPeerError func(Peer, interface{})
myState *ConsensusState myState *ConsensusState
myevpool *EvidencePool
state *PeerConnState state *PeerConnState
updateStateQueue chan MsgInfo updateStateQueue chan MsgInfo
...@@ -374,6 +374,21 @@ func (pc *peerConn) TrySend(msg MsgInfo) bool { ...@@ -374,6 +374,21 @@ func (pc *peerConn) TrySend(msg MsgInfo) bool {
} }
} }
// PickSendVote picks a vote and sends it to the peer.
// Returns true if vote was sent.
func (pc *peerConn) PickSendVote(votes ttypes.VoteSetReader) bool {
if vote, ok := pc.state.PickVoteToSend(votes); ok {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()}
tendermintlog.Debug("Sending vote message", "vote", msg)
if pc.Send(msg) {
pc.state.SetHasVote(vote)
return true
}
return false
}
return false
}
func (pc *peerConn) IsRunning() bool { func (pc *peerConn) IsRunning() bool {
return atomic.LoadUint32(&pc.started) == 1 && atomic.LoadUint32(&pc.stopped) == 0 return atomic.LoadUint32(&pc.started) == 1 && atomic.LoadUint32(&pc.stopped) == 0
} }
...@@ -545,7 +560,8 @@ FOR_LOOP: ...@@ -545,7 +560,8 @@ FOR_LOOP:
tendermintlog.Error("peerConn recvRoutine Unmarshal data failed", "err", err) tendermintlog.Error("peerConn recvRoutine Unmarshal data failed", "err", err)
continue continue
} }
if pc.transferChannel != nil && (pkt.TypeID == ttypes.ProposalID || pkt.TypeID == ttypes.VoteID || pkt.TypeID == ttypes.ProposalBlockID) { if pc.transferChannel != nil && (pkt.TypeID == ttypes.ProposalID || pkt.TypeID == ttypes.VoteID ||
pkt.TypeID == ttypes.ProposalBlockID) {
pc.transferChannel <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()} pc.transferChannel <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()}
if pkt.TypeID == ttypes.ProposalID { if pkt.TypeID == ttypes.ProposalID {
proposal := realMsg.(*tmtypes.Proposal) proposal := realMsg.(*tmtypes.Proposal)
...@@ -562,19 +578,6 @@ FOR_LOOP: ...@@ -562,19 +578,6 @@ FOR_LOOP:
} }
} else if pkt.TypeID == ttypes.ProposalHeartbeatID { } else if pkt.TypeID == ttypes.ProposalHeartbeatID {
pc.heartbeatQueue <- realMsg.(*tmtypes.Heartbeat) pc.heartbeatQueue <- realMsg.(*tmtypes.Heartbeat)
} else if pkt.TypeID == ttypes.EvidenceListID {
go func() {
for _, ev := range realMsg.(*tmtypes.EvidenceData).Evidence {
evidence := ttypes.EvidenceEnvelope2Evidence(ev)
if evidence != nil {
err := pc.myevpool.AddEvidence(evidence.(ttypes.Evidence))
if err != nil {
tendermintlog.Error("Evidence is not valid", "evidence", ev, "err", err)
// TODO: punish peer
}
}
}
}()
} else { } else {
pc.updateStateQueue <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()} pc.updateStateQueue <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()}
} }
...@@ -601,12 +604,15 @@ FOR_LOOP: ...@@ -601,12 +604,15 @@ FOR_LOOP:
typeID := msg.TypeID typeID := msg.TypeID
if typeID == ttypes.NewRoundStepID { if typeID == ttypes.NewRoundStepID {
pc.state.ApplyNewRoundStepMessage(msg.Msg.(*tmtypes.NewRoundStepMsg)) pc.state.ApplyNewRoundStepMessage(msg.Msg.(*tmtypes.NewRoundStepMsg))
} else if typeID == ttypes.ValidBlockID {
pc.state.ApplyValidBlockMessage(msg.Msg.(*tmtypes.ValidBlockMsg))
} else if typeID == ttypes.CommitStepID { } else if typeID == ttypes.CommitStepID {
pc.state.ApplyCommitStepMessage(msg.Msg.(*tmtypes.CommitStepMsg)) pc.state.ApplyCommitStepMessage(msg.Msg.(*tmtypes.CommitStepMsg))
} else if typeID == ttypes.HasVoteID { } else if typeID == ttypes.HasVoteID {
pc.state.ApplyHasVoteMessage(msg.Msg.(*tmtypes.HasVoteMsg)) pc.state.ApplyHasVoteMessage(msg.Msg.(*tmtypes.HasVoteMsg))
} else if typeID == ttypes.VoteSetMaj23ID { } else if typeID == ttypes.VoteSetMaj23ID {
tmp := msg.Msg.(*tmtypes.VoteSetMaj23Msg) tmp := msg.Msg.(*tmtypes.VoteSetMaj23Msg)
tendermintlog.Debug("updateStateRoutine", "VoteSetMaj23Msg", tmp)
pc.myState.SetPeerMaj23(tmp.Height, int(tmp.Round), byte(tmp.Type), pc.id, tmp.BlockID) pc.myState.SetPeerMaj23(tmp.Height, int(tmp.Round), byte(tmp.Type), pc.id, tmp.BlockID)
var myVotes *ttypes.BitArray var myVotes *ttypes.BitArray
switch byte(tmp.Type) { switch byte(tmp.Type) {
...@@ -692,16 +698,21 @@ OUTER_LOOP: ...@@ -692,16 +698,21 @@ OUTER_LOOP:
// If the peer is on a previous height, help catch up. // If the peer is on a previous height, help catch up.
if (0 < prs.Height) && (prs.Height < rs.Height) { if (0 < prs.Height) && (prs.Height < rs.Height) {
if prs.Height+1 == rs.Height && prs.Round == rs.LastCommit.Round() && prs.Step == ttypes.RoundStepCommit && prs.ProposalBlock { if prs.ProposalBlockHash == nil || prs.ProposalBlock {
tendermintlog.Debug("Peer is waiting for finalizeCommit finish", "peerip", pc.ip.String(), time.Sleep(pc.myState.PeerGossipSleep())
"state", fmt.Sprintf("%v/%v/%v", prs.Height, prs.Round, prs.Step))
time.Sleep(10 * pc.myState.PeerGossipSleep())
continue OUTER_LOOP continue OUTER_LOOP
} }
tendermintlog.Info("help catch up", "peerip", pc.ip.String(), "selfHeight", rs.Height, "peerHeight", prs.Height) tendermintlog.Info("help catch up", "peerip", pc.ip.String(), "selfHeight", rs.Height, "peerHeight", prs.Height)
proposalBlock := pc.myState.client.LoadProposalBlock(prs.Height) proposalBlock := pc.myState.client.LoadProposalBlock(prs.Height)
newBlock := &ttypes.TendermintBlock{TendermintBlock: proposalBlock}
if proposalBlock == nil { if proposalBlock == nil {
tendermintlog.Error("Failed to load propsal block", "selfHeight", rs.Height, "blockstoreHeight", pc.myState.client.GetCurrentHeight()) tendermintlog.Error("Fail to load propsal block", "selfHeight", rs.Height,
"blockstoreHeight", pc.myState.client.GetCurrentHeight())
time.Sleep(pc.myState.PeerGossipSleep())
continue OUTER_LOOP
} else if !bytes.Equal(newBlock.Hash(), prs.ProposalBlockHash) {
tendermintlog.Error("Peer ProposalBlockHash mismatch", "ProposalBlockHash", fmt.Sprintf("%X", prs.ProposalBlockHash),
"newBlockHash", fmt.Sprintf("%X", newBlock.Hash()))
time.Sleep(pc.myState.PeerGossipSleep()) time.Sleep(pc.myState.PeerGossipSleep())
continue OUTER_LOOP continue OUTER_LOOP
} }
...@@ -709,9 +720,8 @@ OUTER_LOOP: ...@@ -709,9 +720,8 @@ OUTER_LOOP:
tendermintlog.Info("Sending block for catchup", "peerip", pc.ip.String(), "block(H/R)", tendermintlog.Info("Sending block for catchup", "peerip", pc.ip.String(), "block(H/R)",
fmt.Sprintf("%v/%v", proposalBlock.Header.Height, proposalBlock.Header.Round)) fmt.Sprintf("%v/%v", proposalBlock.Header.Height, proposalBlock.Header.Round))
if pc.Send(msg) { if pc.Send(msg) {
//prs.SetHasProposalBlock(rs.ProposalBlock) prs.SetHasProposalBlock(newBlock)
} }
time.Sleep(10 * pc.myState.PeerGossipSleep())
continue OUTER_LOOP continue OUTER_LOOP
} }
...@@ -754,14 +764,16 @@ OUTER_LOOP: ...@@ -754,14 +764,16 @@ OUTER_LOOP:
} }
// Send proposal block // Send proposal block
if rs.ProposalBlock != nil && !prs.ProposalBlock { if rs.Proposal != nil && prs.ProposalBlockHash != nil && bytes.Equal(rs.Proposal.Blockhash, prs.ProposalBlockHash) {
msg := MsgInfo{TypeID: ttypes.ProposalBlockID, Msg: rs.ProposalBlock.TendermintBlock, PeerID: pc.id, PeerIP: pc.ip.String()} if rs.ProposalBlock != nil && !prs.ProposalBlock {
tendermintlog.Debug(fmt.Sprintf("Sending proposal block. Self state: %v/%v/%v", rs.Height, rs.Round, rs.Step), msg := MsgInfo{TypeID: ttypes.ProposalBlockID, Msg: rs.ProposalBlock.TendermintBlock, PeerID: pc.id, PeerIP: pc.ip.String()}
"peerip", pc.ip.String(), "block-height", rs.ProposalBlock.Header.Height, "block-round", rs.ProposalBlock.Header.Round) tendermintlog.Debug(fmt.Sprintf("Sending proposal block. Self state: %v/%v/%v", rs.Height, rs.Round, rs.Step),
if pc.Send(msg) { "peerip", pc.ip.String(), "block-height", rs.ProposalBlock.Header.Height, "block-round", rs.ProposalBlock.Header.Round)
prs.SetHasProposalBlock(rs.ProposalBlock) if pc.Send(msg) {
prs.SetHasProposalBlock(rs.ProposalBlock)
}
continue OUTER_LOOP
} }
continue OUTER_LOOP
} }
// Nothing to do. Sleep. // Nothing to do. Sleep.
...@@ -785,9 +797,6 @@ OUTER_LOOP: ...@@ -785,9 +797,6 @@ OUTER_LOOP:
rs := pc.myState.GetRoundState() rs := pc.myState.GetRoundState()
prs := pc.state prs := pc.state
//tendermintlog.Debug("gossipVotesRoutine", "rs(H/R/S)", fmt.Sprintf("%v/%v/%v", rs.Height, rs.Round, rs.Step.String()),
// "prs(H/R/S)", fmt.Sprintf("%v/%v/%v", prs.Height, prs.Round, prs.Step.String()),
// "precommits", rs.Votes.Precommits(prs.Round).BitArray().String(), "peerip", pc.ip.String())
switch sleeping { switch sleeping {
case 1: // First sleep case 1: // First sleep
...@@ -806,11 +815,8 @@ OUTER_LOOP: ...@@ -806,11 +815,8 @@ OUTER_LOOP:
// Special catchup logic. // Special catchup logic.
// If peer is lagging by height 1, send LastCommit. // If peer is lagging by height 1, send LastCommit.
if prs.Height != 0 && rs.Height == prs.Height+1 { if prs.Height != 0 && rs.Height == prs.Height+1 {
if vote, ok := pc.state.PickVoteToSend(rs.LastCommit); ok { if pc.PickSendVote(rs.LastCommit) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.LastCommit to send", "peerip", pc.ip.String(), "height", prs.Height)
pc.Send(msg)
tendermintlog.Debug("Picked rs.LastCommit to send", "peerip", pc.ip.String(), "height", prs.Height, "vote.Height", vote.Height)
} else {
continue OUTER_LOOP continue OUTER_LOOP
} }
} }
...@@ -820,14 +826,13 @@ OUTER_LOOP: ...@@ -820,14 +826,13 @@ OUTER_LOOP:
if prs.Height != 0 && rs.Height >= prs.Height+2 { if prs.Height != 0 && rs.Height >= prs.Height+2 {
// Load the block commit for prs.Height, // Load the block commit for prs.Height,
// which contains precommit signatures for prs.Height. // which contains precommit signatures for prs.Height.
commit := pc.myState.client.LoadSeenCommit(prs.Height) commit := pc.myState.client.LoadBlockCommit(prs.Height + 1)
commitObj := &ttypes.Commit{TendermintCommit: commit} commitObj := &ttypes.Commit{TendermintCommit: commit}
if vote, ok := pc.state.PickVoteToSend(commitObj); ok { if pc.PickSendVote(commitObj) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Info("Picked Catchup commit to send",
pc.Send(msg) "commit(H/R)", fmt.Sprintf("%v/%v", commitObj.Height(), commitObj.Round()),
tendermintlog.Info("Picked Catchup commit to send", "BitArray", commitObj.BitArray().String(), "valIndex", vote.ValidatorIndex, "BitArray", commitObj.BitArray().String(),
"peerip", pc.ip.String(), "height", prs.Height, "vote.Height", vote.Height) "peerip", pc.ip.String(), "height", prs.Height)
} else {
continue OUTER_LOOP continue OUTER_LOOP
} }
} }
...@@ -851,47 +856,53 @@ OUTER_LOOP: ...@@ -851,47 +856,53 @@ OUTER_LOOP:
func (pc *peerConn) gossipVotesForHeight(rs *ttypes.RoundState, prs *ttypes.PeerRoundState) bool { func (pc *peerConn) gossipVotesForHeight(rs *ttypes.RoundState, prs *ttypes.PeerRoundState) bool {
// If there are lastCommits to send... // If there are lastCommits to send...
if prs.Step == ttypes.RoundStepNewHeight { if prs.Step == ttypes.RoundStepNewHeight {
if vote, ok := pc.state.PickVoteToSend(rs.LastCommit); ok { if pc.PickSendVote(rs.LastCommit) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.LastCommit to send", "peerip", pc.ip.String(),
pc.Send(msg) "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
tendermintlog.Debug("Picked rs.LastCommit to send", "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
return true return true
} }
} }
// If there are POL prevotes to send...
if prs.Step <= ttypes.RoundStepPropose && prs.Round != -1 && prs.Round <= rs.Round && prs.ProposalPOLRound != -1 {
if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
if pc.PickSendVote(polPrevotes) {
tendermintlog.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
"peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round),
"POLRound", prs.ProposalPOLRound)
return true
}
}
}
// If there are prevotes to send... // If there are prevotes to send...
if prs.Step <= ttypes.RoundStepPrevoteWait && prs.Round != -1 && prs.Round <= rs.Round { if prs.Step <= ttypes.RoundStepPrevoteWait && prs.Round != -1 && prs.Round <= rs.Round {
if vote, ok := pc.state.PickVoteToSend(rs.Votes.Prevotes(prs.Round)); ok { if pc.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.Prevotes(prs.Round) to send",
pc.Send(msg) "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
tendermintlog.Debug("Picked rs.Prevotes(prs.Round) to send", "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
return true return true
} }
} }
// If there are precommits to send... // If there are precommits to send...
if prs.Step <= ttypes.RoundStepPrecommitWait && prs.Round != -1 && prs.Round <= rs.Round { if prs.Step <= ttypes.RoundStepPrecommitWait && prs.Round != -1 && prs.Round <= rs.Round {
if vote, ok := pc.state.PickVoteToSend(rs.Votes.Precommits(prs.Round)); ok { if pc.PickSendVote(rs.Votes.Precommits(prs.Round)) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.Precommits(prs.Round) to send",
pc.Send(msg) "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
tendermintlog.Debug("Picked rs.Precommits(prs.Round) to send", "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
return true return true
} }
} }
// If there are prevotes to send...Needed because of validBlock mechanism // If there are prevotes to send...Needed because of validBlock mechanism
if prs.Round != -1 && prs.Round <= rs.Round { if prs.Round != -1 && prs.Round <= rs.Round {
if vote, ok := pc.state.PickVoteToSend(rs.Votes.Prevotes(prs.Round)); ok { if pc.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.Prevotes(prs.Round) to send",
pc.Send(msg) "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
tendermintlog.Debug("Picked rs.Prevotes(prs.Round) to send", "peerip", pc.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", prs.Height, prs.Round))
return true return true
} }
} }
// If there are POLPrevotes to send... // If there are POLPrevotes to send...
if prs.ProposalPOLRound != -1 { if prs.ProposalPOLRound != -1 {
if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil { if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
if vote, ok := pc.state.PickVoteToSend(polPrevotes); ok { if pc.PickSendVote(polPrevotes) {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} tendermintlog.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
pc.Send(msg) "peerip", pc.ip.String(), "round", prs.ProposalPOLRound)
tendermintlog.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send", "peerip", pc.ip.String(), "round", prs.ProposalPOLRound)
return true return true
} }
} }
...@@ -972,7 +983,7 @@ OUTER_LOOP: ...@@ -972,7 +983,7 @@ OUTER_LOOP:
// Maybe send Height/CatchupCommitRound/CatchupCommit. // Maybe send Height/CatchupCommitRound/CatchupCommit.
{ {
prs := pc.state.GetRoundState() prs := pc.state.GetRoundState()
if prs.CatchupCommitRound != -1 && 0 < prs.Height && prs.Height <= pc.myState.client.GetCurrentHeight() { if prs.CatchupCommitRound != -1 && 0 < prs.Height && prs.Height <= pc.myState.client.csStore.LoadStateHeight() {
commit := pc.myState.LoadCommit(prs.Height) commit := pc.myState.LoadCommit(prs.Height)
commitTmp := ttypes.Commit{TendermintCommit: commit} commitTmp := ttypes.Commit{TendermintCommit: commit}
msg := MsgInfo{TypeID: ttypes.VoteSetMaj23ID, Msg: &tmtypes.VoteSetMaj23Msg{ msg := MsgInfo{TypeID: ttypes.VoteSetMaj23ID, Msg: &tmtypes.VoteSetMaj23Msg{
...@@ -1036,10 +1047,12 @@ func (ps *PeerConnState) SetHasProposal(proposal *tmtypes.Proposal) { ...@@ -1036,10 +1047,12 @@ func (ps *PeerConnState) SetHasProposal(proposal *tmtypes.Proposal) {
if ps.Proposal { if ps.Proposal {
return return
} }
tendermintlog.Debug("Peer set proposal", "peerip", ps.ip.String(), "peer-state", fmt.Sprintf("%v/%v/%v", ps.Height, ps.Round, ps.Step), tendermintlog.Debug("Peer set proposal", "peerip", ps.ip.String(),
"proposal(H/R)", fmt.Sprintf("%v/%v", proposal.Height, proposal.Round)) "peer-state", fmt.Sprintf("%v/%v/%v", ps.Height, ps.Round, ps.Step),
"proposal(H/R/Hash)", fmt.Sprintf("%v/%v/%X", proposal.Height, proposal.Round, proposal.Blockhash))
ps.Proposal = true ps.Proposal = true
ps.ProposalBlockHash = proposal.Blockhash
ps.ProposalPOLRound = int(proposal.POLRound) ps.ProposalPOLRound = int(proposal.POLRound)
ps.ProposalPOL = nil // Nil until ttypes.ProposalPOLMessage received. ps.ProposalPOL = nil // Nil until ttypes.ProposalPOLMessage received.
} }
...@@ -1055,7 +1068,8 @@ func (ps *PeerConnState) SetHasProposalBlock(block *ttypes.TendermintBlock) { ...@@ -1055,7 +1068,8 @@ func (ps *PeerConnState) SetHasProposalBlock(block *ttypes.TendermintBlock) {
if ps.ProposalBlock { if ps.ProposalBlock {
return return
} }
tendermintlog.Debug("Peer set proposal block", "peerip", ps.ip.String(), "peer-state", fmt.Sprintf("%v/%v/%v", ps.Height, ps.Round, ps.Step), tendermintlog.Debug("Peer set proposal block", "peerip", ps.ip.String(),
"peer-state", fmt.Sprintf("%v/%v/%v", ps.Height, ps.Round, ps.Step),
"block(H/R)", fmt.Sprintf("%v/%v", block.Header.Height, block.Header.Round)) "block(H/R)", fmt.Sprintf("%v/%v", block.Header.Height, block.Header.Round))
ps.ProposalBlock = true ps.ProposalBlock = true
} }
...@@ -1088,7 +1102,6 @@ func (ps *PeerConnState) PickVoteToSend(votes ttypes.VoteSetReader) (vote *ttype ...@@ -1088,7 +1102,6 @@ func (ps *PeerConnState) PickVoteToSend(votes ttypes.VoteSetReader) (vote *ttype
tendermintlog.Debug("PickVoteToSend", "peer(H/R)", fmt.Sprintf("%v/%v", ps.Height, ps.Round), tendermintlog.Debug("PickVoteToSend", "peer(H/R)", fmt.Sprintf("%v/%v", ps.Height, ps.Round),
"vote(H/R)", fmt.Sprintf("%v/%v", height, round), "type", voteType, "selfVotes", votes.BitArray().String(), "vote(H/R)", fmt.Sprintf("%v/%v", height, round), "type", voteType, "selfVotes", votes.BitArray().String(),
"peerVotes", psVotes.String(), "peerip", ps.ip.String()) "peerVotes", psVotes.String(), "peerip", ps.ip.String())
ps.setHasVote(height, round, voteType, index)
return votes.GetByIndex(index), true return votes.GetByIndex(index), true
} }
return nil, false return nil, false
...@@ -1211,7 +1224,8 @@ func (ps *PeerConnState) setHasVote(height int64, round int, voteType byte, inde ...@@ -1211,7 +1224,8 @@ func (ps *PeerConnState) setHasVote(height int64, round int, voteType byte, inde
if psVotes != nil { if psVotes != nil {
psVotes.SetIndex(index, true) psVotes.SetIndex(index, true)
} }
tendermintlog.Debug("setHasVote after", "height", height, "index", index, "type", voteType, "peerVotes", psVotes.String(), "peerip", ps.ip.String()) tendermintlog.Debug("setHasVote after", "height", height, "index", index, "type", voteType,
"peerVotes", psVotes.String(), "peerip", ps.ip.String())
} }
// ApplyNewRoundStepMessage updates the peer state for the new round. // ApplyNewRoundStepMessage updates the peer state for the new round.
...@@ -1238,13 +1252,16 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg) ...@@ -1238,13 +1252,16 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg)
ps.Step = ttypes.RoundStepType(msg.Step) ps.Step = ttypes.RoundStepType(msg.Step)
ps.StartTime = startTime ps.StartTime = startTime
tendermintlog.Debug("ApplyNewRoundStepMessage", "peerip", ps.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound), tendermintlog.Debug("ApplyNewRoundStepMessage", "peerip", ps.ip.String(),
"peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound),
"msg(H/R/S)", fmt.Sprintf("%v/%v/%v", msg.Height, msg.Round, ps.Step)) "msg(H/R/S)", fmt.Sprintf("%v/%v/%v", msg.Height, msg.Round, ps.Step))
if psHeight != msg.Height || psRound != int(msg.Round) { if psHeight != msg.Height || psRound != int(msg.Round) {
tendermintlog.Debug("Reset Proposal, Prevotes, Precommits", "peerip", ps.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound)) tendermintlog.Debug("Reset Proposal, Prevotes, Precommits", "peerip", ps.ip.String(),
"peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound))
ps.Proposal = false ps.Proposal = false
ps.ProposalBlock = false ps.ProposalBlock = false
ps.ProposalBlockHash = nil
ps.ProposalPOLRound = -1 ps.ProposalPOLRound = -1
ps.ProposalPOL = nil ps.ProposalPOL = nil
// We'll update the BitArray capacity later. // We'll update the BitArray capacity later.
...@@ -1256,11 +1273,13 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg) ...@@ -1256,11 +1273,13 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg)
// Preserve psCatchupCommit! // Preserve psCatchupCommit!
// NOTE: We prefer to use prs.Precommits if // NOTE: We prefer to use prs.Precommits if
// pr.Round matches pr.CatchupCommitRound. // pr.Round matches pr.CatchupCommitRound.
tendermintlog.Debug("Reset Precommits to CatchupCommit", "peerip", ps.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound)) tendermintlog.Debug("Reset Precommits to CatchupCommit", "peerip", ps.ip.String(),
"peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound))
ps.Precommits = psCatchupCommit ps.Precommits = psCatchupCommit
} }
if psHeight != msg.Height { if psHeight != msg.Height {
tendermintlog.Debug("Reset LastCommit, CatchupCommit", "peerip", ps.ip.String(), "peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound)) tendermintlog.Debug("Reset LastCommit, CatchupCommit", "peerip", ps.ip.String(),
"peer(H/R)", fmt.Sprintf("%v/%v", psHeight, psRound))
// Shift Precommits to LastCommit. // Shift Precommits to LastCommit.
if psHeight+1 == msg.Height && psRound == int(msg.LastCommitRound) { if psHeight+1 == msg.Height && psRound == int(msg.LastCommitRound) {
ps.LastCommitRound = int(msg.LastCommitRound) ps.LastCommitRound = int(msg.LastCommitRound)
...@@ -1283,7 +1302,24 @@ func (ps *PeerConnState) ApplyCommitStepMessage(msg *tmtypes.CommitStepMsg) { ...@@ -1283,7 +1302,24 @@ func (ps *PeerConnState) ApplyCommitStepMessage(msg *tmtypes.CommitStepMsg) {
if ps.Height != msg.Height { if ps.Height != msg.Height {
return return
} }
}
// ApplyValidBlockMessage updates the peer state for the new valid block.
func (ps *PeerConnState) ApplyValidBlockMessage(msg *tmtypes.ValidBlockMsg) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
if ps.Height != msg.Height {
return
}
if ps.Round != int(msg.Round) && !msg.IsCommit {
return
}
tendermintlog.Debug("ApplyValidBlockMessage", "peerip", ps.ip.String(),
"peer(H/R)", fmt.Sprintf("%v/%v", ps.Height, ps.Round),
"blockhash", fmt.Sprintf("%X", msg.Blockhash))
ps.ProposalBlockHash = msg.Blockhash
} }
// ApplyProposalPOLMessage updates the peer state for the new proposal POL. // ApplyProposalPOLMessage updates the peer state for the new proposal POL.
...@@ -1312,7 +1348,8 @@ func (ps *PeerConnState) ApplyHasVoteMessage(msg *tmtypes.HasVoteMsg) { ...@@ -1312,7 +1348,8 @@ func (ps *PeerConnState) ApplyHasVoteMessage(msg *tmtypes.HasVoteMsg) {
return return
} }
tendermintlog.Debug("ApplyHasVoteMessage", "msg(H/R)", fmt.Sprintf("%v/%v", msg.Height, msg.Round), "peerip", ps.ip.String()) tendermintlog.Debug("ApplyHasVoteMessage", "msg(H/R)", fmt.Sprintf("%v/%v", msg.Height, msg.Round),
"peerip", ps.ip.String())
ps.setHasVote(msg.Height, int(msg.Round), byte(msg.Type), int(msg.Index)) ps.setHasVote(msg.Height, int(msg.Round), byte(msg.Type), int(msg.Index))
} }
......
...@@ -133,7 +133,6 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) { ...@@ -133,7 +133,6 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) {
// encrypt the frame // encrypt the frame
var sealedFrame = make([]byte, sealedFrameSize) var sealedFrame = make([]byte, sealedFrameSize)
secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret) secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
// fmt.Printf("secretbox.Seal(sealed:%X,sendNonce:%X,shrSecret:%X\n", sealedFrame, sc.sendNonce, sc.shrSecret)
incr2Nonce(sc.sendNonce) incr2Nonce(sc.sendNonce)
// end encryption // end encryption
...@@ -162,7 +161,6 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) { ...@@ -162,7 +161,6 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
// decrypt the frame // decrypt the frame
var frame = make([]byte, totalFrameSize) var frame = make([]byte, totalFrameSize)
// fmt.Printf("secretbox.Open(sealed:%X,recvNonce:%X,shrSecret:%X\n", sealedFrame, sc.recvNonce, sc.shrSecret)
_, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret) _, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret)
if !ok { if !ok {
return n, errors.New("Failed to decrypt SecretConnection") return n, errors.New("Failed to decrypt SecretConnection")
...@@ -298,9 +296,7 @@ func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto ...@@ -298,9 +296,7 @@ func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto
if err2 != nil { if err2 != nil {
return return
} }
//n := int(0) // not used.
//recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), authSigMsgSize, &n, &err2).(authSigMessage)
//secret.Info("shareAuthSignature", "readBuffer", readBuffer)
recvMsg.Key, err2 = types.ConsensusCrypto.PubKeyFromBytes(readBuffer[:32]) recvMsg.Key, err2 = types.ConsensusCrypto.PubKeyFromBytes(readBuffer[:32])
if err2 != nil { if err2 != nil {
return return
......
...@@ -118,9 +118,9 @@ func (s State) GetValidators() (last *ttypes.ValidatorSet, current *ttypes.Valid ...@@ -118,9 +118,9 @@ func (s State) GetValidators() (last *ttypes.ValidatorSet, current *ttypes.Valid
// Create a block from the latest state // Create a block from the latest state
// MakeBlock builds a block with the given txs and commit from the current state. // MakeBlock builds a block with the given txs and commit from the current state.
func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, commit *tmtypes.TendermintCommit) *ttypes.TendermintBlock { func (s State) MakeBlock(height int64, round int64, pblock *types.Block, commit *tmtypes.TendermintCommit, proposerAddr []byte) *ttypes.TendermintBlock {
// build base block // build base block
block := ttypes.MakeBlock(height, round, Txs, commit) block := ttypes.MakeBlock(height, round, pblock, commit)
// fill header with state data // fill header with state data
block.Header.ChainID = s.ChainID block.Header.ChainID = s.ChainID
...@@ -130,6 +130,7 @@ func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, co ...@@ -130,6 +130,7 @@ func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, co
block.Header.AppHash = s.AppHash block.Header.AppHash = s.AppHash
block.Header.ConsensusHash = s.ConsensusParams.Hash() block.Header.ConsensusHash = s.ConsensusParams.Hash()
block.Header.LastResultsHash = s.LastResultsHash block.Header.LastResultsHash = s.LastResultsHash
block.Header.ProposerAddr = proposerAddr
return block return block
} }
...@@ -226,6 +227,7 @@ func LoadState(state *tmtypes.State) State { ...@@ -226,6 +227,7 @@ func LoadState(state *tmtypes.State) State {
ChainID: state.GetChainID(), ChainID: state.GetChainID(),
LastBlockHeight: state.GetLastBlockHeight(), LastBlockHeight: state.GetLastBlockHeight(),
LastBlockTotalTx: state.GetLastBlockTotalTx(), LastBlockTotalTx: state.GetLastBlockTotalTx(),
LastBlockID: ttypes.BlockID{BlockID: *state.LastBlockID},
LastBlockTime: state.LastBlockTime, LastBlockTime: state.LastBlockTime,
Validators: nil, Validators: nil,
LastValidators: nil, LastValidators: nil,
...@@ -307,7 +309,7 @@ func (csdb *CSStateDB) LoadValidators(height int64) (*ttypes.ValidatorSet, error ...@@ -307,7 +309,7 @@ func (csdb *CSStateDB) LoadValidators(height int64) (*ttypes.ValidatorSet, error
if height == 0 { if height == 0 {
return nil, nil return nil, nil
} }
if csdb.state.LastBlockHeight+1 == height { if csdb.state.LastBlockHeight == height {
return csdb.state.Validators, nil return csdb.state.Validators, nil
} }
...@@ -374,6 +376,7 @@ func SaveState(state State) *tmtypes.State { ...@@ -374,6 +376,7 @@ func SaveState(state State) *tmtypes.State {
ChainID: state.ChainID, ChainID: state.ChainID,
LastBlockHeight: state.LastBlockHeight, LastBlockHeight: state.LastBlockHeight,
LastBlockTotalTx: state.LastBlockTotalTx, LastBlockTotalTx: state.LastBlockTotalTx,
LastBlockID: &state.LastBlockID.BlockID,
LastBlockTime: state.LastBlockTime, LastBlockTime: state.LastBlockTime,
Validators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}}, Validators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}},
LastValidators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}}, LastValidators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}},
...@@ -458,17 +461,14 @@ func LoadProposer(source *tmtypes.Validator) (*ttypes.Validator, error) { ...@@ -458,17 +461,14 @@ func LoadProposer(source *tmtypes.Validator) (*ttypes.Validator, error) {
} }
// CreateBlockInfoTx make blockInfo to the first transaction of the block and execer is valnode // CreateBlockInfoTx make blockInfo to the first transaction of the block and execer is valnode
func CreateBlockInfoTx(pubkey string, lastCommit *tmtypes.TendermintCommit, seenCommit *tmtypes.TendermintCommit, state *tmtypes.State, proposal *tmtypes.Proposal, block *tmtypes.TendermintBlock) *types.Transaction { func CreateBlockInfoTx(pubkey string, state *tmtypes.State, block *tmtypes.TendermintBlock) *types.Transaction {
blockNoTxs := *block blockSave := *block
blockNoTxs.Txs = make([]*types.Transaction, 0) blockSave.Data = nil
blockInfo := &tmtypes.TendermintBlockInfo{ blockInfo := &tmtypes.TendermintBlockInfo{
SeenCommit: seenCommit, State: state,
LastCommit: lastCommit, Block: &blockSave,
State: state,
Proposal: proposal,
Block: &blockNoTxs,
} }
tendermintlog.Debug("CreateBlockInfoTx", "validators", blockInfo.State.Validators.Validators, "block", block, "block-notxs", blockNoTxs) tendermintlog.Debug("CreateBlockInfoTx", "blockInfo", blockInfo)
nput := &tmtypes.ValNodeAction_BlockInfo{BlockInfo: blockInfo} nput := &tmtypes.ValNodeAction_BlockInfo{BlockInfo: blockInfo}
action := &tmtypes.ValNodeAction{Value: nput, Ty: tmtypes.ValNodeActionBlockInfo} action := &tmtypes.ValNodeAction{Value: nput, Ty: tmtypes.ValNodeActionBlockInfo}
......
package tendermint
import (
"fmt"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/gogo/protobuf/proto"
)
var (
stateKey = []byte("stateKey")
)
type ConsensusStore struct {
db dbm.DB
}
// NewConsensusStore returns a new ConsensusStore with the given DB
func NewConsensusStore() *ConsensusStore {
db := DefaultDBProvider("state")
db.SetCacheSize(100)
return &ConsensusStore{
db: db,
}
}
// LoadStateFromStore
func (cs *ConsensusStore) LoadStateFromStore() *tmtypes.State {
buf, err := cs.db.Get(stateKey)
if err != nil {
tendermintlog.Error("LoadStateFromStore", "err", err)
return nil
}
state := &tmtypes.State{}
err = types.Decode(buf, state)
if err != nil {
panic(err)
}
return state
}
// LoadStateHeight
func (cs *ConsensusStore) LoadStateHeight() int64 {
state := cs.LoadStateFromStore()
if state == nil {
return int64(0)
}
return state.LastBlockHeight
}
// LoadSeenCommit by height
func (cs *ConsensusStore) LoadSeenCommit(height int64) *tmtypes.TendermintCommit {
buf, err := cs.db.Get(calcSeenCommitKey(height))
if err != nil {
tendermintlog.Error("LoadSeenCommit", "err", err)
return nil
}
commit := &tmtypes.TendermintCommit{}
err = types.Decode(buf, commit)
if err != nil {
panic(err)
}
return commit
}
// SaveConsensusState save state and seenCommit
func (cs *ConsensusStore) SaveConsensusState(height int64, state *tmtypes.State, sc proto.Message) error {
seenCommitBytes := types.Encode(sc)
stateBytes := types.Encode(state)
batch := cs.db.NewBatch(true)
batch.Set(calcSeenCommitKey(height), seenCommitBytes)
batch.Set(stateKey, stateBytes)
err := batch.Write()
if err != nil {
tendermintlog.Error("SaveConsensusState batch.Write", "err", err)
return err
}
return nil
}
func calcSeenCommitKey(height int64) []byte {
return []byte(fmt.Sprintf("SC:%v", height))
}
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
package tendermint package tendermint
import ( import (
"bytes"
"fmt" "fmt"
"os"
"time" "time"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
...@@ -38,6 +40,7 @@ var ( ...@@ -38,6 +40,7 @@ var (
timeoutCommit int32 = 1000 timeoutCommit int32 = 1000
skipTimeoutCommit = false skipTimeoutCommit = false
createEmptyBlocks = false createEmptyBlocks = false
fastSync = false
createEmptyBlocksInterval int32 // second createEmptyBlocksInterval int32 // second
validatorNodes = []string{"127.0.0.1:46656"} validatorNodes = []string{"127.0.0.1:46656"}
peerGossipSleepDuration int32 = 100 peerGossipSleepDuration int32 = 100
...@@ -59,6 +62,7 @@ type Client struct { ...@@ -59,6 +62,7 @@ type Client struct {
privKey crypto.PrivKey // local node's p2p key privKey crypto.PrivKey // local node's p2p key
pubKey string pubKey string
csState *ConsensusState csState *ConsensusState
csStore *ConsensusStore // save consensus state
evidenceDB dbm.DB evidenceDB dbm.DB
crypto crypto.Crypto crypto crypto.Crypto
node *Node node *Node
...@@ -81,6 +85,7 @@ type subConfig struct { ...@@ -81,6 +85,7 @@ type subConfig struct {
CreateEmptyBlocks bool `json:"createEmptyBlocks"` CreateEmptyBlocks bool `json:"createEmptyBlocks"`
CreateEmptyBlocksInterval int32 `json:"createEmptyBlocksInterval"` CreateEmptyBlocksInterval int32 `json:"createEmptyBlocksInterval"`
ValidatorNodes []string `json:"validatorNodes"` ValidatorNodes []string `json:"validatorNodes"`
FastSync bool `json:"fastSync"`
} }
func (client *Client) applyConfig(sub []byte) { func (client *Client) applyConfig(sub []byte) {
...@@ -126,12 +131,13 @@ func (client *Client) applyConfig(sub []byte) { ...@@ -126,12 +131,13 @@ func (client *Client) applyConfig(sub []byte) {
if len(subcfg.ValidatorNodes) > 0 { if len(subcfg.ValidatorNodes) > 0 {
validatorNodes = subcfg.ValidatorNodes validatorNodes = subcfg.ValidatorNodes
} }
fastSync = subcfg.FastSync
} }
// DefaultDBProvider returns a database using the DBBackend and DBDir // DefaultDBProvider returns a database using the DBBackend and DBDir
// specified in the ctx.Config. // specified in the ctx.Config.
func DefaultDBProvider(ID string) (dbm.DB, error) { func DefaultDBProvider(name string) dbm.DB {
return dbm.NewDB(ID, "leveldb", "./datadir", 0), nil return dbm.NewDB(name, "leveldb", fmt.Sprintf("datadir%stendermint", string(os.PathSeparator)), 0)
} }
// New ... // New ...
...@@ -140,18 +146,14 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -140,18 +146,14 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
//init rand //init rand
ttypes.Init() ttypes.Init()
genDoc, err := ttypes.GenesisDocFromFile("./genesis.json") genDoc, err := ttypes.GenesisDocFromFile("genesis.json")
if err != nil { if err != nil {
tendermintlog.Error("NewTendermintClient", "msg", "GenesisDocFromFile failded", "error", err) tendermintlog.Error("NewTendermintClient", "msg", "GenesisDocFromFile failded", "error", err)
return nil return nil
} }
// Make Evidence Reactor // Make Evidence Reactor
evidenceDB, err := DefaultDBProvider("CSevidence") evidenceDB := DefaultDBProvider("evidence")
if err != nil {
tendermintlog.Error("NewTendermintClient", "msg", "DefaultDBProvider evidenceDB failded", "error", err)
return nil
}
cr, err := crypto.New(types.GetSignName("", types.ED25519)) cr, err := crypto.New(types.GetSignName("", types.ED25519))
if err != nil { if err != nil {
...@@ -167,7 +169,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -167,7 +169,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
return nil return nil
} }
privValidator := ttypes.LoadOrGenPrivValidatorFS("./priv_validator.json") privValidator := ttypes.LoadOrGenPrivValidatorFS("priv_validator.json")
if privValidator == nil { if privValidator == nil {
tendermintlog.Error("NewTendermintClient create priv_validator file failed") tendermintlog.Error("NewTendermintClient create priv_validator file failed")
return nil return nil
...@@ -183,6 +185,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -183,6 +185,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
privValidator: privValidator, privValidator: privValidator,
privKey: priv, privKey: priv,
pubKey: pubkey, pubKey: pubkey,
csStore: NewConsensusStore(),
evidenceDB: evidenceDB, evidenceDB: evidenceDB,
crypto: cr, crypto: cr,
txsAvailable: make(chan int64, 1), txsAvailable: make(chan int64, 1),
...@@ -223,16 +226,13 @@ func (client *Client) SetQueueClient(q queue.Client) { ...@@ -223,16 +226,13 @@ func (client *Client) SetQueueClient(q queue.Client) {
go client.StartConsensus() go client.StartConsensus()
} }
// DebugCatchup define whether catch up now
const DebugCatchup = false
// StartConsensus a routine that make the consensus start // StartConsensus a routine that make the consensus start
func (client *Client) StartConsensus() { func (client *Client) StartConsensus() {
//进入共识前先同步到最大高度 //进入共识前先同步到最大高度
hint := time.NewTicker(5 * time.Second) hint := time.NewTicker(5 * time.Second)
beg := time.Now() beg := time.Now()
OuterLoop: OuterLoop:
for !DebugCatchup { for fastSync {
select { select {
case <-hint.C: case <-hint.C:
tendermintlog.Info("Still catching up max height......", "Height", client.GetCurrentHeight(), "cost", time.Since(beg)) tendermintlog.Info("Still catching up max height......", "Height", client.GetCurrentHeight(), "cost", time.Since(beg))
...@@ -246,60 +246,46 @@ OuterLoop: ...@@ -246,60 +246,46 @@ OuterLoop:
} }
hint.Stop() hint.Stop()
curHeight := client.GetCurrentHeight() // load state
blockInfo, err := client.QueryBlockInfoByHeight(curHeight)
if curHeight != 0 && err != nil {
tendermintlog.Error("StartConsensus GetBlockInfo failed", "error", err)
panic(fmt.Sprintf("StartConsensus GetBlockInfo failed:%v", err))
}
var state State var state State
if blockInfo == nil { if client.GetCurrentHeight() == 0 {
if curHeight != 0 { genState, err := MakeGenesisState(client.genesisDoc)
tendermintlog.Error("StartConsensus", "msg", "block height is not 0 but blockinfo is nil")
panic(fmt.Sprintf("StartConsensus block height is %v but block info is nil", curHeight))
}
statetmp, err := MakeGenesisState(client.genesisDoc)
if err != nil { if err != nil {
tendermintlog.Error("StartConsensus", "msg", "MakeGenesisState failded", "error", err) panic(fmt.Sprintf("StartConsensus MakeGenesisState fail:%v", err))
return
} }
state = statetmp.Copy() state = genState.Copy()
} else if client.GetCurrentHeight() <= client.csStore.LoadStateHeight() {
stoState := client.csStore.LoadStateFromStore()
if stoState == nil {
panic("StartConsensus LoadStateFromStore fail")
}
state = LoadState(stoState)
tendermintlog.Info("Load state from store")
} else { } else {
tendermintlog.Debug("StartConsensus", "blockinfo", blockInfo) height := client.GetCurrentHeight()
csState := blockInfo.GetState() blkState := client.LoadBlockState(height)
if csState == nil { if blkState == nil {
tendermintlog.Error("StartConsensus", "msg", "blockInfo.GetState is nil") panic("StartConsensus LoadBlockState fail")
return
} }
state = LoadState(csState) state = LoadState(blkState)
if seenCommit := blockInfo.SeenCommit; seenCommit != nil { tendermintlog.Info("Load state from block")
state.LastBlockID = ttypes.BlockID{ //save initial state in store
BlockID: tmtypes.BlockID{ blkCommit := client.LoadBlockCommit(height)
Hash: seenCommit.BlockID.GetHash(), if blkCommit == nil {
}, panic("StartConsensus LoadBlockCommit fail")
}
} }
} err := client.csStore.SaveConsensusState(height-1, blkState, blkCommit)
if err != nil {
tendermintlog.Debug("Load state finish", "state", state) panic(fmt.Sprintf("StartConsensus SaveConsensusState fail: %v", err))
valNodes, err := client.QueryValidatorsByHeight(curHeight)
if err == nil && valNodes != nil {
if len(valNodes.Nodes) > 0 {
tendermintlog.Info("StartConsensus validators update", "update-valnodes", valNodes)
prevValSet := state.LastValidators.Copy()
nextValSet := prevValSet.Copy()
err := updateValidators(nextValSet, valNodes.Nodes)
if err != nil {
tendermintlog.Error("Error changing validator set", "error", err)
}
// change results from this height but only applies to the next height
state.LastHeightValidatorsChanged = curHeight + 1
nextValSet.IncrementAccum(1)
state.Validators = nextValSet
} }
tendermintlog.Info("Save state from block")
} }
tendermintlog.Info("StartConsensus", "validators", state.Validators) tendermintlog.Debug("Load state finish", "state", state)
// start
tendermintlog.Info("StartConsensus",
"privValidator", fmt.Sprintf("%X", ttypes.Fingerprint(client.privValidator.GetAddress())),
"Validators", state.Validators.String())
// Log whether this node is a validator or an observer // Log whether this node is a validator or an observer
if state.Validators.HasAddress(client.privValidator.GetAddress()) { if state.Validators.HasAddress(client.privValidator.GetAddress()) {
tendermintlog.Info("This node is a validator") tendermintlog.Info("This node is a validator")
...@@ -309,15 +295,11 @@ OuterLoop: ...@@ -309,15 +295,11 @@ OuterLoop:
stateDB := NewStateDB(client, state) stateDB := NewStateDB(client, state)
//make evidenceReactor
evidenceStore := NewEvidenceStore(client.evidenceDB)
evidencePool := NewEvidencePool(stateDB, state, evidenceStore)
// make block executor for consensus and blockchain reactors to execute blocks // make block executor for consensus and blockchain reactors to execute blocks
blockExec := NewBlockExecutor(stateDB, evidencePool) blockExec := NewBlockExecutor(stateDB)
// Make ConsensusReactor // Make ConsensusReactor
csState := NewConsensusState(client, state, blockExec, evidencePool) csState := NewConsensusState(client, state, blockExec)
// reset height, round, state begin at newheigt,0,0 // reset height, round, state begin at newheigt,0,0
client.privValidator.ResetLastHeight(state.LastBlockHeight) client.privValidator.ResetLastHeight(state.LastBlockHeight)
csState.SetPrivValidator(client.privValidator) csState.SetPrivValidator(client.privValidator)
...@@ -326,7 +308,7 @@ OuterLoop: ...@@ -326,7 +308,7 @@ OuterLoop:
// Create & add listener // Create & add listener
protocol, listeningAddress := "tcp", "0.0.0.0:46656" protocol, listeningAddress := "tcp", "0.0.0.0:46656"
node := NewNode(validatorNodes, protocol, listeningAddress, client.privKey, state.ChainID, tendermintVersion, csState, evidencePool) node := NewNode(validatorNodes, protocol, listeningAddress, client.privKey, state.ChainID, tendermintVersion, csState)
client.node = node client.node = node
node.Start() node.Start()
...@@ -353,8 +335,56 @@ func (client *Client) CreateGenesisTx() (ret []*types.Transaction) { ...@@ -353,8 +335,56 @@ func (client *Client) CreateGenesisTx() (ret []*types.Transaction) {
return return
} }
// CheckBlock 暂不检查任何的交易 func (client *Client) getBlockInfoTx(current *types.Block) (*tmtypes.ValNodeAction, error) {
//检查第一个笔交易的execs, 以及执行状态
if len(current.Txs) == 0 {
return nil, types.ErrEmptyTx
}
baseTx := current.Txs[0]
//判断交易类型和执行情况
var valAction tmtypes.ValNodeAction
err := types.Decode(baseTx.GetPayload(), &valAction)
if err != nil {
return nil, err
}
if valAction.GetTy() != tmtypes.ValNodeActionBlockInfo {
return nil, ttypes.ErrBaseTxType
}
//判断交易执行是否OK
if valAction.GetBlockInfo() == nil {
return nil, ttypes.ErrBlockInfoTx
}
return &valAction, nil
}
// CheckBlock 检查区块
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error { func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
if current.Block.Difficulty != types.GetP(0).PowLimitBits {
return types.ErrBlockHeaderDifficulty
}
valAction, err := client.getBlockInfoTx(current.Block)
if err != nil {
return err
}
if parent.Height+1 != current.Block.Height {
return types.ErrBlockHeight
}
//判断exec 是否成功
if current.Receipts[0].Ty != types.ExecOk {
return ttypes.ErrBaseExecErr
}
info := valAction.GetBlockInfo()
if current.Block.Height > 1 {
lastValAction, err := client.getBlockInfoTx(parent)
if err != nil {
return err
}
lastInfo := lastValAction.GetBlockInfo()
lastProposalBlock := &ttypes.TendermintBlock{TendermintBlock: lastInfo.GetBlock()}
if !lastProposalBlock.HashesTo(info.Block.Header.LastBlockID.Hash) {
return ttypes.ErrLastBlockID
}
}
return nil return nil
} }
...@@ -377,17 +407,30 @@ func (client *Client) CreateBlock() { ...@@ -377,17 +407,30 @@ func (client *Client) CreateBlock() {
if issleep { if issleep {
time.Sleep(time.Second) time.Sleep(time.Second)
} }
if !client.CheckTxsAvailable() { height, err := client.getLastHeight()
if err != nil {
issleep = true
continue
}
if !client.CheckTxsAvailable(height) {
issleep = true issleep = true
continue continue
} }
issleep = false issleep = false
client.txsAvailable <- client.GetCurrentHeight() + 1 client.txsAvailable <- height + 1
time.Sleep(time.Duration(timeoutTxAvail) * time.Millisecond) time.Sleep(time.Duration(timeoutTxAvail) * time.Millisecond)
} }
} }
func (client *Client) getLastHeight() (int64, error) {
lastBlock, err := client.RequestLastBlock()
if err != nil {
return -1, err
}
return lastBlock.Height, nil
}
// TxsAvailable check available channel // TxsAvailable check available channel
func (client *Client) TxsAvailable() <-chan int64 { func (client *Client) TxsAvailable() <-chan int64 {
return client.txsAvailable return client.txsAvailable
...@@ -399,9 +442,9 @@ func (client *Client) StopC() <-chan struct{} { ...@@ -399,9 +442,9 @@ func (client *Client) StopC() <-chan struct{} {
} }
// CheckTxsAvailable check whether some new transactions arriving // CheckTxsAvailable check whether some new transactions arriving
func (client *Client) CheckTxsAvailable() bool { func (client *Client) CheckTxsAvailable(height int64) bool {
txs := client.RequestTx(10, nil) txs := client.RequestTx(10, nil)
txs = client.CheckTxDup(txs, client.GetCurrentHeight()) txs = client.CheckTxDup(txs, height)
return len(txs) != 0 return len(txs) != 0
} }
...@@ -416,58 +459,64 @@ func (client *Client) CheckTxDup(txs []*types.Transaction, height int64) (transa ...@@ -416,58 +459,64 @@ func (client *Client) CheckTxDup(txs []*types.Transaction, height int64) (transa
return types.CacheToTxs(cacheTxs) return types.CacheToTxs(cacheTxs)
} }
// BuildBlock build a new block contains some transactions // BuildBlock build a new block
func (client *Client) BuildBlock() *types.Block { func (client *Client) BuildBlock() *types.Block {
lastHeight := client.GetCurrentHeight() lastBlock := client.GetCurrentBlock()
txs := client.RequestTx(int(types.GetP(lastHeight+1).MaxTxNumber)-1, nil) txs := client.RequestTx(int(types.GetP(lastBlock.Height+1).MaxTxNumber)-1, nil)
newblock := &types.Block{} // placeholder
newblock.Height = lastHeight + 1 tx0 := &types.Transaction{}
client.AddTxsToBlock(newblock, txs) txs = append([]*types.Transaction{tx0}, txs...)
return newblock
} var newblock types.Block
// CommitBlock call WriteBlock to real commit to chain
func (client *Client) CommitBlock(propBlock *types.Block) error {
newblock := *propBlock
lastBlock, err := client.RequestBlock(newblock.Height - 1)
if err != nil {
tendermintlog.Error("RequestBlock fail", "err", err)
return err
}
newblock.ParentHash = lastBlock.Hash() newblock.ParentHash = lastBlock.Hash()
newblock.TxHash = merkle.CalcMerkleRoot(newblock.Txs) newblock.Height = lastBlock.Height + 1
newblock.BlockTime = time.Now().Unix() client.AddTxsToBlock(&newblock, txs)
//固定难度
newblock.Difficulty = types.GetP(0).PowLimitBits
//newblock.TxHash = merkle.CalcMerkleRoot(newblock.Txs)
newblock.BlockTime = types.Now().Unix()
if lastBlock.BlockTime >= newblock.BlockTime { if lastBlock.BlockTime >= newblock.BlockTime {
newblock.BlockTime = lastBlock.BlockTime + 1 newblock.BlockTime = lastBlock.BlockTime + 1
} }
newblock.Difficulty = types.GetP(0).PowLimitBits return &newblock
}
err = client.WriteBlock(lastBlock.StateHash, &newblock) // CommitBlock call WriteBlock to commit to chain
if err != nil { func (client *Client) CommitBlock(block *types.Block) error {
tendermintlog.Error(fmt.Sprintf("********************CommitBlock err:%v", err.Error())) retErr := client.WriteBlock(nil, block)
return err if retErr != nil {
} tendermintlog.Info("CommitBlock fail", "err", retErr)
tendermintlog.Info("Commit block success", "height", newblock.Height, "CurrentHeight", client.GetCurrentHeight()) if client.WaitBlock(block.Height) {
if client.GetCurrentHeight() != newblock.Height { curBlock, err := client.RequestBlock(block.Height)
tendermintlog.Warn("Commit block fail", "height", newblock.Height, "CurrentHeight", client.GetCurrentHeight()) if err == nil {
if bytes.Equal(curBlock.Hash(), block.Hash()) {
tendermintlog.Info("already has block")
return nil
}
tendermintlog.Info("block is different", "block", block, "curBlock", curBlock)
if bytes.Equal(curBlock.Txs[0].Hash(), block.Txs[0].Hash()) {
tendermintlog.Warn("base tx is same, origin maybe same")
return nil
}
}
}
return retErr
} }
return nil return nil
} }
// CheckCommit by height // WaitBlock by height
func (client *Client) CheckCommit(height int64) bool { func (client *Client) WaitBlock(height int64) bool {
retry := 0 retry := 0
var newHeight int64
for { for {
newHeight = client.GetCurrentHeight() newHeight, err := client.getLastHeight()
if newHeight >= height { if err == nil && newHeight >= height {
tendermintlog.Info("Sync block success", "height", height, "CurrentHeight", newHeight)
return true return true
} }
retry++ retry++
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
if retry >= 600 { if retry >= 100 {
tendermintlog.Warn("Sync block fail", "height", height, "CurrentHeight", newHeight) tendermintlog.Warn("Wait block fail", "height", height, "CurrentHeight", newHeight)
return false return false
} }
} }
...@@ -493,6 +542,7 @@ func (client *Client) QueryValidatorsByHeight(height int64) (*tmtypes.ValNodes, ...@@ -493,6 +542,7 @@ func (client *Client) QueryValidatorsByHeight(height int64) (*tmtypes.ValNodes,
} }
msg, err = client.GetQueueClient().Wait(msg) msg, err = client.GetQueueClient().Wait(msg)
if err != nil { if err != nil {
tendermintlog.Info("QueryValidatorsByHeight result", "err", err)
return nil, err return nil, err
} }
return msg.GetData().(types.Message).(*tmtypes.ValNodes), nil return msg.GetData().(types.Message).(*tmtypes.ValNodes), nil
...@@ -523,30 +573,32 @@ func (client *Client) QueryBlockInfoByHeight(height int64) (*tmtypes.TendermintB ...@@ -523,30 +573,32 @@ func (client *Client) QueryBlockInfoByHeight(height int64) (*tmtypes.TendermintB
return msg.GetData().(types.Message).(*tmtypes.TendermintBlockInfo), nil return msg.GetData().(types.Message).(*tmtypes.TendermintBlockInfo), nil
} }
// LoadSeenCommit by height // LoadBlockCommit by height
func (client *Client) LoadSeenCommit(height int64) *tmtypes.TendermintCommit { func (client *Client) LoadBlockCommit(height int64) *tmtypes.TendermintCommit {
blockInfo, err := client.QueryBlockInfoByHeight(height) blockInfo, err := client.QueryBlockInfoByHeight(height)
if err != nil { if err != nil {
panic(fmt.Sprintf("LoadSeenCommit GetBlockInfo failed:%v", err)) tendermintlog.Error("LoadBlockCommit GetBlockInfo fail", "err", err)
return nil
} }
if blockInfo == nil { if blockInfo == nil {
tendermintlog.Error("LoadSeenCommit get nil block info") tendermintlog.Error("LoadBlockCommit get nil block info")
return nil return nil
} }
return blockInfo.GetSeenCommit() return blockInfo.GetBlock().GetLastCommit()
} }
// LoadBlockCommit by height // LoadBlockState by height
func (client *Client) LoadBlockCommit(height int64) *tmtypes.TendermintCommit { func (client *Client) LoadBlockState(height int64) *tmtypes.State {
blockInfo, err := client.QueryBlockInfoByHeight(height) blockInfo, err := client.QueryBlockInfoByHeight(height)
if err != nil { if err != nil {
panic(fmt.Sprintf("LoadBlockCommit GetBlockInfo failed:%v", err)) tendermintlog.Error("LoadBlockState GetBlockInfo fail", "err", err)
return nil
} }
if blockInfo == nil { if blockInfo == nil {
tendermintlog.Error("LoadBlockCommit get nil block info") tendermintlog.Error("LoadBlockState get nil block info")
return nil return nil
} }
return blockInfo.GetLastCommit() return blockInfo.GetState()
} }
// LoadProposalBlock by height // LoadProposalBlock by height
...@@ -567,8 +619,8 @@ func (client *Client) LoadProposalBlock(height int64) *tmtypes.TendermintBlock { ...@@ -567,8 +619,8 @@ func (client *Client) LoadProposalBlock(height int64) *tmtypes.TendermintBlock {
proposalBlock := blockInfo.GetBlock() proposalBlock := blockInfo.GetBlock()
if proposalBlock != nil { if proposalBlock != nil {
proposalBlock.Txs = append(proposalBlock.Txs, block.Txs[1:]...) proposalBlock.Data = block
txHash := merkle.CalcMerkleRoot(proposalBlock.Txs) txHash := merkle.CalcMerkleRoot(proposalBlock.Data.Txs)
tendermintlog.Debug("LoadProposalBlock txs hash", "height", proposalBlock.Header.Height, "tx-hash", fmt.Sprintf("%X", txHash)) tendermintlog.Debug("LoadProposalBlock txs hash", "height", proposalBlock.Header.Height, "tx-hash", fmt.Sprintf("%X", txHash))
} }
return proposalBlock return proposalBlock
......
...@@ -7,6 +7,7 @@ package tendermint ...@@ -7,6 +7,7 @@ package tendermint
import ( import (
"context" "context"
"encoding/binary" "encoding/binary"
"encoding/hex"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
...@@ -15,6 +16,8 @@ import ( ...@@ -15,6 +16,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/33cn/chain33/blockchain" "github.com/33cn/chain33/blockchain"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/limits" "github.com/33cn/chain33/common/limits"
...@@ -27,6 +30,7 @@ import ( ...@@ -27,6 +30,7 @@ import (
"github.com/33cn/chain33/store" "github.com/33cn/chain33/store"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/norm/types" pty "github.com/33cn/plugin/plugin/dapp/norm/types"
ty "github.com/33cn/plugin/plugin/dapp/valnode/types"
"google.golang.org/grpc" "google.golang.org/grpc"
_ "github.com/33cn/chain33/system" _ "github.com/33cn/chain33/system"
...@@ -36,7 +40,7 @@ import ( ...@@ -36,7 +40,7 @@ import (
var ( var (
random *rand.Rand random *rand.Rand
loopCount = 10 loopCount = 3
conn *grpc.ClientConn conn *grpc.ClientConn
c types.Chain33Client c types.Chain33Client
) )
...@@ -50,12 +54,12 @@ func init() { ...@@ -50,12 +54,12 @@ func init() {
log.SetLogLevel("info") log.SetLogLevel("info")
} }
func TestTendermintPerf(t *testing.T) { func TestTendermintPerf(t *testing.T) {
TendermintPerf() TendermintPerf(t)
fmt.Println("=======start clear test data!=======") fmt.Println("=======start clear test data!=======")
clearTestData() clearTestData()
} }
func TendermintPerf() { func TendermintPerf(t *testing.T) {
q, chain, s, mem, exec, cs, p2p := initEnvTendermint() q, chain, s, mem, exec, cs, p2p := initEnvTendermint()
defer chain.Close() defer chain.Close()
defer mem.Close() defer mem.Close()
...@@ -68,12 +72,18 @@ func TendermintPerf() { ...@@ -68,12 +72,18 @@ func TendermintPerf() {
for err != nil { for err != nil {
err = createConn() err = createConn()
} }
time.Sleep(10 * time.Second) time.Sleep(2 * time.Second)
for i := 0; i < loopCount; i++ { for i := 0; i < loopCount; i++ {
NormPut() NormPut()
time.Sleep(time.Second) time.Sleep(time.Second)
} }
time.Sleep(10 * time.Second) CheckState(t, cs.(*Client))
AddNode()
for i := 0; i < loopCount*3; i++ {
NormPut()
time.Sleep(time.Second)
}
time.Sleep(2 * time.Second)
} }
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) { func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
...@@ -177,3 +187,38 @@ func NormPut() { ...@@ -177,3 +187,38 @@ func NormPut() {
return return
} }
} }
func AddNode() {
pubkey := "788657125A5A547B499F8B74239092EBB6466E8A205348D9EA645D510235A671"
pubkeybyte, err := hex.DecodeString(pubkey)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
nput := &ty.ValNodeAction_Node{Node: &ty.ValNode{PubKey: pubkeybyte, Power: int64(2)}}
action := &ty.ValNodeAction{Value: nput, Ty: ty.ValNodeActionUpdate}
tx := &types.Transaction{Execer: []byte("valnode"), Payload: types.Encode(action), Fee: fee}
tx.To = address.ExecAddress("valnode")
tx.Nonce = random.Int63()
tx.Sign(types.SECP256K1, getprivkey("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"))
reply, err := c.SendTransaction(context.Background(), tx)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if !reply.IsOk {
fmt.Fprintln(os.Stderr, errors.New(string(reply.GetMsg())))
return
}
}
func CheckState(t *testing.T, client *Client) {
msg1, err := client.Query_IsHealthy(&types.ReqNil{})
assert.Nil(t, err)
flag := msg1.(*ty.IsHealthy).IsHealthy
assert.Equal(t, true, flag)
_, err = client.Query_NodeInfo(&types.ReqNil{})
assert.Nil(t, err)
}
...@@ -17,7 +17,6 @@ import ( ...@@ -17,7 +17,6 @@ import (
"github.com/33cn/chain33/common/merkle" "github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types" tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/golang/protobuf/proto"
) )
var ( var (
...@@ -58,67 +57,62 @@ type TendermintBlock struct { ...@@ -58,67 +57,62 @@ type TendermintBlock struct {
// MakeBlock returns a new block with an empty header, except what can be computed from itself. // MakeBlock returns a new block with an empty header, except what can be computed from itself.
// It populates the same set of fields validated by ValidateBasic // It populates the same set of fields validated by ValidateBasic
func MakeBlock(height int64, round int64, Txs []*types.Transaction, commit *tmtypes.TendermintCommit) *TendermintBlock { func MakeBlock(height int64, round int64, pblock *types.Block, commit *tmtypes.TendermintCommit) *TendermintBlock {
block := &TendermintBlock{&tmtypes.TendermintBlock{ block := &TendermintBlock{
Header: &tmtypes.TendermintBlockHeader{ &tmtypes.TendermintBlock{
Height: height, Header: &tmtypes.TendermintBlockHeader{
Round: round, Height: height,
Time: time.Now().UnixNano(), Round: round,
NumTxs: int64(len(Txs)), Time: pblock.BlockTime,
NumTxs: int64(len(pblock.Txs)),
},
Data: pblock,
LastCommit: commit,
}, },
Txs: Txs,
LastCommit: commit,
Evidence: &tmtypes.EvidenceData{Evidence: make([]*tmtypes.EvidenceEnvelope, 0)},
},
} }
block.FillHeader() block.FillHeader()
return block return block
} }
// AddEvidence appends the given evidence to the block
func (b *TendermintBlock) AddEvidence(evidence []Evidence) {
for _, item := range evidence {
ev := item.Child()
if ev != nil {
data, err := proto.Marshal(ev)
if err != nil {
blocklog.Error("AddEvidence marshal failed", "error", err)
panic("AddEvidence marshal failed")
}
env := &tmtypes.EvidenceEnvelope{
TypeName: item.TypeName(),
Data: data,
}
b.Evidence.Evidence = append(b.Evidence.Evidence, env)
}
}
}
// ValidateBasic performs basic validation that doesn't involve state data. // ValidateBasic performs basic validation that doesn't involve state data.
// It checks the internal consistency of the block. // It checks the internal consistency of the block.
func (b *TendermintBlock) ValidateBasic() (int64, error) { // Further validation is done using state#ValidateBlock.
newTxs := int64(len(b.Txs)) func (b *TendermintBlock) ValidateBasic() error {
if b == nil {
return errors.New("nil block")
}
if b.Header.Height < 0 {
return errors.New("Negative Header.Height")
} else if b.Header.Height == 0 {
return errors.New("Zero Header.Height")
}
newTxs := int64(len(b.Data.Txs))
if b.Header.NumTxs != newTxs { if b.Header.NumTxs != newTxs {
return 0, fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs) return fmt.Errorf("Wrong Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs)
} }
if b.Header.TotalTxs < 0 {
return errors.New("Negative Header.TotalTxs")
}
lastCommit := Commit{ lastCommit := Commit{
TendermintCommit: b.LastCommit, TendermintCommit: b.LastCommit,
} }
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) { if b.Header.Height > 1 {
return 0, fmt.Errorf("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash()) if b.LastCommit == nil {
} return errors.New("nil LastCommit")
if b.Header.Height != 1 { }
if err := lastCommit.ValidateBasic(); err != nil { if err := lastCommit.ValidateBasic(); err != nil {
return 0, err return err
} }
} }
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) {
evidence := &EvidenceData{EvidenceData: b.Evidence} return fmt.Errorf("Wrong Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash())
if !bytes.Equal(b.Header.EvidenceHash, evidence.Hash()) {
return 0, errors.New(Fmt("Wrong Block.Header.EvidenceHash. Expected %v, got %v", b.Header.EvidenceHash, evidence.Hash()))
} }
return newTxs, nil
return nil
} }
// FillHeader fills in any remaining header fields that are a function of the block data // FillHeader fills in any remaining header fields that are a function of the block data
...@@ -129,10 +123,6 @@ func (b *TendermintBlock) FillHeader() { ...@@ -129,10 +123,6 @@ func (b *TendermintBlock) FillHeader() {
} }
b.Header.LastCommitHash = lastCommit.Hash() b.Header.LastCommitHash = lastCommit.Hash()
} }
if b.Header.EvidenceHash == nil {
evidence := &EvidenceData{EvidenceData: b.Evidence}
b.Header.EvidenceHash = evidence.Hash()
}
} }
// Hash computes and returns the block hash. // Hash computes and returns the block hash.
...@@ -173,10 +163,8 @@ func (b *TendermintBlock) StringIndented(indent string) string { ...@@ -173,10 +163,8 @@ func (b *TendermintBlock) StringIndented(indent string) string {
return Fmt(`Block{ return Fmt(`Block{
%s %v %s %v
%s %v %s %v
%s %v
%s}#%v`, %s}#%v`,
indent, header.StringIndented(indent+" "), indent, header.StringIndented(indent+" "),
// indent, b.Evidence.StringIndented(indent+" "),
indent, lastCommit.StringIndented(indent+" "), indent, lastCommit.StringIndented(indent+" "),
indent, b.Hash()) indent, b.Hash())
} }
...@@ -227,7 +215,6 @@ func (h *Header) StringIndented(indent string) string { ...@@ -227,7 +215,6 @@ func (h *Header) StringIndented(indent string) string {
%s App: %v %s App: %v
%s Conensus: %v %s Conensus: %v
%s Results: %v %s Results: %v
%s Evidence: %v
%s}#%v`, %s}#%v`,
indent, h.ChainID, indent, h.ChainID,
indent, h.Height, indent, h.Height,
...@@ -240,24 +227,19 @@ func (h *Header) StringIndented(indent string) string { ...@@ -240,24 +227,19 @@ func (h *Header) StringIndented(indent string) string {
indent, h.AppHash, indent, h.AppHash,
indent, h.ConsensusHash, indent, h.ConsensusHash,
indent, h.LastResultsHash, indent, h.LastResultsHash,
indent, h.EvidenceHash,
indent, h.Hash()) indent, h.Hash())
} }
// Commit struct // Commit struct
type Commit struct { type Commit struct {
*tmtypes.TendermintCommit *tmtypes.TendermintCommit
firstPrecommit *tmtypes.Vote
hash []byte hash []byte
bitArray *BitArray bitArray *BitArray
firstPrecommit *tmtypes.Vote
} }
// FirstPrecommit returns the first non-nil precommit in the commit // FirstPrecommit returns the first non-nil precommit in the commit
func (commit *Commit) FirstPrecommit() *tmtypes.Vote { func (commit *Commit) FirstPrecommit() *tmtypes.Vote {
if len(commit.Precommits) == 0 {
return nil
}
if commit.firstPrecommit != nil { if commit.firstPrecommit != nil {
return commit.firstPrecommit return commit.firstPrecommit
} }
...@@ -334,13 +316,14 @@ func (commit *Commit) ValidateBasic() error { ...@@ -334,13 +316,14 @@ func (commit *Commit) ValidateBasic() error {
height, round := commit.Height(), commit.Round() height, round := commit.Height(), commit.Round()
// validate the precommits // validate the precommits
for _, precommit := range commit.Precommits { for _, item := range commit.Precommits {
// It's OK for precommits to be missing. // may be nil if validator skipped.
if precommit == nil { if item == nil || len(item.Signature) == 0 {
continue continue
} }
precommit := &Vote{Vote: item}
// Ensure that all votes are precommits // Ensure that all votes are precommits
if byte(precommit.Type) != VoteTypePrecommit { if precommit.Type != uint32(VoteTypePrecommit) {
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v", return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
precommit.Type) precommit.Type)
} }
...@@ -394,113 +377,3 @@ type SignedHeader struct { ...@@ -394,113 +377,3 @@ type SignedHeader struct {
Header *Header `json:"header"` Header *Header `json:"header"`
Commit *Commit `json:"commit"` Commit *Commit `json:"commit"`
} }
// EvidenceEnvelope ...
type EvidenceEnvelope struct {
*tmtypes.EvidenceEnvelope
}
// EvidenceEnvelopeList contains any evidence of malicious wrong-doing by validators
type EvidenceEnvelopeList []EvidenceEnvelope
// Hash ...
func (env EvidenceEnvelope) Hash() []byte {
penv := env.EvidenceEnvelope
evidence := EvidenceEnvelope2Evidence(penv)
if evidence != nil {
return evidence.Hash()
}
return nil
}
func (env EvidenceEnvelope) String() string {
penv := env.EvidenceEnvelope
evidence := EvidenceEnvelope2Evidence(penv)
if evidence != nil {
return evidence.String()
}
return ""
}
// Hash returns the simple merkle root hash of the EvidenceList.
func (evl EvidenceEnvelopeList) Hash() []byte {
// Recursive impl.
// Copied from tmlibs/merkle to avoid allocations
switch len(evl) {
case 0:
return nil
case 1:
return evl[0].Hash()
default:
left := evl[:(len(evl)+1)/2].Hash()
right := evl[(len(evl)+1)/2:].Hash()
cache := make([]byte, len(left)+len(right))
return merkle.GetHashFromTwoHash(cache, left, right)
}
}
func (evl EvidenceEnvelopeList) String() string {
s := ""
for _, e := range evl {
s += Fmt("%s\t\t", e)
}
return s
}
// Has returns true if the evidence is in the EvidenceList.
func (evl EvidenceEnvelopeList) Has(evidence Evidence) bool {
for _, ev := range evl {
penv := ev.EvidenceEnvelope
tmp := EvidenceEnvelope2Evidence(penv)
if tmp != nil {
if tmp.Equal(evidence) {
return true
}
}
}
return false
}
// EvidenceData ...
type EvidenceData struct {
*tmtypes.EvidenceData
hash []byte
}
// Hash returns the hash of the data.
func (data *EvidenceData) Hash() []byte {
if data.hash == nil {
if data.EvidenceData == nil {
return nil
}
var evidence EvidenceEnvelopeList
for _, item := range data.Evidence {
elem := EvidenceEnvelope{
EvidenceEnvelope: item,
}
evidence = append(evidence, elem)
}
data.hash = evidence.Hash()
}
return data.hash
}
// StringIndented returns a string representation of the evidence.
func (data *EvidenceData) StringIndented(indent string) string {
if data == nil {
return "nil-Evidence"
}
evStrings := make([]string, MinInt(len(data.Evidence), 21))
for i, ev := range data.Evidence {
if i == 20 {
evStrings[i] = Fmt("... (%v total)", len(data.Evidence))
break
}
evStrings[i] = Fmt("Evidence:%v", ev)
}
return Fmt(`Data{
%s %v
%s}#%v`,
indent, strings.Join(evStrings, "\n"+indent+" "),
indent, data.hash)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "errors"
var (
// ErrBaseTxType error type
ErrBaseTxType = errors.New("ErrBaseTxType")
// ErrBlockInfoTx error type
ErrBlockInfoTx = errors.New("ErrBlockInfoTx")
// ErrBaseExecErr error type
ErrBaseExecErr = errors.New("ErrBaseExecErr")
// ErrLastBlockID error type
ErrLastBlockID = errors.New("ErrLastBlockID")
)
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/merkle"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/golang/protobuf/proto"
)
// ErrEvidenceInvalid wraps a piece of evidence and the error denoting how or why it is invalid.
type ErrEvidenceInvalid struct {
Evidence Evidence
ErrorValue error
}
// NewEvidenceInvalidErr ...
func NewEvidenceInvalidErr(ev Evidence, err error) *ErrEvidenceInvalid {
return &ErrEvidenceInvalid{ev, err}
}
// Error returns a string representation of the error.
func (err *ErrEvidenceInvalid) Error() string {
return Fmt("Invalid evidence: %v. Evidence: %v", err.ErrorValue, err.Evidence)
}
//-------------------------------------------
const (
DuplicateVote = "DuplicateVote"
MockGood = "MockGood"
MockBad = "MockBad"
)
// EvidenceType map define
var (
EvidenceType2Type map[string]reflect.Type
EvidenceType2Obj map[string]Evidence
)
// Evidence represents any provable malicious activity by a validator
type Evidence interface {
Height() int64 // height of the equivocation
Address() []byte // address of the equivocating validator
Index() int // index of the validator in the validator set
Hash() []byte // hash of the evidence
Verify(chainID string) error // verify the evidence
Equal(Evidence) bool // check equality of evidence
String() string
Copy() Evidence
TypeName() string
SetChild(child proto.Message)
Child() proto.Message
}
//-------------------------------------------
// EvidenceList is a list of Evidence. Evidences is not a word.
type EvidenceList []Evidence
// Hash returns the simple merkle root hash of the EvidenceList.
func (evl EvidenceList) Hash() []byte {
// Recursive impl.
// Copied from tmlibs/merkle to avoid allocations
switch len(evl) {
case 0:
return nil
case 1:
return evl[0].Hash()
default:
left := evl[:(len(evl)+1)/2].Hash()
right := evl[(len(evl)+1)/2:].Hash()
cache := make([]byte, len(left)+len(right))
return merkle.GetHashFromTwoHash(cache, left, right)
}
}
func (evl EvidenceList) String() string {
s := ""
for _, e := range evl {
s += Fmt("%s\t\t", e)
}
return s
}
// Has returns true if the evidence is in the EvidenceList.
func (evl EvidenceList) Has(evidence Evidence) bool {
for _, ev := range evl {
if ev.Equal(evidence) {
return true
}
}
return false
}
//-------------------------------------------
// DuplicateVoteEvidence contains evidence a validator signed two conflicting votes.
type DuplicateVoteEvidence struct {
*tmtypes.DuplicateVoteEvidence
}
// String returns a string representation of the evidence.
func (dve *DuplicateVoteEvidence) String() string {
return Fmt("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB)
}
// Height returns the height this evidence refers to.
func (dve *DuplicateVoteEvidence) Height() int64 {
return dve.VoteA.Height
}
// Address returns the address of the validator.
func (dve *DuplicateVoteEvidence) Address() []byte {
pubkey, err := PubKeyFromString(dve.PubKey)
if err != nil {
return nil
}
return GenAddressByPubKey(pubkey)
}
// Index returns the index of the validator.
func (dve *DuplicateVoteEvidence) Index() int {
return int(dve.VoteA.ValidatorIndex)
}
// Hash returns the hash of the evidence.
func (dve *DuplicateVoteEvidence) Hash() []byte {
return SimpleHashFromBinary(dve)
}
// Verify returns an error if the two votes aren't conflicting.
// To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks.
func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
// H/R/S must be the same
if dve.VoteA.Height != dve.VoteB.Height ||
dve.VoteA.Round != dve.VoteB.Round ||
dve.VoteA.Type != dve.VoteB.Type {
return fmt.Errorf("DuplicateVoteEvidence Error: H/R/S does not match. Got %v and %v", dve.VoteA, dve.VoteB)
}
// Address must be the same
if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress)
}
// XXX: Should we enforce index is the same ?
if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex)
}
blockIDA := BlockID{
*dve.VoteA.BlockID,
}
blockIDB := BlockID{
*dve.VoteB.BlockID,
}
// BlockIDs must be different
if blockIDA.Equals(blockIDB) {
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
}
// Signatures must be valid
pubkey, err := PubKeyFromString(dve.PubKey)
if err != nil {
return fmt.Errorf("DuplicateVoteEvidence Error: pubkey[%v] to PubKey failed:%v", dve.PubKey, err)
}
sigA, err := ConsensusCrypto.SignatureFromBytes(dve.VoteA.Signature)
if err != nil {
return fmt.Errorf("DuplicateVoteEvidence Error: SIGA[%v] to signature failed:%v", dve.VoteA.Signature, err)
}
sigB, err := ConsensusCrypto.SignatureFromBytes(dve.VoteB.Signature)
if err != nil {
return fmt.Errorf("DuplicateVoteEvidence Error: SIGB[%v] to signature failed:%v", dve.VoteB.Signature, err)
}
vote := &Vote{
dve.VoteA,
}
if !pubkey.VerifyBytes(SignBytes(chainID, vote), sigA) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
}
vote = &Vote{
dve.VoteB,
}
if !pubkey.VerifyBytes(SignBytes(chainID, vote), sigB) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
}
return nil
}
// Equal checks if two pieces of evidence are equal.
func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
if _, ok := ev.(*DuplicateVoteEvidence); !ok {
return false
}
if dve == nil {
return false
}
// just check their hashes
return bytes.Equal(SimpleHashFromBinary(dve), SimpleHashFromBinary(ev.(*DuplicateVoteEvidence)))
}
// TypeName ...
func (dve *DuplicateVoteEvidence) TypeName() string {
return DuplicateVote
}
// Copy ...
func (dve *DuplicateVoteEvidence) Copy() Evidence {
return &DuplicateVoteEvidence{}
}
// SetChild ...
func (dve *DuplicateVoteEvidence) SetChild(child proto.Message) {
dve.DuplicateVoteEvidence = child.(*tmtypes.DuplicateVoteEvidence)
}
// Child ...
func (dve *DuplicateVoteEvidence) Child() proto.Message {
return dve.DuplicateVoteEvidence
}
// SimpleHashFromBinary ...
func SimpleHashFromBinary(item *DuplicateVoteEvidence) []byte {
bytes, e := json.Marshal(item)
if e != nil {
//commonlog.Error("SimpleHashFromBinary marshal failed", "type", item, "error", e)
panic(Fmt("SimpleHashFromBinary marshal failed, err:%v", e))
}
return crypto.Ripemd160(bytes)
}
// EvidenceEnvelope2Evidence ...
func EvidenceEnvelope2Evidence(envelope *tmtypes.EvidenceEnvelope) Evidence {
if v, ok := EvidenceType2Type[envelope.TypeName]; ok {
realMsg2 := reflect.New(v).Interface()
err := proto.Unmarshal(envelope.Data, realMsg2.(proto.Message))
if err != nil {
panic(Fmt("Evidence is not valid", "evidenceType", envelope.TypeName, "err", err))
}
if evidence, ok2 := EvidenceType2Obj[envelope.TypeName]; ok2 {
evidence = evidence.Copy()
evidence.SetChild(realMsg2.(proto.Message))
return evidence.(Evidence)
}
}
return nil
}
// MockGoodEvidence UNSTABLE
type MockGoodEvidence struct {
MGHeight int64
MGAddress []byte
MGIndex int
}
// NewMockGoodEvidence UNSTABLE
func NewMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence {
return MockGoodEvidence{height, address, index}
}
// Height ...
func (e MockGoodEvidence) Height() int64 { return e.MGHeight }
// Address ...
func (e MockGoodEvidence) Address() []byte { return e.MGAddress }
// Index ...
func (e MockGoodEvidence) Index() int { return e.MGIndex }
// Hash ...
func (e MockGoodEvidence) Hash() []byte {
return []byte(Fmt("%d-%d", e.MGHeight, e.MGIndex))
}
// Verify ...
func (e MockGoodEvidence) Verify(chainID string) error { return nil }
// Equal ...
func (e MockGoodEvidence) Equal(ev Evidence) bool {
e2 := ev.(MockGoodEvidence)
return e.MGHeight == e2.MGHeight &&
bytes.Equal(e.MGAddress, e2.MGAddress) &&
e.MGIndex == e2.MGIndex
}
func (e MockGoodEvidence) String() string {
return Fmt("GoodEvidence: %d/%s/%d", e.MGHeight, e.MGAddress, e.MGIndex)
}
// TypeName ...
func (e MockGoodEvidence) TypeName() string {
return MockGood
}
// Copy ...
func (e MockGoodEvidence) Copy() Evidence {
return &MockGoodEvidence{}
}
// SetChild ...
func (e MockGoodEvidence) SetChild(proto.Message) {}
// Child ...
func (e MockGoodEvidence) Child() proto.Message {
return nil
}
// MockBadEvidence UNSTABLE
type MockBadEvidence struct {
MockGoodEvidence
}
// Verify ...
func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") }
// Equal ...
func (e MockBadEvidence) Equal(ev Evidence) bool {
e2 := ev.(MockBadEvidence)
return e.MGHeight == e2.MGHeight &&
bytes.Equal(e.MGAddress, e2.MGAddress) &&
e.MGIndex == e2.MGIndex
}
func (e MockBadEvidence) String() string {
return Fmt("BadEvidence: %d/%s/%d", e.MGHeight, e.MGAddress, e.MGIndex)
}
// TypeName ...
func (e MockBadEvidence) TypeName() string {
return MockBad
}
// Copy ...
func (e MockBadEvidence) Copy() Evidence {
return &MockBadEvidence{}
}
// SetChild ...
func (e MockBadEvidence) SetChild(proto.Message) {}
// Child ...
func (e MockBadEvidence) Child() proto.Message {
return nil
}
//------------------------------------------------------
// evidence pool
// EvidencePool defines the EvidencePool interface used by the ConsensusState.
// UNSTABLE
type EvidencePool interface {
PendingEvidence() []Evidence
AddEvidence(Evidence) error
Update(*TendermintBlock)
}
// MockEvidencePool is an empty implementation of a Mempool, useful for testing.
// UNSTABLE
type MockEvidencePool struct {
}
// PendingEvidence ...
func (m MockEvidencePool) PendingEvidence() []Evidence { return nil }
// AddEvidence ...
func (m MockEvidencePool) AddEvidence(Evidence) error { return nil }
// Update ...
func (m MockEvidencePool) Update(*TendermintBlock) {}
...@@ -100,9 +100,8 @@ func (hvs *HeightVoteSet) SetRound(round int) { ...@@ -100,9 +100,8 @@ func (hvs *HeightVoteSet) SetRound(round int) {
func (hvs *HeightVoteSet) addRound(round int) { func (hvs *HeightVoteSet) addRound(round int) {
if _, ok := hvs.roundVoteSets[round]; ok { if _, ok := hvs.roundVoteSets[round]; ok {
panic(Fmt("Panicked on a Sanity Check: %v", "addRound() for an existing round")) panic("addRound() for an existing round")
} }
// log.Debug("addRound(round)", "round", round)
prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet) prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet)
precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet) precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet)
hvs.roundVoteSets[round] = RoundVoteSet{ hvs.roundVoteSets[round] = RoundVoteSet{
...@@ -179,7 +178,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, voteType byte) *VoteSet { ...@@ -179,7 +178,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, voteType byte) *VoteSet {
case VoteTypePrecommit: case VoteTypePrecommit:
return rvs.Precommits return rvs.Precommits
default: default:
panic(Fmt("Panicked on a Sanity Check: %v", Fmt("Unexpected vote type %X", voteType))) panic(Fmt("Unexpected vote type %X", voteType))
} }
} }
......
...@@ -440,7 +440,7 @@ func (pv *PrivValidatorImp) SignHeartbeat(chainID string, heartbeat *Heartbeat) ...@@ -440,7 +440,7 @@ func (pv *PrivValidatorImp) SignHeartbeat(chainID string, heartbeat *Heartbeat)
// String returns a string representation of the PrivValidatorImp. // String returns a string representation of the PrivValidatorImp.
func (pv *PrivValidatorImp) String() string { func (pv *PrivValidatorImp) String() string {
return Fmt("PrivValidator{%v LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep) return Fmt("PrivValidator{%X LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep)
} }
// GetLastHeight ... // GetLastHeight ...
......
...@@ -32,7 +32,6 @@ const ( ...@@ -32,7 +32,6 @@ const (
RoundStepCommit = RoundStepType(0x08) // Entered commit state machine RoundStepCommit = RoundStepType(0x08) // Entered commit state machine
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait. // NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
EvidenceListID = byte(0x01)
NewRoundStepID = byte(0x02) NewRoundStepID = byte(0x02)
CommitStepID = byte(0x03) CommitStepID = byte(0x03)
ProposalID = byte(0x04) ProposalID = byte(0x04)
...@@ -43,6 +42,7 @@ const ( ...@@ -43,6 +42,7 @@ const (
VoteSetBitsID = byte(0x09) VoteSetBitsID = byte(0x09)
ProposalHeartbeatID = byte(0x0a) ProposalHeartbeatID = byte(0x0a)
ProposalBlockID = byte(0x0b) ProposalBlockID = byte(0x0b)
ValidBlockID = byte(0x0c)
PacketTypePing = byte(0xff) PacketTypePing = byte(0xff)
PacketTypePong = byte(0xfe) PacketTypePong = byte(0xfe)
...@@ -51,7 +51,6 @@ const ( ...@@ -51,7 +51,6 @@ const (
// InitMessageMap ... // InitMessageMap ...
func InitMessageMap() { func InitMessageMap() {
MsgMap = map[byte]reflect.Type{ MsgMap = map[byte]reflect.Type{
EvidenceListID: reflect.TypeOf(tmtypes.EvidenceData{}),
NewRoundStepID: reflect.TypeOf(tmtypes.NewRoundStepMsg{}), NewRoundStepID: reflect.TypeOf(tmtypes.NewRoundStepMsg{}),
CommitStepID: reflect.TypeOf(tmtypes.CommitStepMsg{}), CommitStepID: reflect.TypeOf(tmtypes.CommitStepMsg{}),
ProposalID: reflect.TypeOf(tmtypes.Proposal{}), ProposalID: reflect.TypeOf(tmtypes.Proposal{}),
...@@ -62,6 +61,7 @@ func InitMessageMap() { ...@@ -62,6 +61,7 @@ func InitMessageMap() {
VoteSetBitsID: reflect.TypeOf(tmtypes.VoteSetBitsMsg{}), VoteSetBitsID: reflect.TypeOf(tmtypes.VoteSetBitsMsg{}),
ProposalHeartbeatID: reflect.TypeOf(tmtypes.Heartbeat{}), ProposalHeartbeatID: reflect.TypeOf(tmtypes.Heartbeat{}),
ProposalBlockID: reflect.TypeOf(tmtypes.TendermintBlock{}), ProposalBlockID: reflect.TypeOf(tmtypes.TendermintBlock{}),
ValidBlockID: reflect.TypeOf(tmtypes.ValidBlockMsg{}),
} }
} }
...@@ -108,6 +108,8 @@ type RoundState struct { ...@@ -108,6 +108,8 @@ type RoundState struct {
ProposalBlock *TendermintBlock ProposalBlock *TendermintBlock
LockedRound int LockedRound int
LockedBlock *TendermintBlock LockedBlock *TendermintBlock
ValidRound int // Last known round with POL for non-nil valid block.
ValidBlock *TendermintBlock // Last known block of POL mentioned above.
Votes *HeightVoteSet Votes *HeightVoteSet
CommitRound int CommitRound int
LastCommit *VoteSet // Last precommits at Height-1 LastCommit *VoteSet // Last precommits at Height-1
...@@ -141,6 +143,8 @@ func (rs *RoundState) StringIndented(indent string) string { ...@@ -141,6 +143,8 @@ func (rs *RoundState) StringIndented(indent string) string {
%s ProposalBlock: %v %s ProposalBlock: %v
%s LockedRound: %v %s LockedRound: %v
%s LockedBlock: %v %s LockedBlock: %v
%s ValidRound: %v
%s ValidBlock: %v
%s Votes: %v %s Votes: %v
%s LastCommit: %v %s LastCommit: %v
%s LastValidators:%v %s LastValidators:%v
...@@ -153,6 +157,8 @@ func (rs *RoundState) StringIndented(indent string) string { ...@@ -153,6 +157,8 @@ func (rs *RoundState) StringIndented(indent string) string {
indent, rs.ProposalBlock.StringShort(), indent, rs.ProposalBlock.StringShort(),
indent, rs.LockedRound, indent, rs.LockedRound,
indent, rs.LockedBlock.StringShort(), indent, rs.LockedBlock.StringShort(),
indent, rs.ValidRound,
indent, rs.ValidBlock.StringShort(),
indent, rs.Votes.StringIndented(indent+" "), indent, rs.Votes.StringIndented(indent+" "),
indent, rs.LastCommit.StringShort(), indent, rs.LastCommit.StringShort(),
indent, rs.LastValidators.StringIndented(indent+" "), indent, rs.LastValidators.StringIndented(indent+" "),
...@@ -173,14 +179,15 @@ type PeerRoundState struct { ...@@ -173,14 +179,15 @@ type PeerRoundState struct {
StartTime time.Time // Estimated start of round 0 at this height StartTime time.Time // Estimated start of round 0 at this height
Proposal bool // True if peer has proposal for this round Proposal bool // True if peer has proposal for this round
ProposalBlock bool // True if peer has proposal block for this round ProposalBlock bool // True if peer has proposal block for this round
ProposalPOLRound int // Proposal's POL round. -1 if none. ProposalBlockHash []byte
ProposalPOL *BitArray // nil until ProposalPOLMessage received. ProposalPOLRound int // Proposal's POL round. -1 if none.
Prevotes *BitArray // All votes peer has for this round ProposalPOL *BitArray // nil until ProposalPOLMessage received.
Precommits *BitArray // All precommits peer has for this round Prevotes *BitArray // All votes peer has for this round
LastCommitRound int // Round of commit for last height. -1 if none. Precommits *BitArray // All precommits peer has for this round
LastCommit *BitArray // All commit precommits of commit for last height. LastCommitRound int // Round of commit for last height. -1 if none.
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none. LastCommit *BitArray // All commit precommits of commit for last height.
CatchupCommit *BitArray // All commit precommits peer has for this height & CatchupCommitRound 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
} }
// String returns a string representation of the PeerRoundState // String returns a string representation of the PeerRoundState
...@@ -194,6 +201,7 @@ func (prs PeerRoundState) StringIndented(indent string) string { ...@@ -194,6 +201,7 @@ func (prs PeerRoundState) StringIndented(indent string) string {
%s %v/%v/%v @%v %s %v/%v/%v @%v
%s Proposal %v %s Proposal %v
%s ProposalBlock %v %s ProposalBlock %v
%s ProposalBlockHash %X
%s POL %v (round %v) %s POL %v (round %v)
%s Prevotes %v %s Prevotes %v
%s Precommits %v %s Precommits %v
...@@ -203,6 +211,7 @@ func (prs PeerRoundState) StringIndented(indent string) string { ...@@ -203,6 +211,7 @@ func (prs PeerRoundState) StringIndented(indent string) string {
indent, prs.Height, prs.Round, prs.Step, prs.StartTime, indent, prs.Height, prs.Round, prs.Step, prs.StartTime,
indent, prs.Proposal, indent, prs.Proposal,
indent, prs.ProposalBlock, indent, prs.ProposalBlock,
indent, prs.ProposalBlock,
indent, prs.ProposalPOL, prs.ProposalPOLRound, indent, prs.ProposalPOL, prs.ProposalPOLRound,
indent, prs.Prevotes, indent, prs.Prevotes,
indent, prs.Precommits, indent, prs.Precommits,
......
...@@ -25,6 +25,7 @@ var ( ...@@ -25,6 +25,7 @@ var (
ErrVoteInvalidSignature = errors.New("Invalid signature") ErrVoteInvalidSignature = errors.New("Invalid signature")
ErrVoteInvalidBlockHash = errors.New("Invalid block hash") ErrVoteInvalidBlockHash = errors.New("Invalid block hash")
ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature") ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature")
ErrVoteConflict = errors.New("Conflicting vote")
ErrVoteNil = errors.New("Nil vote") ErrVoteNil = errors.New("Nil vote")
votelog = log15.New("module", "tendermint-vote") votelog = log15.New("module", "tendermint-vote")
) )
...@@ -70,7 +71,7 @@ func NewProposal(height int64, round int, blockhash []byte, polRound int, polBlo ...@@ -70,7 +71,7 @@ func NewProposal(height int64, round int, blockhash []byte, polRound int, polBlo
// String returns a string representation of the Proposal. // String returns a string representation of the Proposal.
func (p *Proposal) String() string { func (p *Proposal) String() string {
return fmt.Sprintf("Proposal{%v/%v (%v,%v) %X %v @ %s}", return fmt.Sprintf("Proposal{%v/%v (%v, %X) %X %X @ %s}",
p.Height, p.Round, p.POLRound, p.POLBlockID, p.Height, p.Round, p.POLRound, p.POLBlockID,
p.Blockhash, p.Signature, CanonicalTime(time.Unix(0, p.Timestamp))) p.Blockhash, p.Signature, CanonicalTime(time.Unix(0, p.Timestamp)))
} }
...@@ -119,34 +120,6 @@ func (heartbeat *Heartbeat) WriteSignBytes(chainID string, w io.Writer, n *int, ...@@ -119,34 +120,6 @@ func (heartbeat *Heartbeat) WriteSignBytes(chainID string, w io.Writer, n *int,
*err = writeErr *err = writeErr
} }
// ErrVoteConflictingVotes ...
type ErrVoteConflictingVotes struct {
*DuplicateVoteEvidence
}
func (err *ErrVoteConflictingVotes) Error() string {
pubkey, error := PubKeyFromString(err.PubKey)
if error != nil {
return fmt.Sprintf("Conflicting votes from validator PubKey:%v,error:%v", err.PubKey, error)
}
addr := GenAddressByPubKey(pubkey)
return fmt.Sprintf("Conflicting votes from validator %v", addr)
}
// NewConflictingVoteError ...
func NewConflictingVoteError(val *Validator, voteA, voteB *tmtypes.Vote) *ErrVoteConflictingVotes {
keyString := fmt.Sprintf("%X", val.PubKey)
return &ErrVoteConflictingVotes{
&DuplicateVoteEvidence{
&tmtypes.DuplicateVoteEvidence{
PubKey: keyString,
VoteA: voteA,
VoteB: voteB,
},
},
}
}
// Types of votes // Types of votes
// TODO Make a new type "VoteType" // TODO Make a new type "VoteType"
const ( const (
...@@ -211,7 +184,7 @@ func (vote *Vote) String() string { ...@@ -211,7 +184,7 @@ func (vote *Vote) String() string {
PanicSanity("Unknown vote type") PanicSanity("Unknown vote type")
} }
return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %v @ %s}", return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
vote.ValidatorIndex, Fingerprint(vote.ValidatorAddress), vote.ValidatorIndex, Fingerprint(vote.ValidatorAddress),
vote.Height, vote.Round, vote.Type, typeString, vote.Height, vote.Round, vote.Type, typeString,
Fingerprint(vote.BlockID.Hash), vote.Signature, Fingerprint(vote.BlockID.Hash), vote.Signature,
...@@ -240,7 +213,6 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { ...@@ -240,7 +213,6 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
// Hash ... // Hash ...
func (vote *Vote) Hash() []byte { func (vote *Vote) Hash() []byte {
if vote == nil { if vote == nil {
//votelog.Error("vote hash is nil")
return nil return nil
} }
bytes, err := json.Marshal(vote) bytes, err := json.Marshal(vote)
......
...@@ -70,7 +70,7 @@ func (v *Validator) String() string { ...@@ -70,7 +70,7 @@ func (v *Validator) String() string {
if v == nil { if v == nil {
return "nil-Validator" return "nil-Validator"
} }
return Fmt("Validator{%v %v VP:%v A:%v}", return Fmt("Validator{ADDR:%X PUB:%X VP:%v A:%v}",
v.Address, v.Address,
v.PubKey, v.PubKey,
v.VotingPower, v.VotingPower,
......
...@@ -200,7 +200,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { ...@@ -200,7 +200,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
// Add vote and get conflicting vote if any // Add vote and get conflicting vote if any
added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower) added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
if conflicting != nil { if conflicting != nil {
return added, NewConflictingVoteError(val, conflicting.Vote, vote.Vote) return added, errors.Wrapf(ErrVoteConflict, "Conflicting vote: %v; New vote: %v", conflicting, vote)
} }
if !added { if !added {
PanicSanity("Expected to add non-conflicting vote") PanicSanity("Expected to add non-conflicting vote")
......
syntax = "proto3"; syntax = "proto3";
import "transaction.proto"; import "blockchain.proto";
package types; package types;
...@@ -30,11 +30,9 @@ message TendermintCommit { ...@@ -30,11 +30,9 @@ message TendermintCommit {
} }
message TendermintBlockInfo { message TendermintBlockInfo {
TendermintCommit SeenCommit = 1; State State = 2;
TendermintCommit LastCommit = 2; Proposal Proposal = 3;
State State = 3; TendermintBlock block = 4;
Proposal Proposal = 4;
TendermintBlock block = 5;
} }
message BlockSize { message BlockSize {
...@@ -89,20 +87,6 @@ message State { ...@@ -89,20 +87,6 @@ message State {
bytes AppHash = 12; bytes AppHash = 12;
} }
message DuplicateVoteEvidence {
string pubKey = 1;
Vote voteA = 2;
Vote voteB = 3;
}
message EvidenceEnvelope {
string typeName = 1;
bytes data = 2;
}
message EvidenceData {
repeated EvidenceEnvelope evidence = 1;
}
message TendermintBlockHeader { message TendermintBlockHeader {
string chainID = 1; string chainID = 1;
...@@ -117,15 +101,13 @@ message TendermintBlockHeader { ...@@ -117,15 +101,13 @@ message TendermintBlockHeader {
bytes consensusHash = 10; bytes consensusHash = 10;
bytes appHash = 11; bytes appHash = 11;
bytes lastResultsHash = 12; bytes lastResultsHash = 12;
bytes evidenceHash = 13; bytes proposerAddr = 13;
} }
message TendermintBlock { message TendermintBlock {
TendermintBlockHeader header = 1; TendermintBlockHeader header = 1;
repeated Transaction txs = 2; Block data = 2;
EvidenceData evidence = 3; TendermintCommit lastCommit = 4;
TendermintCommit lastCommit = 4;
bytes proposerAddr = 5;
} }
message Proposal { message Proposal {
...@@ -146,6 +128,13 @@ message NewRoundStepMsg { ...@@ -146,6 +128,13 @@ message NewRoundStepMsg {
int32 lastCommitRound = 5; int32 lastCommitRound = 5;
} }
message ValidBlockMsg {
int64 height = 1;
int32 round = 2;
bytes blockhash = 3;
bool isCommit = 4;
}
message CommitStepMsg { message CommitStepMsg {
int64 height = 1; int64 height = 1;
} }
......
...@@ -35,7 +35,7 @@ func (m *BlockID) Reset() { *m = BlockID{} } ...@@ -35,7 +35,7 @@ func (m *BlockID) Reset() { *m = BlockID{} }
func (m *BlockID) String() string { return proto.CompactTextString(m) } func (m *BlockID) String() string { return proto.CompactTextString(m) }
func (*BlockID) ProtoMessage() {} func (*BlockID) ProtoMessage() {}
func (*BlockID) Descriptor() ([]byte, []int) { func (*BlockID) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{0} return fileDescriptor_tendermint_df861948ed10449a, []int{0}
} }
func (m *BlockID) XXX_Unmarshal(b []byte) error { func (m *BlockID) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BlockID.Unmarshal(m, b) return xxx_messageInfo_BlockID.Unmarshal(m, b)
...@@ -74,7 +74,7 @@ func (m *TendermintBitArray) Reset() { *m = TendermintBitArray{} } ...@@ -74,7 +74,7 @@ func (m *TendermintBitArray) Reset() { *m = TendermintBitArray{} }
func (m *TendermintBitArray) String() string { return proto.CompactTextString(m) } func (m *TendermintBitArray) String() string { return proto.CompactTextString(m) }
func (*TendermintBitArray) ProtoMessage() {} func (*TendermintBitArray) ProtoMessage() {}
func (*TendermintBitArray) Descriptor() ([]byte, []int) { func (*TendermintBitArray) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{1} return fileDescriptor_tendermint_df861948ed10449a, []int{1}
} }
func (m *TendermintBitArray) XXX_Unmarshal(b []byte) error { func (m *TendermintBitArray) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TendermintBitArray.Unmarshal(m, b) return xxx_messageInfo_TendermintBitArray.Unmarshal(m, b)
...@@ -126,7 +126,7 @@ func (m *Vote) Reset() { *m = Vote{} } ...@@ -126,7 +126,7 @@ func (m *Vote) Reset() { *m = Vote{} }
func (m *Vote) String() string { return proto.CompactTextString(m) } func (m *Vote) String() string { return proto.CompactTextString(m) }
func (*Vote) ProtoMessage() {} func (*Vote) ProtoMessage() {}
func (*Vote) Descriptor() ([]byte, []int) { func (*Vote) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{2} return fileDescriptor_tendermint_df861948ed10449a, []int{2}
} }
func (m *Vote) XXX_Unmarshal(b []byte) error { func (m *Vote) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Vote.Unmarshal(m, b) return xxx_messageInfo_Vote.Unmarshal(m, b)
...@@ -214,7 +214,7 @@ func (m *TendermintCommit) Reset() { *m = TendermintCommit{} } ...@@ -214,7 +214,7 @@ func (m *TendermintCommit) Reset() { *m = TendermintCommit{} }
func (m *TendermintCommit) String() string { return proto.CompactTextString(m) } func (m *TendermintCommit) String() string { return proto.CompactTextString(m) }
func (*TendermintCommit) ProtoMessage() {} func (*TendermintCommit) ProtoMessage() {}
func (*TendermintCommit) Descriptor() ([]byte, []int) { func (*TendermintCommit) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{3} return fileDescriptor_tendermint_df861948ed10449a, []int{3}
} }
func (m *TendermintCommit) XXX_Unmarshal(b []byte) error { func (m *TendermintCommit) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TendermintCommit.Unmarshal(m, b) return xxx_messageInfo_TendermintCommit.Unmarshal(m, b)
...@@ -249,21 +249,19 @@ func (m *TendermintCommit) GetPrecommits() []*Vote { ...@@ -249,21 +249,19 @@ func (m *TendermintCommit) GetPrecommits() []*Vote {
} }
type TendermintBlockInfo struct { type TendermintBlockInfo struct {
SeenCommit *TendermintCommit `protobuf:"bytes,1,opt,name=SeenCommit,proto3" json:"SeenCommit,omitempty"` State *State `protobuf:"bytes,2,opt,name=State,proto3" json:"State,omitempty"`
LastCommit *TendermintCommit `protobuf:"bytes,2,opt,name=LastCommit,proto3" json:"LastCommit,omitempty"` Proposal *Proposal `protobuf:"bytes,3,opt,name=Proposal,proto3" json:"Proposal,omitempty"`
State *State `protobuf:"bytes,3,opt,name=State,proto3" json:"State,omitempty"` Block *TendermintBlock `protobuf:"bytes,4,opt,name=block,proto3" json:"block,omitempty"`
Proposal *Proposal `protobuf:"bytes,4,opt,name=Proposal,proto3" json:"Proposal,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
Block *TendermintBlock `protobuf:"bytes,5,opt,name=block,proto3" json:"block,omitempty"` XXX_unrecognized []byte `json:"-"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_sizecache int32 `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *TendermintBlockInfo) Reset() { *m = TendermintBlockInfo{} } func (m *TendermintBlockInfo) Reset() { *m = TendermintBlockInfo{} }
func (m *TendermintBlockInfo) String() string { return proto.CompactTextString(m) } func (m *TendermintBlockInfo) String() string { return proto.CompactTextString(m) }
func (*TendermintBlockInfo) ProtoMessage() {} func (*TendermintBlockInfo) ProtoMessage() {}
func (*TendermintBlockInfo) Descriptor() ([]byte, []int) { func (*TendermintBlockInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{4} return fileDescriptor_tendermint_df861948ed10449a, []int{4}
} }
func (m *TendermintBlockInfo) XXX_Unmarshal(b []byte) error { func (m *TendermintBlockInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TendermintBlockInfo.Unmarshal(m, b) return xxx_messageInfo_TendermintBlockInfo.Unmarshal(m, b)
...@@ -283,20 +281,6 @@ func (m *TendermintBlockInfo) XXX_DiscardUnknown() { ...@@ -283,20 +281,6 @@ func (m *TendermintBlockInfo) XXX_DiscardUnknown() {
var xxx_messageInfo_TendermintBlockInfo proto.InternalMessageInfo var xxx_messageInfo_TendermintBlockInfo proto.InternalMessageInfo
func (m *TendermintBlockInfo) GetSeenCommit() *TendermintCommit {
if m != nil {
return m.SeenCommit
}
return nil
}
func (m *TendermintBlockInfo) GetLastCommit() *TendermintCommit {
if m != nil {
return m.LastCommit
}
return nil
}
func (m *TendermintBlockInfo) GetState() *State { func (m *TendermintBlockInfo) GetState() *State {
if m != nil { if m != nil {
return m.State return m.State
...@@ -331,7 +315,7 @@ func (m *BlockSize) Reset() { *m = BlockSize{} } ...@@ -331,7 +315,7 @@ func (m *BlockSize) Reset() { *m = BlockSize{} }
func (m *BlockSize) String() string { return proto.CompactTextString(m) } func (m *BlockSize) String() string { return proto.CompactTextString(m) }
func (*BlockSize) ProtoMessage() {} func (*BlockSize) ProtoMessage() {}
func (*BlockSize) Descriptor() ([]byte, []int) { func (*BlockSize) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{5} return fileDescriptor_tendermint_df861948ed10449a, []int{5}
} }
func (m *BlockSize) XXX_Unmarshal(b []byte) error { func (m *BlockSize) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BlockSize.Unmarshal(m, b) return xxx_messageInfo_BlockSize.Unmarshal(m, b)
...@@ -384,7 +368,7 @@ func (m *TxSize) Reset() { *m = TxSize{} } ...@@ -384,7 +368,7 @@ func (m *TxSize) Reset() { *m = TxSize{} }
func (m *TxSize) String() string { return proto.CompactTextString(m) } func (m *TxSize) String() string { return proto.CompactTextString(m) }
func (*TxSize) ProtoMessage() {} func (*TxSize) ProtoMessage() {}
func (*TxSize) Descriptor() ([]byte, []int) { func (*TxSize) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{6} return fileDescriptor_tendermint_df861948ed10449a, []int{6}
} }
func (m *TxSize) XXX_Unmarshal(b []byte) error { func (m *TxSize) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TxSize.Unmarshal(m, b) return xxx_messageInfo_TxSize.Unmarshal(m, b)
...@@ -429,7 +413,7 @@ func (m *BlockGossip) Reset() { *m = BlockGossip{} } ...@@ -429,7 +413,7 @@ func (m *BlockGossip) Reset() { *m = BlockGossip{} }
func (m *BlockGossip) String() string { return proto.CompactTextString(m) } func (m *BlockGossip) String() string { return proto.CompactTextString(m) }
func (*BlockGossip) ProtoMessage() {} func (*BlockGossip) ProtoMessage() {}
func (*BlockGossip) Descriptor() ([]byte, []int) { func (*BlockGossip) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{7} return fileDescriptor_tendermint_df861948ed10449a, []int{7}
} }
func (m *BlockGossip) XXX_Unmarshal(b []byte) error { func (m *BlockGossip) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BlockGossip.Unmarshal(m, b) return xxx_messageInfo_BlockGossip.Unmarshal(m, b)
...@@ -467,7 +451,7 @@ func (m *EvidenceParams) Reset() { *m = EvidenceParams{} } ...@@ -467,7 +451,7 @@ func (m *EvidenceParams) Reset() { *m = EvidenceParams{} }
func (m *EvidenceParams) String() string { return proto.CompactTextString(m) } func (m *EvidenceParams) String() string { return proto.CompactTextString(m) }
func (*EvidenceParams) ProtoMessage() {} func (*EvidenceParams) ProtoMessage() {}
func (*EvidenceParams) Descriptor() ([]byte, []int) { func (*EvidenceParams) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{8} return fileDescriptor_tendermint_df861948ed10449a, []int{8}
} }
func (m *EvidenceParams) XXX_Unmarshal(b []byte) error { func (m *EvidenceParams) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EvidenceParams.Unmarshal(m, b) return xxx_messageInfo_EvidenceParams.Unmarshal(m, b)
...@@ -508,7 +492,7 @@ func (m *ConsensusParams) Reset() { *m = ConsensusParams{} } ...@@ -508,7 +492,7 @@ func (m *ConsensusParams) Reset() { *m = ConsensusParams{} }
func (m *ConsensusParams) String() string { return proto.CompactTextString(m) } func (m *ConsensusParams) String() string { return proto.CompactTextString(m) }
func (*ConsensusParams) ProtoMessage() {} func (*ConsensusParams) ProtoMessage() {}
func (*ConsensusParams) Descriptor() ([]byte, []int) { func (*ConsensusParams) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{9} return fileDescriptor_tendermint_df861948ed10449a, []int{9}
} }
func (m *ConsensusParams) XXX_Unmarshal(b []byte) error { func (m *ConsensusParams) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConsensusParams.Unmarshal(m, b) return xxx_messageInfo_ConsensusParams.Unmarshal(m, b)
...@@ -570,7 +554,7 @@ func (m *Validator) Reset() { *m = Validator{} } ...@@ -570,7 +554,7 @@ func (m *Validator) Reset() { *m = Validator{} }
func (m *Validator) String() string { return proto.CompactTextString(m) } func (m *Validator) String() string { return proto.CompactTextString(m) }
func (*Validator) ProtoMessage() {} func (*Validator) ProtoMessage() {}
func (*Validator) Descriptor() ([]byte, []int) { func (*Validator) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{10} return fileDescriptor_tendermint_df861948ed10449a, []int{10}
} }
func (m *Validator) XXX_Unmarshal(b []byte) error { func (m *Validator) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Validator.Unmarshal(m, b) return xxx_messageInfo_Validator.Unmarshal(m, b)
...@@ -630,7 +614,7 @@ func (m *ValidatorSet) Reset() { *m = ValidatorSet{} } ...@@ -630,7 +614,7 @@ func (m *ValidatorSet) Reset() { *m = ValidatorSet{} }
func (m *ValidatorSet) String() string { return proto.CompactTextString(m) } func (m *ValidatorSet) String() string { return proto.CompactTextString(m) }
func (*ValidatorSet) ProtoMessage() {} func (*ValidatorSet) ProtoMessage() {}
func (*ValidatorSet) Descriptor() ([]byte, []int) { func (*ValidatorSet) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{11} return fileDescriptor_tendermint_df861948ed10449a, []int{11}
} }
func (m *ValidatorSet) XXX_Unmarshal(b []byte) error { func (m *ValidatorSet) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidatorSet.Unmarshal(m, b) return xxx_messageInfo_ValidatorSet.Unmarshal(m, b)
...@@ -686,7 +670,7 @@ func (m *State) Reset() { *m = State{} } ...@@ -686,7 +670,7 @@ func (m *State) Reset() { *m = State{} }
func (m *State) String() string { return proto.CompactTextString(m) } func (m *State) String() string { return proto.CompactTextString(m) }
func (*State) ProtoMessage() {} func (*State) ProtoMessage() {}
func (*State) Descriptor() ([]byte, []int) { func (*State) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{12} return fileDescriptor_tendermint_df861948ed10449a, []int{12}
} }
func (m *State) XXX_Unmarshal(b []byte) error { func (m *State) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_State.Unmarshal(m, b) return xxx_messageInfo_State.Unmarshal(m, b)
...@@ -790,144 +774,6 @@ func (m *State) GetAppHash() []byte { ...@@ -790,144 +774,6 @@ func (m *State) GetAppHash() []byte {
return nil return nil
} }
type DuplicateVoteEvidence struct {
PubKey string `protobuf:"bytes,1,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
VoteA *Vote `protobuf:"bytes,2,opt,name=voteA,proto3" json:"voteA,omitempty"`
VoteB *Vote `protobuf:"bytes,3,opt,name=voteB,proto3" json:"voteB,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DuplicateVoteEvidence) Reset() { *m = DuplicateVoteEvidence{} }
func (m *DuplicateVoteEvidence) String() string { return proto.CompactTextString(m) }
func (*DuplicateVoteEvidence) ProtoMessage() {}
func (*DuplicateVoteEvidence) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{13}
}
func (m *DuplicateVoteEvidence) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DuplicateVoteEvidence.Unmarshal(m, b)
}
func (m *DuplicateVoteEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DuplicateVoteEvidence.Marshal(b, m, deterministic)
}
func (dst *DuplicateVoteEvidence) XXX_Merge(src proto.Message) {
xxx_messageInfo_DuplicateVoteEvidence.Merge(dst, src)
}
func (m *DuplicateVoteEvidence) XXX_Size() int {
return xxx_messageInfo_DuplicateVoteEvidence.Size(m)
}
func (m *DuplicateVoteEvidence) XXX_DiscardUnknown() {
xxx_messageInfo_DuplicateVoteEvidence.DiscardUnknown(m)
}
var xxx_messageInfo_DuplicateVoteEvidence proto.InternalMessageInfo
func (m *DuplicateVoteEvidence) GetPubKey() string {
if m != nil {
return m.PubKey
}
return ""
}
func (m *DuplicateVoteEvidence) GetVoteA() *Vote {
if m != nil {
return m.VoteA
}
return nil
}
func (m *DuplicateVoteEvidence) GetVoteB() *Vote {
if m != nil {
return m.VoteB
}
return nil
}
type EvidenceEnvelope struct {
TypeName string `protobuf:"bytes,1,opt,name=typeName,proto3" json:"typeName,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EvidenceEnvelope) Reset() { *m = EvidenceEnvelope{} }
func (m *EvidenceEnvelope) String() string { return proto.CompactTextString(m) }
func (*EvidenceEnvelope) ProtoMessage() {}
func (*EvidenceEnvelope) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{14}
}
func (m *EvidenceEnvelope) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EvidenceEnvelope.Unmarshal(m, b)
}
func (m *EvidenceEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EvidenceEnvelope.Marshal(b, m, deterministic)
}
func (dst *EvidenceEnvelope) XXX_Merge(src proto.Message) {
xxx_messageInfo_EvidenceEnvelope.Merge(dst, src)
}
func (m *EvidenceEnvelope) XXX_Size() int {
return xxx_messageInfo_EvidenceEnvelope.Size(m)
}
func (m *EvidenceEnvelope) XXX_DiscardUnknown() {
xxx_messageInfo_EvidenceEnvelope.DiscardUnknown(m)
}
var xxx_messageInfo_EvidenceEnvelope proto.InternalMessageInfo
func (m *EvidenceEnvelope) GetTypeName() string {
if m != nil {
return m.TypeName
}
return ""
}
func (m *EvidenceEnvelope) GetData() []byte {
if m != nil {
return m.Data
}
return nil
}
type EvidenceData struct {
Evidence []*EvidenceEnvelope `protobuf:"bytes,1,rep,name=evidence,proto3" json:"evidence,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EvidenceData) Reset() { *m = EvidenceData{} }
func (m *EvidenceData) String() string { return proto.CompactTextString(m) }
func (*EvidenceData) ProtoMessage() {}
func (*EvidenceData) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{15}
}
func (m *EvidenceData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EvidenceData.Unmarshal(m, b)
}
func (m *EvidenceData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EvidenceData.Marshal(b, m, deterministic)
}
func (dst *EvidenceData) XXX_Merge(src proto.Message) {
xxx_messageInfo_EvidenceData.Merge(dst, src)
}
func (m *EvidenceData) XXX_Size() int {
return xxx_messageInfo_EvidenceData.Size(m)
}
func (m *EvidenceData) XXX_DiscardUnknown() {
xxx_messageInfo_EvidenceData.DiscardUnknown(m)
}
var xxx_messageInfo_EvidenceData proto.InternalMessageInfo
func (m *EvidenceData) GetEvidence() []*EvidenceEnvelope {
if m != nil {
return m.Evidence
}
return nil
}
type TendermintBlockHeader struct { type TendermintBlockHeader struct {
ChainID string `protobuf:"bytes,1,opt,name=chainID,proto3" json:"chainID,omitempty"` ChainID string `protobuf:"bytes,1,opt,name=chainID,proto3" json:"chainID,omitempty"`
Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
...@@ -941,7 +787,7 @@ type TendermintBlockHeader struct { ...@@ -941,7 +787,7 @@ type TendermintBlockHeader struct {
ConsensusHash []byte `protobuf:"bytes,10,opt,name=consensusHash,proto3" json:"consensusHash,omitempty"` ConsensusHash []byte `protobuf:"bytes,10,opt,name=consensusHash,proto3" json:"consensusHash,omitempty"`
AppHash []byte `protobuf:"bytes,11,opt,name=appHash,proto3" json:"appHash,omitempty"` AppHash []byte `protobuf:"bytes,11,opt,name=appHash,proto3" json:"appHash,omitempty"`
LastResultsHash []byte `protobuf:"bytes,12,opt,name=lastResultsHash,proto3" json:"lastResultsHash,omitempty"` LastResultsHash []byte `protobuf:"bytes,12,opt,name=lastResultsHash,proto3" json:"lastResultsHash,omitempty"`
EvidenceHash []byte `protobuf:"bytes,13,opt,name=evidenceHash,proto3" json:"evidenceHash,omitempty"` ProposerAddr []byte `protobuf:"bytes,13,opt,name=proposerAddr,proto3" json:"proposerAddr,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -951,7 +797,7 @@ func (m *TendermintBlockHeader) Reset() { *m = TendermintBlockHeader{} } ...@@ -951,7 +797,7 @@ func (m *TendermintBlockHeader) Reset() { *m = TendermintBlockHeader{} }
func (m *TendermintBlockHeader) String() string { return proto.CompactTextString(m) } func (m *TendermintBlockHeader) String() string { return proto.CompactTextString(m) }
func (*TendermintBlockHeader) ProtoMessage() {} func (*TendermintBlockHeader) ProtoMessage() {}
func (*TendermintBlockHeader) Descriptor() ([]byte, []int) { func (*TendermintBlockHeader) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{16} return fileDescriptor_tendermint_df861948ed10449a, []int{13}
} }
func (m *TendermintBlockHeader) XXX_Unmarshal(b []byte) error { func (m *TendermintBlockHeader) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TendermintBlockHeader.Unmarshal(m, b) return xxx_messageInfo_TendermintBlockHeader.Unmarshal(m, b)
...@@ -1055,19 +901,17 @@ func (m *TendermintBlockHeader) GetLastResultsHash() []byte { ...@@ -1055,19 +901,17 @@ func (m *TendermintBlockHeader) GetLastResultsHash() []byte {
return nil return nil
} }
func (m *TendermintBlockHeader) GetEvidenceHash() []byte { func (m *TendermintBlockHeader) GetProposerAddr() []byte {
if m != nil { if m != nil {
return m.EvidenceHash return m.ProposerAddr
} }
return nil return nil
} }
type TendermintBlock struct { type TendermintBlock struct {
Header *TendermintBlockHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Header *TendermintBlockHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
Txs []*types.Transaction `protobuf:"bytes,2,rep,name=txs,proto3" json:"txs,omitempty"` Data *types.Block `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
Evidence *EvidenceData `protobuf:"bytes,3,opt,name=evidence,proto3" json:"evidence,omitempty"`
LastCommit *TendermintCommit `protobuf:"bytes,4,opt,name=lastCommit,proto3" json:"lastCommit,omitempty"` LastCommit *TendermintCommit `protobuf:"bytes,4,opt,name=lastCommit,proto3" json:"lastCommit,omitempty"`
ProposerAddr []byte `protobuf:"bytes,5,opt,name=proposerAddr,proto3" json:"proposerAddr,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -1077,7 +921,7 @@ func (m *TendermintBlock) Reset() { *m = TendermintBlock{} } ...@@ -1077,7 +921,7 @@ func (m *TendermintBlock) Reset() { *m = TendermintBlock{} }
func (m *TendermintBlock) String() string { return proto.CompactTextString(m) } func (m *TendermintBlock) String() string { return proto.CompactTextString(m) }
func (*TendermintBlock) ProtoMessage() {} func (*TendermintBlock) ProtoMessage() {}
func (*TendermintBlock) Descriptor() ([]byte, []int) { func (*TendermintBlock) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{17} return fileDescriptor_tendermint_df861948ed10449a, []int{14}
} }
func (m *TendermintBlock) XXX_Unmarshal(b []byte) error { func (m *TendermintBlock) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TendermintBlock.Unmarshal(m, b) return xxx_messageInfo_TendermintBlock.Unmarshal(m, b)
...@@ -1104,16 +948,9 @@ func (m *TendermintBlock) GetHeader() *TendermintBlockHeader { ...@@ -1104,16 +948,9 @@ func (m *TendermintBlock) GetHeader() *TendermintBlockHeader {
return nil return nil
} }
func (m *TendermintBlock) GetTxs() []*types.Transaction { func (m *TendermintBlock) GetData() *types.Block {
if m != nil { if m != nil {
return m.Txs return m.Data
}
return nil
}
func (m *TendermintBlock) GetEvidence() *EvidenceData {
if m != nil {
return m.Evidence
} }
return nil return nil
} }
...@@ -1125,13 +962,6 @@ func (m *TendermintBlock) GetLastCommit() *TendermintCommit { ...@@ -1125,13 +962,6 @@ func (m *TendermintBlock) GetLastCommit() *TendermintCommit {
return nil return nil
} }
func (m *TendermintBlock) GetProposerAddr() []byte {
if m != nil {
return m.ProposerAddr
}
return nil
}
type Proposal struct { type Proposal struct {
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
Round int32 `protobuf:"varint,2,opt,name=round,proto3" json:"round,omitempty"` Round int32 `protobuf:"varint,2,opt,name=round,proto3" json:"round,omitempty"`
...@@ -1149,7 +979,7 @@ func (m *Proposal) Reset() { *m = Proposal{} } ...@@ -1149,7 +979,7 @@ func (m *Proposal) Reset() { *m = Proposal{} }
func (m *Proposal) String() string { return proto.CompactTextString(m) } func (m *Proposal) String() string { return proto.CompactTextString(m) }
func (*Proposal) ProtoMessage() {} func (*Proposal) ProtoMessage() {}
func (*Proposal) Descriptor() ([]byte, []int) { func (*Proposal) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{18} return fileDescriptor_tendermint_df861948ed10449a, []int{15}
} }
func (m *Proposal) XXX_Unmarshal(b []byte) error { func (m *Proposal) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Proposal.Unmarshal(m, b) return xxx_messageInfo_Proposal.Unmarshal(m, b)
...@@ -1233,7 +1063,7 @@ func (m *NewRoundStepMsg) Reset() { *m = NewRoundStepMsg{} } ...@@ -1233,7 +1063,7 @@ func (m *NewRoundStepMsg) Reset() { *m = NewRoundStepMsg{} }
func (m *NewRoundStepMsg) String() string { return proto.CompactTextString(m) } func (m *NewRoundStepMsg) String() string { return proto.CompactTextString(m) }
func (*NewRoundStepMsg) ProtoMessage() {} func (*NewRoundStepMsg) ProtoMessage() {}
func (*NewRoundStepMsg) Descriptor() ([]byte, []int) { func (*NewRoundStepMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{19} return fileDescriptor_tendermint_df861948ed10449a, []int{16}
} }
func (m *NewRoundStepMsg) XXX_Unmarshal(b []byte) error { func (m *NewRoundStepMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NewRoundStepMsg.Unmarshal(m, b) return xxx_messageInfo_NewRoundStepMsg.Unmarshal(m, b)
...@@ -1288,6 +1118,68 @@ func (m *NewRoundStepMsg) GetLastCommitRound() int32 { ...@@ -1288,6 +1118,68 @@ func (m *NewRoundStepMsg) GetLastCommitRound() int32 {
return 0 return 0
} }
type ValidBlockMsg struct {
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
Round int32 `protobuf:"varint,2,opt,name=round,proto3" json:"round,omitempty"`
Blockhash []byte `protobuf:"bytes,3,opt,name=blockhash,proto3" json:"blockhash,omitempty"`
IsCommit bool `protobuf:"varint,4,opt,name=isCommit,proto3" json:"isCommit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidBlockMsg) Reset() { *m = ValidBlockMsg{} }
func (m *ValidBlockMsg) String() string { return proto.CompactTextString(m) }
func (*ValidBlockMsg) ProtoMessage() {}
func (*ValidBlockMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_df861948ed10449a, []int{17}
}
func (m *ValidBlockMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidBlockMsg.Unmarshal(m, b)
}
func (m *ValidBlockMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidBlockMsg.Marshal(b, m, deterministic)
}
func (dst *ValidBlockMsg) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidBlockMsg.Merge(dst, src)
}
func (m *ValidBlockMsg) XXX_Size() int {
return xxx_messageInfo_ValidBlockMsg.Size(m)
}
func (m *ValidBlockMsg) XXX_DiscardUnknown() {
xxx_messageInfo_ValidBlockMsg.DiscardUnknown(m)
}
var xxx_messageInfo_ValidBlockMsg proto.InternalMessageInfo
func (m *ValidBlockMsg) GetHeight() int64 {
if m != nil {
return m.Height
}
return 0
}
func (m *ValidBlockMsg) GetRound() int32 {
if m != nil {
return m.Round
}
return 0
}
func (m *ValidBlockMsg) GetBlockhash() []byte {
if m != nil {
return m.Blockhash
}
return nil
}
func (m *ValidBlockMsg) GetIsCommit() bool {
if m != nil {
return m.IsCommit
}
return false
}
type CommitStepMsg struct { type CommitStepMsg struct {
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -1299,7 +1191,7 @@ func (m *CommitStepMsg) Reset() { *m = CommitStepMsg{} } ...@@ -1299,7 +1191,7 @@ func (m *CommitStepMsg) Reset() { *m = CommitStepMsg{} }
func (m *CommitStepMsg) String() string { return proto.CompactTextString(m) } func (m *CommitStepMsg) String() string { return proto.CompactTextString(m) }
func (*CommitStepMsg) ProtoMessage() {} func (*CommitStepMsg) ProtoMessage() {}
func (*CommitStepMsg) Descriptor() ([]byte, []int) { func (*CommitStepMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{20} return fileDescriptor_tendermint_df861948ed10449a, []int{18}
} }
func (m *CommitStepMsg) XXX_Unmarshal(b []byte) error { func (m *CommitStepMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CommitStepMsg.Unmarshal(m, b) return xxx_messageInfo_CommitStepMsg.Unmarshal(m, b)
...@@ -1339,7 +1231,7 @@ func (m *ProposalPOLMsg) Reset() { *m = ProposalPOLMsg{} } ...@@ -1339,7 +1231,7 @@ func (m *ProposalPOLMsg) Reset() { *m = ProposalPOLMsg{} }
func (m *ProposalPOLMsg) String() string { return proto.CompactTextString(m) } func (m *ProposalPOLMsg) String() string { return proto.CompactTextString(m) }
func (*ProposalPOLMsg) ProtoMessage() {} func (*ProposalPOLMsg) ProtoMessage() {}
func (*ProposalPOLMsg) Descriptor() ([]byte, []int) { func (*ProposalPOLMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{21} return fileDescriptor_tendermint_df861948ed10449a, []int{19}
} }
func (m *ProposalPOLMsg) XXX_Unmarshal(b []byte) error { func (m *ProposalPOLMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProposalPOLMsg.Unmarshal(m, b) return xxx_messageInfo_ProposalPOLMsg.Unmarshal(m, b)
...@@ -1394,7 +1286,7 @@ func (m *HasVoteMsg) Reset() { *m = HasVoteMsg{} } ...@@ -1394,7 +1286,7 @@ func (m *HasVoteMsg) Reset() { *m = HasVoteMsg{} }
func (m *HasVoteMsg) String() string { return proto.CompactTextString(m) } func (m *HasVoteMsg) String() string { return proto.CompactTextString(m) }
func (*HasVoteMsg) ProtoMessage() {} func (*HasVoteMsg) ProtoMessage() {}
func (*HasVoteMsg) Descriptor() ([]byte, []int) { func (*HasVoteMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{22} return fileDescriptor_tendermint_df861948ed10449a, []int{20}
} }
func (m *HasVoteMsg) XXX_Unmarshal(b []byte) error { func (m *HasVoteMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HasVoteMsg.Unmarshal(m, b) return xxx_messageInfo_HasVoteMsg.Unmarshal(m, b)
...@@ -1456,7 +1348,7 @@ func (m *VoteSetMaj23Msg) Reset() { *m = VoteSetMaj23Msg{} } ...@@ -1456,7 +1348,7 @@ func (m *VoteSetMaj23Msg) Reset() { *m = VoteSetMaj23Msg{} }
func (m *VoteSetMaj23Msg) String() string { return proto.CompactTextString(m) } func (m *VoteSetMaj23Msg) String() string { return proto.CompactTextString(m) }
func (*VoteSetMaj23Msg) ProtoMessage() {} func (*VoteSetMaj23Msg) ProtoMessage() {}
func (*VoteSetMaj23Msg) Descriptor() ([]byte, []int) { func (*VoteSetMaj23Msg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{23} return fileDescriptor_tendermint_df861948ed10449a, []int{21}
} }
func (m *VoteSetMaj23Msg) XXX_Unmarshal(b []byte) error { func (m *VoteSetMaj23Msg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VoteSetMaj23Msg.Unmarshal(m, b) return xxx_messageInfo_VoteSetMaj23Msg.Unmarshal(m, b)
...@@ -1519,7 +1411,7 @@ func (m *VoteSetBitsMsg) Reset() { *m = VoteSetBitsMsg{} } ...@@ -1519,7 +1411,7 @@ func (m *VoteSetBitsMsg) Reset() { *m = VoteSetBitsMsg{} }
func (m *VoteSetBitsMsg) String() string { return proto.CompactTextString(m) } func (m *VoteSetBitsMsg) String() string { return proto.CompactTextString(m) }
func (*VoteSetBitsMsg) ProtoMessage() {} func (*VoteSetBitsMsg) ProtoMessage() {}
func (*VoteSetBitsMsg) Descriptor() ([]byte, []int) { func (*VoteSetBitsMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{24} return fileDescriptor_tendermint_df861948ed10449a, []int{22}
} }
func (m *VoteSetBitsMsg) XXX_Unmarshal(b []byte) error { func (m *VoteSetBitsMsg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VoteSetBitsMsg.Unmarshal(m, b) return xxx_messageInfo_VoteSetBitsMsg.Unmarshal(m, b)
...@@ -1590,7 +1482,7 @@ func (m *Heartbeat) Reset() { *m = Heartbeat{} } ...@@ -1590,7 +1482,7 @@ func (m *Heartbeat) Reset() { *m = Heartbeat{} }
func (m *Heartbeat) String() string { return proto.CompactTextString(m) } func (m *Heartbeat) String() string { return proto.CompactTextString(m) }
func (*Heartbeat) ProtoMessage() {} func (*Heartbeat) ProtoMessage() {}
func (*Heartbeat) Descriptor() ([]byte, []int) { func (*Heartbeat) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{25} return fileDescriptor_tendermint_df861948ed10449a, []int{23}
} }
func (m *Heartbeat) XXX_Unmarshal(b []byte) error { func (m *Heartbeat) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Heartbeat.Unmarshal(m, b) return xxx_messageInfo_Heartbeat.Unmarshal(m, b)
...@@ -1663,7 +1555,7 @@ func (m *IsHealthy) Reset() { *m = IsHealthy{} } ...@@ -1663,7 +1555,7 @@ func (m *IsHealthy) Reset() { *m = IsHealthy{} }
func (m *IsHealthy) String() string { return proto.CompactTextString(m) } func (m *IsHealthy) String() string { return proto.CompactTextString(m) }
func (*IsHealthy) ProtoMessage() {} func (*IsHealthy) ProtoMessage() {}
func (*IsHealthy) Descriptor() ([]byte, []int) { func (*IsHealthy) Descriptor() ([]byte, []int) {
return fileDescriptor_tendermint_73641ebf19da43cb, []int{26} return fileDescriptor_tendermint_df861948ed10449a, []int{24}
} }
func (m *IsHealthy) XXX_Unmarshal(b []byte) error { func (m *IsHealthy) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IsHealthy.Unmarshal(m, b) return xxx_messageInfo_IsHealthy.Unmarshal(m, b)
...@@ -1704,13 +1596,11 @@ func init() { ...@@ -1704,13 +1596,11 @@ func init() {
proto.RegisterType((*Validator)(nil), "types.Validator") proto.RegisterType((*Validator)(nil), "types.Validator")
proto.RegisterType((*ValidatorSet)(nil), "types.ValidatorSet") proto.RegisterType((*ValidatorSet)(nil), "types.ValidatorSet")
proto.RegisterType((*State)(nil), "types.State") proto.RegisterType((*State)(nil), "types.State")
proto.RegisterType((*DuplicateVoteEvidence)(nil), "types.DuplicateVoteEvidence")
proto.RegisterType((*EvidenceEnvelope)(nil), "types.EvidenceEnvelope")
proto.RegisterType((*EvidenceData)(nil), "types.EvidenceData")
proto.RegisterType((*TendermintBlockHeader)(nil), "types.TendermintBlockHeader") proto.RegisterType((*TendermintBlockHeader)(nil), "types.TendermintBlockHeader")
proto.RegisterType((*TendermintBlock)(nil), "types.TendermintBlock") proto.RegisterType((*TendermintBlock)(nil), "types.TendermintBlock")
proto.RegisterType((*Proposal)(nil), "types.Proposal") proto.RegisterType((*Proposal)(nil), "types.Proposal")
proto.RegisterType((*NewRoundStepMsg)(nil), "types.NewRoundStepMsg") proto.RegisterType((*NewRoundStepMsg)(nil), "types.NewRoundStepMsg")
proto.RegisterType((*ValidBlockMsg)(nil), "types.ValidBlockMsg")
proto.RegisterType((*CommitStepMsg)(nil), "types.CommitStepMsg") proto.RegisterType((*CommitStepMsg)(nil), "types.CommitStepMsg")
proto.RegisterType((*ProposalPOLMsg)(nil), "types.ProposalPOLMsg") proto.RegisterType((*ProposalPOLMsg)(nil), "types.ProposalPOLMsg")
proto.RegisterType((*HasVoteMsg)(nil), "types.HasVoteMsg") proto.RegisterType((*HasVoteMsg)(nil), "types.HasVoteMsg")
...@@ -1720,100 +1610,92 @@ func init() { ...@@ -1720,100 +1610,92 @@ func init() {
proto.RegisterType((*IsHealthy)(nil), "types.IsHealthy") proto.RegisterType((*IsHealthy)(nil), "types.IsHealthy")
} }
func init() { proto.RegisterFile("tendermint.proto", fileDescriptor_tendermint_73641ebf19da43cb) } func init() { proto.RegisterFile("tendermint.proto", fileDescriptor_tendermint_df861948ed10449a) }
var fileDescriptor_tendermint_73641ebf19da43cb = []byte{ var fileDescriptor_tendermint_df861948ed10449a = []byte{
// 1472 bytes of a gzipped FileDescriptorProto // 1339 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4f, 0x73, 0x1b, 0xc5, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x6e, 0x1b, 0x45,
0x12, 0xaf, 0xb5, 0x2c, 0xd9, 0x6a, 0xc9, 0x7f, 0xde, 0xe4, 0x39, 0xd1, 0xcb, 0xf3, 0xab, 0xd2, 0x14, 0xd6, 0xc6, 0x3f, 0x89, 0x8f, 0xf3, 0xa7, 0x29, 0x2d, 0xa6, 0x04, 0xc9, 0x1a, 0xf1, 0x63,
0x9b, 0x0a, 0x20, 0x92, 0x94, 0x93, 0xb2, 0x53, 0xc5, 0x21, 0x84, 0x8a, 0x65, 0xa7, 0x62, 0x83, 0xda, 0x2a, 0x54, 0x69, 0x25, 0x2e, 0x4a, 0x51, 0x93, 0xb4, 0x6a, 0x02, 0x09, 0xb5, 0xc6, 0x56,
0x9d, 0xa8, 0x46, 0xaa, 0x70, 0x1e, 0x4b, 0x83, 0xb4, 0x20, 0xed, 0x2e, 0x3b, 0x23, 0x45, 0xa6, 0xb9, 0x9e, 0xd8, 0x83, 0xbd, 0x60, 0xef, 0x9a, 0x9d, 0xb1, 0x1b, 0x23, 0x71, 0xc3, 0x1b, 0x20,
0x8a, 0x0b, 0x07, 0xee, 0x7c, 0x10, 0x4e, 0x1c, 0xf8, 0x08, 0x7c, 0x02, 0x8e, 0xf0, 0x45, 0xb8, 0xf1, 0x04, 0xdc, 0x73, 0xc5, 0x05, 0x8f, 0xc0, 0x13, 0x70, 0x09, 0xcf, 0x82, 0xce, 0x99, 0xd9,
0x50, 0xd3, 0x33, 0xb3, 0xff, 0xa4, 0x28, 0x40, 0x51, 0xdc, 0xd4, 0x3d, 0xbf, 0x99, 0xde, 0xee, 0xf5, 0xec, 0xda, 0x4d, 0x29, 0x42, 0xdc, 0xed, 0xf9, 0xce, 0x37, 0x73, 0xf6, 0xfc, 0xce, 0x0c,
0xfe, 0x75, 0x4f, 0x8f, 0x60, 0x57, 0x89, 0x60, 0x20, 0xe2, 0x89, 0x1f, 0xa8, 0x83, 0x28, 0x0e, 0xec, 0x1a, 0x15, 0xf5, 0x55, 0x32, 0x0e, 0x23, 0xb3, 0x3f, 0x49, 0x62, 0x13, 0xb3, 0x8a, 0x99,
0x55, 0x48, 0xca, 0xea, 0x3a, 0x12, 0xf2, 0xf6, 0xbf, 0x54, 0xcc, 0x03, 0xc9, 0xfb, 0xca, 0x0f, 0x4f, 0x94, 0xbe, 0xb9, 0x7b, 0x31, 0x8a, 0x7b, 0xdf, 0xf4, 0x86, 0x32, 0x8c, 0xac, 0x82, 0xbf,
0x03, 0xb3, 0x42, 0xff, 0x07, 0x1b, 0xed, 0x71, 0xd8, 0xff, 0xe2, 0xfc, 0x94, 0x10, 0x58, 0x3f, 0x03, 0xeb, 0x47, 0x88, 0x9d, 0x3e, 0x66, 0x0c, 0xca, 0x27, 0x52, 0x0f, 0x1b, 0x41, 0x33, 0x68,
0xe3, 0x72, 0xd4, 0xf0, 0x9a, 0x5e, 0xab, 0xce, 0xf0, 0x37, 0xfd, 0x08, 0x48, 0x2f, 0x39, 0xac, 0x6d, 0x0a, 0xfa, 0xe6, 0x9f, 0x02, 0xeb, 0x66, 0x7b, 0x1d, 0x85, 0xe6, 0x30, 0x49, 0xe4, 0x1c,
0xed, 0xab, 0xe3, 0x38, 0xe6, 0xd7, 0x1a, 0xd9, 0xf6, 0x95, 0x44, 0x64, 0x99, 0xe1, 0x6f, 0xf2, 0x99, 0x47, 0xa1, 0xd1, 0xc4, 0xac, 0x08, 0xfa, 0x66, 0x6f, 0x40, 0xe5, 0xc9, 0x48, 0x8d, 0x75,
0x6f, 0x28, 0x3f, 0x1b, 0x8b, 0x89, 0x6c, 0xac, 0x35, 0x4b, 0xad, 0x75, 0x66, 0x04, 0xfa, 0xcd, 0x63, 0xad, 0x59, 0x6a, 0x95, 0x85, 0x15, 0xf8, 0x0f, 0x6b, 0x50, 0x7e, 0x1e, 0x1b, 0xc5, 0x6e,
0x1a, 0xac, 0xbf, 0x0a, 0x95, 0x20, 0x77, 0x61, 0xf7, 0x15, 0x1f, 0xfb, 0x03, 0xae, 0xc2, 0xf8, 0xc1, 0xee, 0x73, 0x39, 0x0a, 0xfb, 0xd2, 0xc4, 0xc9, 0x61, 0xbf, 0x9f, 0x28, 0xad, 0x9d, 0xa1,
0x78, 0x30, 0x88, 0x85, 0x94, 0xd6, 0xd0, 0x82, 0x9e, 0xbc, 0x0b, 0xdb, 0x89, 0xee, 0x3c, 0x18, 0x25, 0x9c, 0xbd, 0x0f, 0xdb, 0x19, 0x76, 0x1a, 0xf5, 0xd5, 0x65, 0x63, 0x8d, 0x0c, 0x15, 0x50,
0x88, 0x79, 0x63, 0x0d, 0x0d, 0x15, 0xb4, 0xe4, 0x26, 0x54, 0xce, 0x84, 0x3f, 0x1c, 0xa9, 0x46, 0x76, 0x03, 0xaa, 0x27, 0x2a, 0x1c, 0x0c, 0x4d, 0xa3, 0xd4, 0x0c, 0x5a, 0x25, 0xe1, 0x24, 0xfc,
0xa9, 0xe9, 0xb5, 0x4a, 0xcc, 0x4a, 0xfa, 0x53, 0x58, 0x38, 0x0d, 0x06, 0x8d, 0x75, 0xdc, 0x66, 0x15, 0x11, 0x4f, 0xa3, 0x7e, 0xa3, 0x4c, 0xcb, 0xac, 0xc0, 0xf6, 0xa0, 0xd6, 0x0d, 0xc7, 0x4a,
0x04, 0xb2, 0x0f, 0xd5, 0x9e, 0x3f, 0x11, 0x52, 0xf1, 0x49, 0xd4, 0x28, 0xe3, 0x86, 0x54, 0xa1, 0x1b, 0x39, 0x9e, 0x34, 0x2a, 0xb4, 0x60, 0x01, 0xa0, 0x4b, 0xdd, 0xf9, 0x44, 0x35, 0xaa, 0xcd,
0x5d, 0xea, 0x5d, 0x47, 0xa2, 0x51, 0x69, 0x7a, 0xad, 0x2d, 0x86, 0xbf, 0x49, 0x2b, 0x89, 0x4d, 0xa0, 0xb5, 0x25, 0xe8, 0x9b, 0xb5, 0xb2, 0xd8, 0x34, 0xd6, 0x9b, 0x41, 0xab, 0x7e, 0xb0, 0xbd,
0x63, 0xa3, 0xe9, 0xb5, 0x6a, 0x87, 0xdb, 0x07, 0x18, 0xc7, 0x03, 0xab, 0x65, 0x49, 0xe8, 0xf6, 0x4f, 0x61, 0xdc, 0x77, 0xa8, 0xc8, 0x42, 0xb7, 0x07, 0xb5, 0x4e, 0x38, 0x88, 0xa4, 0x99, 0x26,
0xa1, 0xda, 0xf5, 0x87, 0x01, 0x57, 0xd3, 0x58, 0x34, 0x36, 0xd1, 0xad, 0x54, 0x41, 0x7d, 0xd8, 0xaa, 0xb1, 0x41, 0x6e, 0x2d, 0x00, 0x1e, 0xc2, 0xee, 0x22, 0x88, 0xc7, 0xf1, 0x78, 0x1c, 0x1a,
0x4d, 0x83, 0x78, 0x12, 0x4e, 0x26, 0xbe, 0xca, 0x9e, 0xed, 0xad, 0x3e, 0xfb, 0x1e, 0x40, 0x27, 0x7f, 0xef, 0xe0, 0xea, 0xbd, 0x6f, 0x03, 0xb4, 0x13, 0xd5, 0xa3, 0x65, 0x36, 0xba, 0xf5, 0x83,
0x16, 0x7d, 0xdc, 0x66, 0xa2, 0x5b, 0x3b, 0xac, 0x59, 0xb0, 0x0e, 0x2d, 0xcb, 0x2c, 0xd3, 0x6f, 0xba, 0x23, 0x63, 0x68, 0x85, 0xa7, 0xe6, 0x3f, 0x05, 0x70, 0xcd, 0x4b, 0x18, 0x6d, 0x11, 0x7d,
0xd7, 0xe0, 0x46, 0x26, 0x61, 0x78, 0x44, 0xf0, 0x59, 0x48, 0x3e, 0x00, 0xe8, 0x0a, 0x11, 0x18, 0x15, 0x33, 0x0e, 0x95, 0x8e, 0x91, 0x46, 0x51, 0x24, 0xeb, 0x07, 0x9b, 0x6e, 0x3d, 0x61, 0xc2,
0xe3, 0xd6, 0xe2, 0x2d, 0x7b, 0x48, 0xf1, 0xdb, 0x58, 0x06, 0xaa, 0x37, 0x5e, 0x70, 0x69, 0x57, 0xaa, 0xd8, 0x6d, 0xd8, 0x68, 0x27, 0xf1, 0x24, 0xd6, 0x72, 0x44, 0x01, 0xad, 0x1f, 0xec, 0x38,
0x30, 0x0f, 0xab, 0x36, 0xa6, 0x50, 0x42, 0xa1, 0xdc, 0x55, 0x5c, 0x09, 0xcc, 0x4d, 0xed, 0xb0, 0x5a, 0x0a, 0x8b, 0x8c, 0xc0, 0xee, 0x40, 0x85, 0x6a, 0x89, 0x62, 0x5c, 0x3f, 0xb8, 0xe1, 0x98,
0x6e, 0xf7, 0xa0, 0x8e, 0x99, 0x25, 0x72, 0x0f, 0x36, 0x3b, 0x71, 0x18, 0x85, 0x92, 0x8f, 0x31, 0x05, 0xdb, 0xc2, 0x92, 0xf8, 0x97, 0x50, 0x23, 0xb9, 0x13, 0x7e, 0xa7, 0xd8, 0x4d, 0xd8, 0x38,
0x57, 0xb5, 0xc3, 0x1d, 0x0b, 0x73, 0x6a, 0x96, 0x00, 0xc8, 0x7d, 0x28, 0x5f, 0x69, 0x7f, 0x30, 0x97, 0x97, 0x47, 0x73, 0xa3, 0xd2, 0x0a, 0xca, 0x64, 0x4c, 0xe9, 0xb9, 0xbc, 0xec, 0x5e, 0x6a,
0x77, 0xb5, 0xc3, 0x9b, 0x0b, 0x1f, 0x81, 0xde, 0x32, 0x03, 0xa2, 0x9f, 0x42, 0x15, 0xe5, 0xae, 0x97, 0x72, 0x27, 0x39, 0xfc, 0xa9, 0xd4, 0x69, 0xaa, 0xad, 0xc4, 0x3f, 0x81, 0x6a, 0xf7, 0xf2,
0xff, 0x95, 0x20, 0xb7, 0x61, 0xf3, 0x92, 0xcf, 0xdb, 0xd7, 0x4a, 0x38, 0xce, 0x26, 0xb2, 0x26, 0x1f, 0xee, 0x8a, 0xab, 0xd7, 0x72, 0xab, 0x1f, 0x42, 0x9d, 0x7e, 0xeb, 0x69, 0xac, 0x75, 0x38,
0xd1, 0x25, 0x9f, 0xf7, 0xe6, 0xd2, 0x92, 0xcc, 0x4a, 0x56, 0xff, 0x9c, 0x4b, 0x47, 0x2e, 0x23, 0x61, 0xfb, 0xc0, 0x48, 0x6c, 0xcb, 0xc4, 0xe0, 0x9e, 0xfe, 0x66, 0x2b, 0x34, 0xbc, 0x05, 0xdb,
0xd1, 0x0f, 0xa1, 0xd2, 0x9b, 0xff, 0xc1, 0x53, 0xf5, 0xee, 0xb5, 0xdc, 0xee, 0x27, 0x50, 0xc3, 0x4f, 0x66, 0x61, 0x5f, 0x45, 0x3d, 0xd5, 0x96, 0x89, 0x1c, 0xa7, 0x86, 0x0e, 0x07, 0x8a, 0x56,
0xcf, 0x7a, 0x1e, 0x4a, 0xe9, 0x47, 0xe4, 0x00, 0x08, 0x8a, 0x1d, 0x1e, 0x2b, 0x7d, 0x66, 0xf6, 0x59, 0x43, 0x87, 0x03, 0xc5, 0xff, 0x0c, 0x60, 0xe7, 0x38, 0x8e, 0xb4, 0x8a, 0xf4, 0x54, 0x3b,
0xb0, 0x25, 0x2b, 0xb4, 0x05, 0xdb, 0xcf, 0x66, 0xfe, 0x40, 0x04, 0x7d, 0xd1, 0xe1, 0x31, 0x9f, 0xee, 0xbe, 0x17, 0x13, 0x57, 0x03, 0xbb, 0x7e, 0x0d, 0x20, 0x2e, 0xbc, 0xb0, 0xbd, 0x97, 0xba,
0x38, 0x43, 0xc7, 0x43, 0x81, 0xbb, 0x8c, 0xa1, 0xe3, 0xa1, 0xa0, 0xbf, 0x78, 0xb0, 0x73, 0x12, 0xea, 0x72, 0xb8, 0x95, 0x86, 0x9c, 0x40, 0x91, 0xc6, 0xe1, 0x7e, 0xce, 0x27, 0x97, 0x48, 0xe6,
0x06, 0x52, 0x04, 0x72, 0x2a, 0x2d, 0xf6, 0x20, 0x13, 0x13, 0xcb, 0x81, 0xdd, 0x2c, 0xeb, 0xb4, 0x6f, 0x6c, 0x35, 0x22, 0xe7, 0xfa, 0xc3, 0xa2, 0x2b, 0x2e, 0xaf, 0xd7, 0xdd, 0xc2, 0xbc, 0x52,
0x9e, 0x65, 0xc2, 0xf6, 0x8e, 0x73, 0xd5, 0xe6, 0x7d, 0xcb, 0x85, 0x1c, 0x95, 0xcc, 0xc5, 0xe1, 0x14, 0xc8, 0x7c, 0x0a, 0xb5, 0xac, 0x37, 0x59, 0x03, 0xd6, 0xf3, 0x1d, 0x9e, 0x8a, 0x18, 0x9e,
0x51, 0xce, 0x27, 0x9b, 0x6f, 0x92, 0x3d, 0xd8, 0xac, 0xb0, 0x9c, 0xeb, 0x4f, 0x8a, 0xae, 0x58, 0xf6, 0xf4, 0xe2, 0x73, 0x35, 0x27, 0x17, 0x36, 0x85, 0x93, 0x58, 0x13, 0xea, 0xcf, 0x63, 0x13,
0x06, 0xec, 0xd9, 0x8d, 0xf9, 0x45, 0x56, 0x00, 0xd3, 0x29, 0x54, 0x93, 0x6e, 0x40, 0x1a, 0xb0, 0x46, 0x83, 0x76, 0xfc, 0x42, 0x25, 0x2e, 0xc5, 0x3e, 0x84, 0x2d, 0x7d, 0xd8, 0xeb, 0x4d, 0xc7,
0x91, 0xef, 0x29, 0x4e, 0xd4, 0xe1, 0xe9, 0x4c, 0xaf, 0x3e, 0x11, 0xd7, 0xe8, 0x42, 0x9d, 0x59, 0xf4, 0x5b, 0x25, 0x61, 0x05, 0x1e, 0xc1, 0x66, 0x66, 0xb6, 0xa3, 0x0c, 0xbb, 0x0b, 0x90, 0xc9,
0x89, 0x34, 0xa1, 0xf6, 0x2a, 0x54, 0x7e, 0x30, 0xec, 0x84, 0xaf, 0x45, 0x6c, 0x53, 0x9c, 0x55, 0x68, 0xbc, 0xe4, 0xc5, 0x34, 0x53, 0x08, 0x8f, 0xc3, 0xee, 0xa4, 0x35, 0xaf, 0x12, 0x17, 0xd6,
0xe9, 0x26, 0x72, 0xdc, 0xef, 0x4f, 0x27, 0xf8, 0x59, 0x25, 0x66, 0x04, 0x1a, 0x40, 0x3d, 0x31, 0x65, 0x7e, 0xc6, 0xe0, 0x7f, 0x94, 0x5d, 0x1b, 0xa1, 0x8f, 0xc7, 0x38, 0x45, 0x5d, 0xfb, 0xd6,
0xdb, 0x15, 0x8a, 0x3c, 0x04, 0x48, 0x64, 0x6d, 0xbc, 0x94, 0x89, 0x69, 0xb2, 0xc0, 0x32, 0x18, 0x44, 0x2a, 0xb2, 0x16, 0xec, 0x9c, 0x49, 0x6d, 0xcb, 0xdf, 0x4d, 0x27, 0x5b, 0x74, 0x45, 0x18,
0x72, 0xdf, 0x71, 0x5e, 0xc4, 0x36, 0xac, 0x8b, 0xf8, 0x04, 0x41, 0x7f, 0x5e, 0xb7, 0x65, 0xa4, 0x47, 0x62, 0x06, 0x75, 0x63, 0x23, 0x47, 0xdd, 0x4b, 0xe7, 0xfa, 0x12, 0xce, 0xee, 0x42, 0x3d,
0x7d, 0x3c, 0x19, 0x71, 0x3f, 0xb0, 0x0d, 0xa3, 0xca, 0x9c, 0x48, 0x5a, 0xb0, 0xa3, 0xeb, 0x0e, 0xc3, 0x4e, 0x1f, 0xbb, 0xe4, 0x14, 0x47, 0x86, 0x4f, 0x61, 0xef, 0xc2, 0xd6, 0x62, 0x97, 0x70,
0x83, 0x6b, 0xfb, 0xa1, 0x21, 0x5d, 0x51, 0xad, 0x9b, 0x70, 0xa2, 0xea, 0x85, 0x8a, 0x8f, 0x7b, 0xac, 0xdc, 0xc8, 0xcb, 0x83, 0xec, 0x5e, 0x2e, 0x62, 0x55, 0xda, 0xf6, 0x5a, 0x31, 0x02, 0x1d,
0x73, 0xeb, 0xfa, 0x82, 0x9e, 0x3c, 0x84, 0x5a, 0xa2, 0x3b, 0x3f, 0xb5, 0xc9, 0x29, 0x36, 0xa9, 0x65, 0x72, 0x41, 0x7b, 0x00, 0xdb, 0xb8, 0x8b, 0xb7, 0x70, 0xfd, 0xe5, 0x0b, 0x0b, 0x54, 0xf6,
0x2c, 0x84, 0xdc, 0x81, 0xad, 0xf4, 0x14, 0x7f, 0x22, 0x6c, 0x93, 0xcd, 0x2b, 0xc9, 0x51, 0x2e, 0x08, 0xde, 0x46, 0xc4, 0xc6, 0x60, 0x81, 0x1f, 0x0f, 0x65, 0x34, 0x50, 0x7d, 0x1a, 0x9e, 0x25,
0x62, 0x15, 0x3c, 0xf6, 0x46, 0x31, 0x02, 0x5d, 0xa1, 0x72, 0x41, 0x7b, 0x0c, 0xdb, 0xfa, 0x94, 0x71, 0x15, 0x85, 0x3d, 0x5a, 0xea, 0xa5, 0x46, 0x2d, 0x37, 0x84, 0x0a, 0x5a, 0xb1, 0xd4, 0x7a,
0xcc, 0xc6, 0x8d, 0x37, 0x6f, 0x2c, 0x40, 0xc9, 0x53, 0xf8, 0xaf, 0xd6, 0x98, 0x18, 0xa4, 0xfa, 0x9f, 0x41, 0x73, 0x61, 0xa0, 0xa0, 0x4c, 0x7f, 0x04, 0xe8, 0x47, 0x5e, 0xc9, 0x4b, 0xf3, 0x2d,
0x93, 0x11, 0x0f, 0x86, 0x62, 0x80, 0xed, 0xba, 0xc4, 0x56, 0x41, 0xc8, 0xd3, 0x85, 0x5a, 0x6a, 0x94, 0x9e, 0x8e, 0x8c, 0xa6, 0x03, 0xb4, 0x4e, 0xc5, 0x5d, 0x84, 0xa9, 0x2f, 0x26, 0x13, 0x62,
0x54, 0x73, 0x4d, 0xa8, 0xb0, 0xca, 0x16, 0x4a, 0xef, 0x63, 0x68, 0xa6, 0x06, 0x0a, 0x8b, 0xee, 0x6c, 0xba, 0xbe, 0xb0, 0x22, 0xff, 0xad, 0x04, 0xd7, 0x0b, 0x93, 0xf3, 0x44, 0xc9, 0xbe, 0xa2,
0x43, 0x00, 0x3f, 0xe4, 0xad, 0x38, 0x97, 0x6f, 0x26, 0xe4, 0x74, 0xac, 0x24, 0x5e, 0xd9, 0x35, 0x5e, 0xea, 0xe5, 0xeb, 0xcc, 0x89, 0xd8, 0x4b, 0x43, 0xbf, 0xbc, 0x9c, 0x84, 0x9d, 0x92, 0xd0,
0x24, 0x77, 0x51, 0x8d, 0x75, 0x11, 0x45, 0x88, 0xa8, 0xdb, 0xba, 0x30, 0x22, 0x9d, 0xc2, 0xde, 0xe1, 0x67, 0x4b, 0xc9, 0x0a, 0x78, 0xbc, 0x19, 0x2c, 0x02, 0xdb, 0x3e, 0xf4, 0x8d, 0x3b, 0x44,
0xe9, 0x34, 0x1a, 0xfb, 0x7d, 0xae, 0x84, 0xbe, 0x44, 0x5c, 0x75, 0xe9, 0x82, 0x89, 0x4c, 0xc1, 0xd3, 0x31, 0xce, 0x5a, 0x5b, 0x1a, 0x4e, 0xc2, 0x5a, 0x1b, 0x79, 0xb5, 0x56, 0x5d, 0x5d, 0x6b,
0x18, 0x96, 0x59, 0x89, 0xfc, 0x1f, 0xca, 0xb3, 0x50, 0x89, 0x63, 0xcb, 0xd9, 0xdc, 0x05, 0x64, 0x1e, 0x05, 0x67, 0xaf, 0xb1, 0x85, 0x6a, 0x4b, 0xa1, 0x24, 0x32, 0x19, 0x0f, 0x73, 0xa4, 0xda,
0x56, 0x1c, 0xa4, 0x6d, 0x3b, 0xc0, 0x22, 0xa4, 0x4d, 0xdb, 0xb0, 0xeb, 0x2c, 0x3d, 0x0b, 0x66, 0x63, 0x8f, 0x9c, 0xb7, 0xe7, 0x63, 0x01, 0x45, 0xde, 0x2c, 0x4b, 0x35, 0xf1, 0x6a, 0x96, 0x97,
0x62, 0x1c, 0x46, 0xd8, 0x46, 0x35, 0xf0, 0x05, 0x9f, 0x08, 0x6b, 0x33, 0x91, 0xf5, 0xad, 0x3c, 0x47, 0xb1, 0xae, 0x7b, 0x69, 0x26, 0x88, 0x06, 0x44, 0xcb, 0x83, 0x18, 0x37, 0xe9, 0x62, 0x6d,
0xe0, 0x8a, 0xdb, 0xe2, 0xc5, 0xdf, 0xf4, 0x04, 0xea, 0xee, 0x8c, 0x53, 0xae, 0x38, 0x39, 0x82, 0xb3, 0x91, 0x8a, 0x98, 0xaf, 0x51, 0x21, 0x5f, 0x36, 0x1b, 0x45, 0x98, 0x71, 0xd8, 0x9c, 0xb8,
0x4d, 0x61, 0x65, 0x5b, 0x80, 0xb7, 0x0a, 0x2d, 0xc4, 0x99, 0x62, 0x09, 0x90, 0xfe, 0x58, 0x82, 0xce, 0xc7, 0x01, 0xd6, 0xd8, 0x22, 0x5a, 0x0e, 0xe3, 0x3f, 0x07, 0xb0, 0x53, 0xc8, 0x1c, 0xbb,
0xbd, 0xc2, 0xcd, 0x71, 0x26, 0xf8, 0x40, 0x60, 0x2f, 0xe9, 0xe7, 0xeb, 0xcc, 0x8a, 0x3a, 0x34, 0x8f, 0x99, 0xc1, 0xec, 0xb9, 0xa9, 0xbe, 0xb7, 0xfa, 0x6c, 0xb4, 0x19, 0x16, 0x8e, 0xcb, 0x9a,
0xa3, 0x6c, 0x79, 0x59, 0x49, 0x77, 0x8a, 0x18, 0xc7, 0x0d, 0x53, 0x4a, 0x46, 0xd0, 0x9f, 0xae, 0x50, 0xee, 0x4b, 0x23, 0x0b, 0x07, 0xb4, 0x3d, 0x45, 0x49, 0xc3, 0x3e, 0x06, 0x58, 0xc4, 0xcc,
0x74, 0x11, 0x98, 0xf6, 0x81, 0xbf, 0xf5, 0x09, 0xc1, 0x74, 0xa2, 0xef, 0x1a, 0x53, 0x1a, 0x56, 0x8d, 0x80, 0x37, 0x97, 0xf6, 0xb6, 0x6a, 0xe1, 0x51, 0xf9, 0x5f, 0xc1, 0xe2, 0x64, 0xf7, 0xea,
0xd2, 0xb5, 0x36, 0xce, 0xd4, 0x5a, 0x65, 0x79, 0xad, 0x65, 0x20, 0x18, 0x34, 0x53, 0xa8, 0xa6, 0x26, 0x58, 0x5d, 0x37, 0xf6, 0xe0, 0x75, 0x75, 0xb3, 0x07, 0x35, 0x93, 0x5d, 0x9a, 0x6c, 0x45,
0x14, 0x4a, 0x2c, 0x91, 0xf5, 0xf8, 0x34, 0x4e, 0xee, 0x61, 0x4c, 0xbe, 0x99, 0x48, 0x0a, 0x5a, 0x2d, 0x00, 0xcc, 0x7b, 0xfb, 0xd9, 0x99, 0x7f, 0xd7, 0xca, 0x64, 0xb6, 0x0f, 0xd0, 0x7e, 0x76,
0x8d, 0x9b, 0x25, 0x54, 0x47, 0x5c, 0xd5, 0xe0, 0xf2, 0x5a, 0x5d, 0xd7, 0x7d, 0xc7, 0x44, 0x84, 0x96, 0x16, 0x51, 0x65, 0x65, 0x11, 0x79, 0x0c, 0xb4, 0xa4, 0xb3, 0x2b, 0x54, 0xd5, 0x5e, 0xa1,
0x01, 0xc2, 0xf2, 0x4a, 0x1d, 0x37, 0x6e, 0xb9, 0x66, 0xd8, 0xe8, 0x44, 0xcd, 0xd7, 0x71, 0x81, 0x32, 0x00, 0xb5, 0x74, 0x93, 0x18, 0x62, 0xbe, 0xd6, 0xad, 0x36, 0x03, 0xf8, 0xaf, 0x01, 0xec,
0xaf, 0x86, 0x8d, 0x45, 0x35, 0xa1, 0x50, 0x77, 0x19, 0x42, 0xd8, 0x16, 0xc2, 0x72, 0x3a, 0xfa, 0x7c, 0xa1, 0x5e, 0x90, 0xe1, 0x8e, 0x51, 0x93, 0x73, 0x3d, 0x78, 0x4d, 0x3f, 0x19, 0x94, 0xb5,
0x9b, 0x07, 0x3b, 0x85, 0xcc, 0x91, 0x47, 0x3a, 0x33, 0x3a, 0x7b, 0xf6, 0x56, 0xdb, 0x5f, 0x3e, 0x51, 0xd6, 0xc5, 0x8a, 0xa0, 0x6f, 0x76, 0x1f, 0xae, 0x6b, 0xd5, 0x8b, 0xa3, 0xbe, 0xee, 0x84,
0x1b, 0x98, 0x0c, 0x33, 0x8b, 0x25, 0x77, 0xa0, 0xa4, 0xe6, 0x6e, 0xa2, 0x72, 0xf7, 0x55, 0x2f, 0x51, 0x4f, 0x75, 0x8c, 0x4c, 0x4c, 0x37, 0x6d, 0xa2, 0x8a, 0x58, 0xad, 0x4c, 0xeb, 0xcb, 0xa5,
0x9d, 0x90, 0x99, 0x5e, 0x26, 0x0f, 0x32, 0xf4, 0x2a, 0xe5, 0x9a, 0x4e, 0x96, 0x85, 0x29, 0xb5, 0x81, 0x2c, 0x55, 0x88, 0x5f, 0x84, 0xf9, 0x0b, 0xd8, 0xa2, 0xe1, 0x46, 0x11, 0x78, 0xfd, 0x5f,
0xf4, 0xc4, 0x94, 0x06, 0xda, 0xf6, 0xcd, 0x37, 0x4f, 0x4c, 0xe3, 0xec, 0xc4, 0x54, 0x8f, 0x6c, 0xce, 0x85, 0xa4, 0x54, 0x08, 0x09, 0xa6, 0x26, 0xd4, 0x5e, 0xa9, 0x6c, 0x88, 0x4c, 0xe6, 0x1f,
0xdf, 0xd7, 0xd7, 0x17, 0x72, 0xa4, 0xce, 0x72, 0x3a, 0xfa, 0xab, 0x97, 0x8e, 0x4c, 0x19, 0x42, 0xc0, 0x96, 0xfd, 0x7a, 0x45, 0xac, 0xf8, 0x8f, 0x01, 0x6c, 0xa7, 0x85, 0xd3, 0x7e, 0x76, 0x76,
0x7a, 0xcb, 0x09, 0x69, 0x26, 0x1a, 0x4b, 0xc8, 0x7d, 0xa8, 0xaa, 0x64, 0xfe, 0x35, 0x54, 0x4d, 0xd5, 0x3f, 0xde, 0x82, 0xdd, 0xc9, 0x82, 0x29, 0xbc, 0xdf, 0x5d, 0xc2, 0xd9, 0x03, 0xa8, 0x7b,
0x15, 0x9a, 0x50, 0x9d, 0x97, 0x17, 0xd9, 0xb1, 0x39, 0x91, 0xc9, 0x01, 0x40, 0xe7, 0xe5, 0x85, 0x98, 0xbb, 0xa2, 0xbc, 0xb5, 0xdc, 0x25, 0xee, 0xb9, 0x21, 0x7c, 0x36, 0xef, 0x03, 0x9c, 0x48,
0x63, 0x67, 0x79, 0x29, 0x3b, 0x33, 0x08, 0x6d, 0x49, 0x26, 0xd3, 0x70, 0xc5, 0x4c, 0xc3, 0x89, 0x8d, 0x17, 0xdf, 0x7f, 0x95, 0x65, 0x34, 0x92, 0x66, 0x19, 0xbf, 0x91, 0x19, 0xd2, 0x1b, 0xc3,
0x42, 0xaf, 0xe2, 0x88, 0x36, 0xd2, 0x19, 0xde, 0x30, 0xab, 0x89, 0x82, 0xfe, 0xe0, 0xc1, 0xce, 0x3d, 0x16, 0x48, 0xe0, 0xdf, 0xc3, 0x0e, 0x9a, 0xe8, 0x28, 0x73, 0x2e, 0xbf, 0x3e, 0xb8, 0xf7,
0x0b, 0xf1, 0x1a, 0x0d, 0x77, 0x95, 0x88, 0x2e, 0xe5, 0xf0, 0x4f, 0xfa, 0x49, 0x60, 0x5d, 0x2a, 0xdf, 0x98, 0x6a, 0xc1, 0xfa, 0xc5, 0x95, 0x07, 0x78, 0xaa, 0xe6, 0xbf, 0x04, 0xb0, 0xed, 0xec,
0x61, 0x5c, 0x2c, 0x33, 0xfc, 0x4d, 0x1e, 0xc1, 0x9e, 0x14, 0xfd, 0x30, 0x18, 0xc8, 0xae, 0x1f, 0xe3, 0xe3, 0xea, 0x7f, 0x36, 0xcf, 0x3e, 0x82, 0xca, 0x2c, 0xc6, 0xbb, 0x6f, 0xe5, 0x55, 0xa9,
0xf4, 0x45, 0x57, 0xf1, 0x58, 0xf5, 0x5c, 0x75, 0x96, 0xd9, 0xf2, 0x45, 0x47, 0x5c, 0x9b, 0x2a, 0xb1, 0x3c, 0xfe, 0x7b, 0x00, 0xb5, 0x13, 0x25, 0x13, 0x73, 0xa1, 0x24, 0xd5, 0xc2, 0xec, 0x25,
0xb4, 0x54, 0x46, 0x7c, 0x51, 0x4d, 0xdf, 0x83, 0x2d, 0x23, 0xbe, 0xe5, 0x93, 0xe9, 0x77, 0x1e, 0x6f, 0xbd, 0xd9, 0x8a, 0xb7, 0xde, 0x6c, 0xe5, 0x5b, 0x6f, 0xb6, 0xf4, 0xd6, 0x1b, 0xe6, 0xde,
0x6c, 0xbb, 0xfc, 0x75, 0x5e, 0x5e, 0xac, 0xf2, 0xee, 0x2e, 0xec, 0x46, 0x29, 0x92, 0x65, 0x1c, 0x7a, 0x45, 0xf7, 0xcb, 0xbe, 0xfb, 0x37, 0x61, 0x43, 0xab, 0x6f, 0xa7, 0x78, 0x43, 0x75, 0xdd,
0x5d, 0xd0, 0x93, 0xc7, 0x50, 0xcb, 0xe8, 0x2c, 0x4f, 0xff, 0xb3, 0x58, 0x05, 0xf6, 0x01, 0xc7, 0x97, 0xc9, 0x57, 0x0f, 0x1a, 0xfe, 0x21, 0xd4, 0x4e, 0xf5, 0x89, 0x92, 0x23, 0x33, 0x9c, 0x23,
0xb2, 0x68, 0x3a, 0x00, 0x38, 0xe3, 0x52, 0xb7, 0xe9, 0xbf, 0x14, 0x6c, 0x6d, 0xc4, 0x05, 0x5b, 0x35, 0x4c, 0x05, 0xf2, 0x60, 0x43, 0x2c, 0x80, 0x8b, 0x2a, 0xbd, 0xa0, 0xef, 0xfd, 0x1d, 0x00,
0xff, 0xd6, 0x48, 0x1f, 0x5f, 0x6d, 0xf6, 0xf9, 0x85, 0x02, 0xfd, 0x1a, 0x76, 0xb4, 0x89, 0xae, 0x00, 0xff, 0xff, 0xe7, 0xeb, 0xd6, 0x7a, 0x6e, 0x0f, 0x00, 0x00,
0x50, 0x97, 0xfc, 0xf3, 0xc3, 0xa3, 0xbf, 0xc7, 0x54, 0x0b, 0x36, 0xae, 0x56, 0x0e, 0x28, 0x6e,
0x99, 0x7e, 0xef, 0xc1, 0xb6, 0xb5, 0xaf, 0x9f, 0xab, 0xff, 0xb0, 0x79, 0xf2, 0xc0, 0xdc, 0x8d,
0xd2, 0x56, 0xcf, 0x8a, 0xd4, 0x18, 0x1c, 0xfd, 0xc9, 0x83, 0xea, 0x99, 0xe0, 0xb1, 0xba, 0x12,
0x1c, 0xb9, 0x30, 0x7b, 0xc3, 0xeb, 0x79, 0xb6, 0xe4, 0xf5, 0x3c, 0x5b, 0xfa, 0x7a, 0x9e, 0x2d,
0xbc, 0x9e, 0x47, 0xb9, 0xd7, 0x73, 0xd1, 0xfd, 0xf5, 0xac, 0xfb, 0xb7, 0x61, 0x53, 0x8a, 0x2f,
0xa7, 0xd8, 0x06, 0x4d, 0x11, 0x24, 0xf2, 0xea, 0x7a, 0xa7, 0xef, 0x43, 0xf5, 0x5c, 0x9e, 0x09,
0x3e, 0x56, 0xa3, 0x6b, 0x0d, 0xf5, 0x9d, 0x80, 0x1e, 0x6c, 0xb2, 0x54, 0x71, 0x55, 0xc1, 0xff,
0x24, 0x8e, 0x7e, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x20, 0x41, 0x55, 0xc1, 0x10, 0x00, 0x00,
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment