mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-29 14:11:21 +00:00
ProposalPOLRound...
This commit is contained in:
parent
3db63477aa
commit
9b96e2e171
@ -62,7 +62,7 @@ func (bs *BlockStore) LoadBlock(height uint) *types.Block {
|
|||||||
panic(Fmt("Error reading block meta: %v", err))
|
panic(Fmt("Error reading block meta: %v", err))
|
||||||
}
|
}
|
||||||
bytez := []byte{}
|
bytez := []byte{}
|
||||||
for i := uint(0); i < meta.Parts.Total; i++ {
|
for i := uint(0); i < meta.PartsHeader.Total; i++ {
|
||||||
part := bs.LoadBlockPart(height, i)
|
part := bs.LoadBlockPart(height, i)
|
||||||
bytez = append(bytez, part.Bytes...)
|
bytez = append(bytez, part.Bytes...)
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,10 @@ type HeightVoteSet struct {
|
|||||||
|
|
||||||
func NewHeightVoteSet(height uint, valSet *sm.ValidatorSet) *HeightVoteSet {
|
func NewHeightVoteSet(height uint, valSet *sm.ValidatorSet) *HeightVoteSet {
|
||||||
hvs := &HeightVoteSet{
|
hvs := &HeightVoteSet{
|
||||||
height: height,
|
height: height,
|
||||||
valSet: valSet,
|
valSet: valSet,
|
||||||
roundVoteSets: make(map[uint]RoundVoteSet),
|
roundVoteSets: make(map[uint]RoundVoteSet),
|
||||||
peerFFPrevotes: make(map[string]*VoteSet),
|
peerFastForward: make(map[string]uint),
|
||||||
}
|
}
|
||||||
hvs.SetRound(0)
|
hvs.SetRound(0)
|
||||||
return hvs
|
return hvs
|
||||||
@ -64,7 +64,7 @@ func (hvs *HeightVoteSet) SetRound(round uint) {
|
|||||||
panic("SetRound() must increment hvs.round")
|
panic("SetRound() must increment hvs.round")
|
||||||
}
|
}
|
||||||
for r := hvs.round + 1; r <= round; r++ {
|
for r := hvs.round + 1; r <= round; r++ {
|
||||||
if _, ok := hvs.roundVoteSet[r]; ok {
|
if _, ok := hvs.roundVoteSets[r]; ok {
|
||||||
continue // Already exists because peerFastForward.
|
continue // Already exists because peerFastForward.
|
||||||
}
|
}
|
||||||
hvs.addRound(round)
|
hvs.addRound(round)
|
||||||
@ -73,18 +73,18 @@ func (hvs *HeightVoteSet) SetRound(round uint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hvs *HeightVoteSet) addRound(round uint) {
|
func (hvs *HeightVoteSet) addRound(round uint) {
|
||||||
if _, ok := hvs.roundVoteSet[r]; ok {
|
if _, ok := hvs.roundVoteSets[round]; ok {
|
||||||
panic("addRound() for an existing round")
|
panic("addRound() for an existing round")
|
||||||
}
|
}
|
||||||
prevotes := NewVoteSet(hvs.height, r, types.VoteTypePrevote, hvs.valSet)
|
prevotes := NewVoteSet(hvs.height, round, types.VoteTypePrevote, hvs.valSet)
|
||||||
precommits := NewVoteSet(hvs.height, r, types.VoteTypePrecommit, hvs.valSet)
|
precommits := NewVoteSet(hvs.height, round, types.VoteTypePrecommit, hvs.valSet)
|
||||||
hvs.roundVoteSets[r] = RoundVoteSet{
|
hvs.roundVoteSets[round] = RoundVoteSet{
|
||||||
Prevotes: prevotes,
|
Prevotes: prevotes,
|
||||||
Precommits: precommits,
|
Precommits: precommits,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONTRACT: if err == nil, added == true
|
// Duplicate votes return added=false, err=nil.
|
||||||
func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peer string) (added bool, index uint, err error) {
|
func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peer string) (added bool, index uint, err error) {
|
||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
@ -92,7 +92,7 @@ func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peer st
|
|||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
if _, ok := hvs.peerFastForward[peer]; !ok {
|
if _, ok := hvs.peerFastForward[peer]; !ok {
|
||||||
hvs.addRound(vote.Round)
|
hvs.addRound(vote.Round)
|
||||||
hvs.peerFastForwards[peer] = vote.Round
|
hvs.peerFastForward[peer] = vote.Round
|
||||||
} else {
|
} else {
|
||||||
// Peer has sent a vote that does not match our round,
|
// Peer has sent a vote that does not match our round,
|
||||||
// for more than one round. Bad peer!
|
// for more than one round. Bad peer!
|
||||||
|
@ -164,13 +164,11 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
|||||||
case *ProposalMessage:
|
case *ProposalMessage:
|
||||||
ps.SetHasProposal(msg.Proposal)
|
ps.SetHasProposal(msg.Proposal)
|
||||||
err = conR.conS.SetProposal(msg.Proposal)
|
err = conR.conS.SetProposal(msg.Proposal)
|
||||||
case *PartMessage:
|
case *ProposalPOLMessage:
|
||||||
if msg.Type == partTypeProposalBlock {
|
ps.ApplyProposalPOLMessage(msg)
|
||||||
ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Proof.Index)
|
case *BlockPartMessage:
|
||||||
_, err = conR.conS.AddProposalBlockPart(msg.Height, msg.Round, msg.Part)
|
ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Proof.Index)
|
||||||
} else {
|
_, err = conR.conS.AddProposalBlockPart(msg.Height, msg.Round, msg.Part)
|
||||||
log.Warn(Fmt("Unknown part type %v", msg.Type))
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
|
log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
|
||||||
}
|
}
|
||||||
@ -203,21 +201,17 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
|||||||
} else {
|
} else {
|
||||||
// Probably an invalid signature. Bad peer.
|
// Probably an invalid signature. Bad peer.
|
||||||
log.Warn("Error attempting to add vote", "error", err)
|
log.Warn("Error attempting to add vote", "error", err)
|
||||||
|
|
||||||
// TODO: punish peer
|
// TODO: punish peer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Initialize Prevotes/Precommits if needed
|
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size(), nil)
|
||||||
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size(), _)
|
ps.EnsureVoteBitArrays(rs.Height-1, rs.LastCommit.Size(), nil)
|
||||||
ps.SetHasVote(vote, index)
|
ps.SetHasVote(vote, index)
|
||||||
if added {
|
if added {
|
||||||
msg := &HasVoteMessage{
|
// If rs.Height == vote.Height && rs.Round < vote.Round,
|
||||||
Height: vote.Height,
|
// the peer is sending us CatchupCommit precommits.
|
||||||
Round: vote.Round,
|
// We could make note of this and help filter in broadcastHasVoteMessage().
|
||||||
Type: vote.Type,
|
conR.broadcastHasVoteMessage(vote, index)
|
||||||
Index: index,
|
|
||||||
}
|
|
||||||
conR.sw.Broadcast(StateChannel, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -232,6 +226,32 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Broadcasts HasVoteMessage to peers that care.
|
||||||
|
func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote, index uint) {
|
||||||
|
msg := &HasVoteMessage{
|
||||||
|
Height: vote.Height,
|
||||||
|
Round: vote.Round,
|
||||||
|
Type: vote.Type,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
conR.sw.Broadcast(StateChannel, msg)
|
||||||
|
/*
|
||||||
|
// TODO: Make this broadcast more selective.
|
||||||
|
for _, peer := range conR.sw.Peers().List() {
|
||||||
|
ps := peer.Data.Get(PeerStateKey).(*PeerState)
|
||||||
|
prs := ps.GetRoundState()
|
||||||
|
if prs.Height == vote.Height {
|
||||||
|
// TODO: Also filter on round?
|
||||||
|
peer.TrySend(StateChannel, msg)
|
||||||
|
} else {
|
||||||
|
// Height doesn't match
|
||||||
|
// TODO: check a field, maybe CatchupCommitRound?
|
||||||
|
// TODO: But that requires changing the struct field comment.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// Sets our private validator account for signing votes.
|
// Sets our private validator account for signing votes.
|
||||||
func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) {
|
func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) {
|
||||||
conR.conS.SetPrivValidator(priv)
|
conR.conS.SetPrivValidator(priv)
|
||||||
@ -254,27 +274,20 @@ func (conR *ConsensusReactor) SetFireable(evsw events.Fireable) {
|
|||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
||||||
// Get seconds since beginning of height.
|
|
||||||
timeElapsed := time.Now().Sub(rs.StartTime)
|
|
||||||
|
|
||||||
// Broadcast NewRoundStepMessage
|
|
||||||
nrsMsg = &NewRoundStepMessage{
|
nrsMsg = &NewRoundStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
Round: rs.Round,
|
Round: rs.Round,
|
||||||
Step: rs.Step,
|
Step: rs.Step,
|
||||||
SecondsSinceStartTime: uint(timeElapsed.Seconds()),
|
SecondsSinceStartTime: uint(time.Now().Sub(rs.StartTime).Seconds()),
|
||||||
LastCommitRound: rs.LastCommit.Round(),
|
LastCommitRound: rs.LastCommit.Round(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the step is commit, then also broadcast a CommitStepMessage.
|
|
||||||
if rs.Step == RoundStepCommit {
|
if rs.Step == RoundStepCommit {
|
||||||
csMsg = &CommitStepMessage{
|
csMsg = &CommitStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
BlockParts: rs.ProposalBlockParts.Header(),
|
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
||||||
BlockBitArray: rs.ProposalBlockParts.BitArray(),
|
BlockParts: rs.ProposalBlockParts.BitArray(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,14 +337,13 @@ OUTER_LOOP:
|
|||||||
prs := ps.GetRoundState()
|
prs := ps.GetRoundState()
|
||||||
|
|
||||||
// Send proposal Block parts?
|
// Send proposal Block parts?
|
||||||
if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockParts) {
|
if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockPartsHeader) {
|
||||||
//log.Debug("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts)
|
//log.Debug("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts)
|
||||||
if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockBitArray.Copy()).PickRandom(); ok {
|
if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockParts.Copy()).PickRandom(); ok {
|
||||||
part := rs.ProposalBlockParts.GetPart(index)
|
part := rs.ProposalBlockParts.GetPart(index)
|
||||||
msg := &PartMessage{
|
msg := &BlockPartMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
Round: rs.Round,
|
Round: rs.Round,
|
||||||
Type: partTypeProposalBlock,
|
|
||||||
Part: part,
|
Part: part,
|
||||||
}
|
}
|
||||||
peer.Send(DataChannel, msg)
|
peer.Send(DataChannel, msg)
|
||||||
@ -342,13 +354,13 @@ 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 {
|
||||||
//log.Debug("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockBitArray", prs.ProposalBlockBitArray)
|
//log.Debug("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockParts", prs.ProposalBlockParts)
|
||||||
if index, ok := prs.ProposalBlockBitArray.Not().PickRandom(); ok {
|
if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
|
||||||
// Ensure that the peer's PartSetHeader is correct
|
// Ensure that the peer's PartSetHeader is correct
|
||||||
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
||||||
if !blockMeta.Parts.Equals(prs.ProposalBlockParts) {
|
if !blockMeta.PartsHeader.Equals(prs.ProposalBlockPartsHeader) {
|
||||||
log.Debug("Peer ProposalBlockParts mismatch, sleeping",
|
log.Debug("Peer ProposalBlockPartsHeader mismatch, sleeping",
|
||||||
"peerHeight", prs.Height, "blockParts", blockMeta.Parts, "peerBlockParts", prs.ProposalBlockParts)
|
"peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
|
||||||
time.Sleep(peerGossipSleepDuration)
|
time.Sleep(peerGossipSleepDuration)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
@ -356,15 +368,14 @@ OUTER_LOOP:
|
|||||||
part := conR.blockStore.LoadBlockPart(prs.Height, index)
|
part := conR.blockStore.LoadBlockPart(prs.Height, index)
|
||||||
if part == nil {
|
if part == nil {
|
||||||
log.Warn("Could not load part", "index", index,
|
log.Warn("Could not load part", "index", index,
|
||||||
"peerHeight", prs.Height, "blockParts", blockMeta.Parts, "peerBlockParts", prs.ProposalBlockParts)
|
"peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
|
||||||
time.Sleep(peerGossipSleepDuration)
|
time.Sleep(peerGossipSleepDuration)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
// Send the part
|
// Send the part
|
||||||
msg := &PartMessage{
|
msg := &BlockPartMessage{
|
||||||
Height: prs.Height,
|
Height: prs.Height,
|
||||||
Round: prs.Round,
|
Round: prs.Round,
|
||||||
Type: partTypeProposalBlock,
|
|
||||||
Part: part,
|
Part: part,
|
||||||
}
|
}
|
||||||
peer.Send(DataChannel, msg)
|
peer.Send(DataChannel, msg)
|
||||||
@ -384,11 +395,27 @@ OUTER_LOOP:
|
|||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send proposal?
|
// By here, height and round match.
|
||||||
|
|
||||||
|
// Send Proposal && ProposalPOL BitArray?
|
||||||
if rs.Proposal != nil && !prs.Proposal {
|
if rs.Proposal != nil && !prs.Proposal {
|
||||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
// Proposal
|
||||||
peer.Send(DataChannel, msg)
|
{
|
||||||
ps.SetHasProposal(rs.Proposal)
|
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||||
|
peer.Send(DataChannel, msg)
|
||||||
|
ps.SetHasProposal(rs.Proposal)
|
||||||
|
}
|
||||||
|
// ProposalPOL.
|
||||||
|
// Must be in the same channel, sequential.
|
||||||
|
// That is, peer must receive ProposalMessage first.
|
||||||
|
if 0 <= rs.Proposal.POLRound {
|
||||||
|
msg := &ProposalPOLMessage{
|
||||||
|
Height: rs.Height,
|
||||||
|
ProposalPOLRound: uint(rs.Proposal.POLRound),
|
||||||
|
ProposalPOL: rs.Votes.Prevotes(uint(rs.Proposal.POLRound)).BitArray(),
|
||||||
|
}
|
||||||
|
peer.Send(DataChannel, msg)
|
||||||
|
}
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,36 +500,42 @@ OUTER_LOOP:
|
|||||||
if rs.Height == prs.Height {
|
if rs.Height == prs.Height {
|
||||||
// If there are lastCommits to send...
|
// If there are lastCommits to send...
|
||||||
if prs.Step == RoundStepNewHeight {
|
if prs.Step == RoundStepNewHeight {
|
||||||
if trySendVote(rs.LastCommit, prs.LastCommit) {
|
if trySendVote(rs.LastCommit, &prs.LastCommit) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are prevotes to send...
|
// If there are prevotes to send...
|
||||||
if rs.Round == prs.Round && prs.Step <= RoundStepPrevote {
|
if rs.Round == prs.Round && prs.Step <= RoundStepPrevote {
|
||||||
if trySendVote(rs.Prevotes, prs.Prevotes) {
|
if trySendVote(rs.Votes.Prevotes(rs.Round), &prs.Prevotes) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are precommits to send...
|
// If there are precommits to send...
|
||||||
if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit {
|
if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit {
|
||||||
if trySendVote(rs.Precommits, prs.Precommits) {
|
if trySendVote(rs.Votes.Precommits(rs.Round), &prs.Precommits) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If there are POLPrevotes to send...
|
||||||
|
if 0 <= prs.ProposalPOLRound {
|
||||||
|
if polPrevotes := rs.Votes.Prevotes(uint(prs.ProposalPOLRound)); polPrevotes != nil {
|
||||||
|
if trySendVote(polPrevotes, &prs.ProposalPOL) {
|
||||||
|
continue 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 && prs.Height == rs.Height-1 {
|
if prs.Height != 0 && prs.Height == rs.Height-1 {
|
||||||
if prs.Round == rs.LastCommit.Round() {
|
if prs.Round == rs.LastCommit.Round() {
|
||||||
if trySendVote(rs.LastCommit, prs.Precommits) {
|
if trySendVote(rs.LastCommit, &prs.Precommits) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
// XXX CONTONUE
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ps.SetCatchupCommitRound(prs.Height, rs.LastCommit.Round())
|
ps.SetCatchupCommitRound(prs.Height, rs.LastCommit.Round())
|
||||||
ps.EnsureVoteBitArrays(prs.Height, rs.LastCommit.Size(), prs)
|
if trySendVote(rs.LastCommit, &prs.CatchupCommit) {
|
||||||
if trySendVote(rs.LastCommit, prs.CatchupCommit) {
|
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -515,15 +548,15 @@ OUTER_LOOP:
|
|||||||
// which contains precommit signatures for prs.Height.
|
// which contains precommit signatures for prs.Height.
|
||||||
validation := conR.blockStore.LoadBlockValidation(prs.Height)
|
validation := conR.blockStore.LoadBlockValidation(prs.Height)
|
||||||
log.Debug("Loaded BlockValidation for catch-up", "height", prs.Height, "validation", validation)
|
log.Debug("Loaded BlockValidation for catch-up", "height", prs.Height, "validation", validation)
|
||||||
// Peer's CommitRound should be -1 or equal to the validation's precommit rounds.
|
// Peer's CatchupCommitRound should be -1 or equal to the validation's precommit rounds.
|
||||||
// If not, warn.
|
// If not, warn.
|
||||||
if prs.CommitRound == -1 {
|
if prs.CatchupCommitRound == -1 {
|
||||||
ps.SetCommitRound(prs.Height, validation.Round())
|
ps.SetCatchupCommitRound(prs.Height, validation.Round())
|
||||||
continue OUTER_LOOP // Get prs := ps.GetRoundState() again.
|
continue OUTER_LOOP // Get prs := ps.GetRoundState() again.
|
||||||
} else if prs.CommitRound != validation.Round() {
|
} else if prs.CatchupCommitRound != int(validation.Round()) {
|
||||||
log.Warn("Peer's CommitRound during catchup not equal to commit round",
|
log.Warn("Peer's CatchupCommitRound during catchup not equal to commit round",
|
||||||
"height", prs.Height, "validation", validation, "prs.CommitRound", prs.CommitRound)
|
"height", prs.Height, "validation", validation, "prs.CatchupCommitRound", prs.CatchupCommitRound)
|
||||||
} else if trySendPrecommitFromValidation(validation, prs.Commit) {
|
} else if trySendPrecommitFromValidation(validation, &prs.CatchupCommit) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,8 +565,8 @@ OUTER_LOOP:
|
|||||||
// We sent nothing. Sleep...
|
// We sent nothing. Sleep...
|
||||||
sleeping = 1
|
sleeping = 1
|
||||||
log.Debug("No votes to send, sleeping", "peer", peer,
|
log.Debug("No votes to send, sleeping", "peer", peer,
|
||||||
"localPV", rs.Prevotes.BitArray(), "peerPV", prs.Prevotes,
|
"localPV", rs.Votes.Prevotes(rs.Round).BitArray(), "peerPV", prs.Prevotes,
|
||||||
"localPC", rs.Precommits.BitArray(), "peerPC", prs.Precommits)
|
"localPC", rs.Votes.Precommits(rs.Round).BitArray(), "peerPC", prs.Precommits)
|
||||||
} else if sleeping == 2 {
|
} else if sleeping == 2 {
|
||||||
// Continued sleep...
|
// Continued sleep...
|
||||||
sleeping = 1
|
sleeping = 1
|
||||||
@ -548,24 +581,21 @@ OUTER_LOOP:
|
|||||||
|
|
||||||
// Read only when returned by PeerState.GetRoundState().
|
// Read only when returned by PeerState.GetRoundState().
|
||||||
type PeerRoundState struct {
|
type PeerRoundState struct {
|
||||||
Height uint // Height peer is at
|
Height uint // Height peer is at
|
||||||
Round uint // Round peer is at
|
Round uint // Round peer is at
|
||||||
Step RoundStepType // Step peer is at
|
Step RoundStepType // Step peer is at
|
||||||
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
|
||||||
ProposalBlockParts types.PartSetHeader //
|
ProposalBlockPartsHeader types.PartSetHeader //
|
||||||
ProposalBlockBitArray *BitArray // True bit -> has part
|
ProposalBlockParts *BitArray //
|
||||||
ProposalPOLParts types.PartSetHeader //
|
ProposalPOLRound int // -1 if none
|
||||||
ProposalPOLBitArray *BitArray // True bit -> has part
|
ProposalPOL *BitArray // nil until ProposalPOLMessage received.
|
||||||
Prevotes *BitArray // All votes peer has for this round
|
Prevotes *BitArray // All votes peer has for this round
|
||||||
Precommits *BitArray // All precommits peer has for this round
|
Precommits *BitArray // All precommits peer has for this round
|
||||||
LastCommitRound uint // Round of commit for last height.
|
LastCommitRound uint // Round of commit for last height.
|
||||||
LastCommit *BitArray // All commit precommits of commit for last height.
|
LastCommit *BitArray // All commit precommits of commit for last height.
|
||||||
|
CatchupCommitRound int // Round that we believe commit round is.
|
||||||
// If peer is leading in height, the round that peer believes commit round is.
|
CatchupCommit *BitArray // All commit precommits peer has for this height
|
||||||
// If peer is lagging in height, the round that we believe commit round is.
|
|
||||||
CatchupCommitRound int
|
|
||||||
CatchupCommit *BitArray // All commit precommits peer has for this height
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -608,10 +638,10 @@ func (ps *PeerState) SetHasProposal(proposal *Proposal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ps.Proposal = true
|
ps.Proposal = true
|
||||||
ps.ProposalBlockParts = proposal.BlockParts
|
ps.ProposalBlockPartsHeader = proposal.BlockPartsHeader
|
||||||
ps.ProposalBlockBitArray = NewBitArray(uint(proposal.BlockParts.Total))
|
ps.ProposalBlockParts = NewBitArray(uint(proposal.BlockPartsHeader.Total))
|
||||||
ps.ProposalPOLParts = proposal.POLParts
|
ps.ProposalPOLRound = proposal.POLRound
|
||||||
ps.ProposalPOLBitArray = NewBitArray(uint(proposal.POLParts.Total))
|
ps.ProposalPOL = nil // Nil until ProposalPOLMessage received.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint) {
|
func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint) {
|
||||||
@ -622,18 +652,7 @@ func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.ProposalBlockBitArray.SetIndex(uint(index), true)
|
ps.ProposalBlockParts.SetIndex(uint(index), true)
|
||||||
}
|
|
||||||
|
|
||||||
func (ps *PeerState) SetHasProposalPOLPart(height uint, round uint, index uint) {
|
|
||||||
ps.mtx.Lock()
|
|
||||||
defer ps.mtx.Unlock()
|
|
||||||
|
|
||||||
if ps.Height != height || ps.Round != round {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ps.ProposalPOLBitArray.SetIndex(uint(index), true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prs: If given, will also update this PeerRoundState copy.
|
// prs: If given, will also update this PeerRoundState copy.
|
||||||
@ -651,6 +670,9 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint, prs *P
|
|||||||
if ps.CatchupCommit == nil {
|
if ps.CatchupCommit == nil {
|
||||||
ps.CatchupCommit = NewBitArray(numValidators)
|
ps.CatchupCommit = NewBitArray(numValidators)
|
||||||
}
|
}
|
||||||
|
if ps.ProposalPOL == nil {
|
||||||
|
ps.ProposalPOL = NewBitArray(numValidators)
|
||||||
|
}
|
||||||
} else if ps.Height == height+1 {
|
} else if ps.Height == height+1 {
|
||||||
if ps.LastCommit == nil {
|
if ps.LastCommit == nil {
|
||||||
ps.LastCommit = NewBitArray(numValidators)
|
ps.LastCommit = NewBitArray(numValidators)
|
||||||
@ -663,6 +685,7 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint, prs *P
|
|||||||
prs.Precommits = ps.Precommits
|
prs.Precommits = ps.Precommits
|
||||||
prs.LastCommit = ps.LastCommit
|
prs.LastCommit = ps.LastCommit
|
||||||
prs.CatchupCommit = ps.CatchupCommit
|
prs.CatchupCommit = ps.CatchupCommit
|
||||||
|
prs.ProposalPOL = ps.ProposalPOL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,13 +707,17 @@ func (ps *PeerState) setHasVote(height uint, round uint, type_ byte, index uint)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By here, ps.Height is height.
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.VoteTypePrevote:
|
||||||
|
if ps.ProposalPOLRound == int(round) {
|
||||||
|
ps.ProposalPOL.SetIndex(index, true)
|
||||||
|
}
|
||||||
ps.Prevotes.SetIndex(index, true)
|
ps.Prevotes.SetIndex(index, true)
|
||||||
log.Debug("SetHasVote", "peer", ps.Key, "prevotes", ps.Prevotes, "index", index)
|
log.Debug("SetHasVote", "peer", ps.Key, "prevotes", ps.Prevotes, "index", index)
|
||||||
case types.VoteTypePrecommit:
|
case types.VoteTypePrecommit:
|
||||||
if ps.CommitRound == round {
|
if ps.CatchupCommitRound == int(round) {
|
||||||
ps.Commit.SetIndex(index, true)
|
ps.CatchupCommit.SetIndex(index, true)
|
||||||
}
|
}
|
||||||
ps.Precommits.SetIndex(index, true)
|
ps.Precommits.SetIndex(index, true)
|
||||||
log.Debug("SetHasVote", "peer", ps.Key, "precommits", ps.Precommits, "index", index)
|
log.Debug("SetHasVote", "peer", ps.Key, "precommits", ps.Precommits, "index", index)
|
||||||
@ -706,7 +733,7 @@ func (ps *PeerState) SetCatchupCommitRound(height, round uint) {
|
|||||||
if ps.Height != height {
|
if ps.Height != height {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round {
|
if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != int(round) {
|
||||||
log.Warn("Conflicting CatchupCommitRound",
|
log.Warn("Conflicting CatchupCommitRound",
|
||||||
"height", height,
|
"height", height,
|
||||||
"orig", ps.CatchupCommitRound,
|
"orig", ps.CatchupCommitRound,
|
||||||
@ -714,7 +741,7 @@ func (ps *PeerState) SetCatchupCommitRound(height, round uint) {
|
|||||||
)
|
)
|
||||||
// TODO think harder
|
// TODO think harder
|
||||||
}
|
}
|
||||||
ps.CatchupCommitRound = round
|
ps.CatchupCommitRound = int(round)
|
||||||
ps.CatchupCommit = nil
|
ps.CatchupCommit = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +754,7 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *Roun
|
|||||||
psRound := ps.Round
|
psRound := ps.Round
|
||||||
//psStep := ps.Step
|
//psStep := ps.Step
|
||||||
psCatchupCommitRound := ps.CatchupCommitRound
|
psCatchupCommitRound := ps.CatchupCommitRound
|
||||||
psCatchupCommit := ps.CatchupCommitRound
|
psCatchupCommit := ps.CatchupCommit
|
||||||
|
|
||||||
startTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
|
startTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
|
||||||
ps.Height = msg.Height
|
ps.Height = msg.Height
|
||||||
@ -736,15 +763,15 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *Roun
|
|||||||
ps.StartTime = startTime
|
ps.StartTime = startTime
|
||||||
if psHeight != msg.Height || psRound != msg.Round {
|
if psHeight != msg.Height || psRound != msg.Round {
|
||||||
ps.Proposal = false
|
ps.Proposal = false
|
||||||
ps.ProposalBlockParts = types.PartSetHeader{}
|
ps.ProposalBlockPartsHeader = types.PartSetHeader{}
|
||||||
ps.ProposalBlockBitArray = nil
|
ps.ProposalBlockParts = nil
|
||||||
ps.ProposalPOLParts = types.PartSetHeader{}
|
ps.ProposalPOLRound = -1
|
||||||
ps.ProposalPOLBitArray = nil
|
ps.ProposalPOL = nil
|
||||||
// We'll update the BitArray capacity later.
|
// We'll update the BitArray capacity later.
|
||||||
ps.Prevotes = nil
|
ps.Prevotes = nil
|
||||||
ps.Precommits = nil
|
ps.Precommits = nil
|
||||||
}
|
}
|
||||||
if psHeight == msg.Height && psRound != msg.Round && msg.Round == psCatchupCommitRound {
|
if psHeight == msg.Height && psRound != msg.Round && int(msg.Round) == psCatchupCommitRound {
|
||||||
// Peer caught up to CatchupCommitRound.
|
// Peer caught up to CatchupCommitRound.
|
||||||
ps.Precommits = psCatchupCommit
|
ps.Precommits = psCatchupCommit
|
||||||
}
|
}
|
||||||
@ -771,8 +798,8 @@ func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ps.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||||
ps.ProposalBlockParts = msg.BlockParts
|
ps.ProposalBlockParts = msg.BlockParts
|
||||||
ps.ProposalBlockBitArray = msg.BlockBitArray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
||||||
@ -786,6 +813,22 @@ func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
|||||||
ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
|
ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ps *PeerState) ApplyProposalPOLMessage(msg *ProposalPOLMessage) {
|
||||||
|
ps.mtx.Lock()
|
||||||
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
|
if ps.Height != msg.Height {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ps.ProposalPOLRound != int(msg.ProposalPOLRound) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Merge onto existing ps.ProposalPOL?
|
||||||
|
// We might have sent some prevotes in the meantime.
|
||||||
|
ps.ProposalPOL = msg.ProposalPOL
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Messages
|
// Messages
|
||||||
|
|
||||||
@ -793,9 +836,10 @@ const (
|
|||||||
msgTypeNewRoundStep = byte(0x01)
|
msgTypeNewRoundStep = byte(0x01)
|
||||||
msgTypeCommitStep = byte(0x02)
|
msgTypeCommitStep = byte(0x02)
|
||||||
msgTypeProposal = byte(0x11)
|
msgTypeProposal = byte(0x11)
|
||||||
msgTypePart = byte(0x12) // both block & POL
|
msgTypeProposalPOL = byte(0x12)
|
||||||
msgTypeVote = byte(0x13)
|
msgTypeBlockPart = byte(0x13) // both block & POL
|
||||||
msgTypeHasVote = byte(0x14)
|
msgTypeVote = byte(0x14)
|
||||||
|
msgTypeHasVote = byte(0x15)
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsensusMessage interface{}
|
type ConsensusMessage interface{}
|
||||||
@ -805,7 +849,8 @@ var _ = binary.RegisterInterface(
|
|||||||
binary.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
|
binary.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
|
||||||
binary.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
|
binary.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
|
||||||
binary.ConcreteType{&ProposalMessage{}, msgTypeProposal},
|
binary.ConcreteType{&ProposalMessage{}, msgTypeProposal},
|
||||||
binary.ConcreteType{&PartMessage{}, msgTypePart},
|
binary.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL},
|
||||||
|
binary.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart},
|
||||||
binary.ConcreteType{&VoteMessage{}, msgTypeVote},
|
binary.ConcreteType{&VoteMessage{}, msgTypeVote},
|
||||||
binary.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
|
binary.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
|
||||||
)
|
)
|
||||||
@ -838,13 +883,13 @@ func (m *NewRoundStepMessage) String() string {
|
|||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type CommitStepMessage struct {
|
type CommitStepMessage struct {
|
||||||
Height uint
|
Height uint
|
||||||
BlockParts types.PartSetHeader
|
BlockPartsHeader types.PartSetHeader
|
||||||
BlockBitArray *BitArray
|
BlockParts *BitArray
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommitStepMessage) String() string {
|
func (m *CommitStepMessage) String() string {
|
||||||
return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockParts, m.BlockBitArray)
|
return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockPartsHeader, m.BlockParts)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
@ -859,20 +904,26 @@ func (m *ProposalMessage) String() string {
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
const (
|
type ProposalPOLMessage struct {
|
||||||
partTypeProposalBlock = byte(0x01)
|
Height uint
|
||||||
partTypeProposalPOL = byte(0x02)
|
ProposalPOLRound uint
|
||||||
)
|
ProposalPOL *BitArray
|
||||||
|
}
|
||||||
|
|
||||||
type PartMessage struct {
|
func (m *ProposalPOLMessage) String() string {
|
||||||
|
return fmt.Sprintf("[ProposalPOL H:%v POLR:%v POL:%v]", m.Height, m.ProposalPOLRound, m.ProposalPOL)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
type BlockPartMessage struct {
|
||||||
Height uint
|
Height uint
|
||||||
Round uint
|
Round uint
|
||||||
Type byte
|
|
||||||
Part *types.Part
|
Part *types.Part
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PartMessage) String() string {
|
func (m *BlockPartMessage) String() string {
|
||||||
return fmt.Sprintf("[Part H:%v R:%v T:%X P:%v]", m.Height, m.Round, m.Type, m.Part)
|
return fmt.Sprintf("[BlockPart H:%v R:%v T:%X P:%v]", m.Height, m.Round, m.Part)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
@ -126,6 +126,7 @@ var (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
|
ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
|
||||||
|
ErrInvalidProposalPOLRound = errors.New("Error invalid proposal POL round")
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -900,6 +901,12 @@ func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
|
|||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// Verify signature
|
// Verify signature
|
||||||
if !cs.Validators.Proposer().PubKey.VerifyBytes(account.SignBytes(cs.state.ChainID, proposal), proposal.Signature) {
|
if !cs.Validators.Proposer().PubKey.VerifyBytes(account.SignBytes(cs.state.ChainID, proposal), proposal.Signature) {
|
||||||
return ErrInvalidProposalSignature
|
return ErrInvalidProposalSignature
|
||||||
|
@ -17,31 +17,31 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Proposal struct {
|
type Proposal struct {
|
||||||
Height uint `json:"height"`
|
Height uint `json:"height"`
|
||||||
Round uint `json:"round"`
|
Round uint `json:"round"`
|
||||||
BlockParts types.PartSetHeader `json:"block_parts"`
|
BlockPartsHeader types.PartSetHeader `json:"block_parts_header"`
|
||||||
POLRound int `json:"pol_round"` // -1 if null.
|
POLRound int `json:"pol_round"` // -1 if null.
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
Signature account.SignatureEd25519 `json:"signature"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProposal(height uint, round uint, blockParts types.PartSetHeader, polRound int) *Proposal {
|
func NewProposal(height uint, round uint, blockPartsHeader types.PartSetHeader, polRound int) *Proposal {
|
||||||
return &Proposal{
|
return &Proposal{
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
BlockParts: blockParts,
|
BlockPartsHeader: blockPartsHeader,
|
||||||
POLRound: polRound,
|
POLRound: polRound,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) String() string {
|
func (p *Proposal) String() string {
|
||||||
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
||||||
p.BlockParts, p.POLRound, p.Signature)
|
p.BlockPartsHeader, p.POLRound, p.Signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
||||||
binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err)
|
||||||
binary.WriteTo([]byte(`,"proposal":{"block_parts":`), w, n, err)
|
binary.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err)
|
||||||
p.BlockParts.WriteSignBytes(w, n, err)
|
p.BlockPartsHeader.WriteSignBytes(w, n, err)
|
||||||
binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), w, n, err)
|
||||||
binary.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (voteSet *VoteSet) Size() uint {
|
|||||||
|
|
||||||
// Returns added=true, index if vote was added
|
// Returns added=true, index if vote was added
|
||||||
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
||||||
// CONTRACT: if err == nil, added == true
|
// Duplicate votes return added=false, err=nil.
|
||||||
// NOTE: vote should not be mutated after adding.
|
// NOTE: vote should not be mutated after adding.
|
||||||
func (voteSet *VoteSet) AddByIndex(valIndex uint, vote *types.Vote) (added bool, index uint, err error) {
|
func (voteSet *VoteSet) AddByIndex(valIndex uint, vote *types.Vote) (added bool, index uint, err error) {
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
@ -88,7 +88,7 @@ func (voteSet *VoteSet) AddByIndex(valIndex uint, vote *types.Vote) (added bool,
|
|||||||
|
|
||||||
// Returns added=true, index if vote was added
|
// Returns added=true, index if vote was added
|
||||||
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
||||||
// CONTRACT: if err == nil, added == true
|
// Duplicate votes return added=false, err=nil.
|
||||||
// NOTE: vote should not be mutated after adding.
|
// NOTE: vote should not be mutated after adding.
|
||||||
func (voteSet *VoteSet) AddByAddress(address []byte, vote *types.Vote) (added bool, index uint, err error) {
|
func (voteSet *VoteSet) AddByAddress(address []byte, vote *types.Vote) (added bool, index uint, err error) {
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
type BlockMeta struct {
|
type BlockMeta struct {
|
||||||
Hash []byte `json:"hash"` // The block hash
|
Hash []byte `json:"hash"` // The block hash
|
||||||
Header *Header `json:"header"` // The block's Header
|
Header *Header `json:"header"` // The block's Header
|
||||||
Parts PartSetHeader `json:"parts"` // The PartSetHeader, for transfer
|
PartsHeader PartSetHeader `json:"parts_header"` // The PartSetHeader, for transfer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
||||||
return &BlockMeta{
|
return &BlockMeta{
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
Header: block.Header,
|
Header: block.Header,
|
||||||
Parts: blockParts.Header(),
|
PartsHeader: blockParts.Header(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user