Browse Source

check *parts.rootHash before sending

pull/9/head
Jae Kwon 10 years ago
parent
commit
f6093caac9
4 changed files with 88 additions and 78 deletions
  1. +7
    -0
      consensus/part_set.go
  2. +24
    -22
      consensus/reactor.go
  3. +54
    -53
      consensus/state.go
  4. +3
    -3
      consensus/state_test.go

+ 7
- 0
consensus/part_set.go View File

@ -147,6 +147,13 @@ func (ps *PartSet) RootHash() []byte {
return ps.rootHash return ps.rootHash
} }
func (ps *PartSet) HashesTo(rootHash []byte) bool {
if ps == nil {
return false
}
return bytes.Equal(ps.rootHash, rootHash)
}
func (ps *PartSet) Count() uint16 { func (ps *PartSet) Count() uint16 {
if ps == nil { if ps == nil {
return 0 return 0


+ 24
- 22
consensus/reactor.go View File

@ -500,17 +500,17 @@ OUTER_LOOP:
rs := conR.conS.GetRoundState() rs := conR.conS.GetRoundState()
prs := ps.GetRoundState() prs := ps.GetRoundState()
// If ProposalBlockHash matches, send parts?
// Send proposal Block parts?
// NOTE: if we or peer is at RoundStepCommit*, the round // NOTE: if we or peer is at RoundStepCommit*, the round
// won't necessarily match, but that's OK. // won't necessarily match, but that's OK.
if rs.ProposalBlock.HashesTo(prs.ProposalBlockHash) {
if index, ok := rs.ProposalBlockPartSet.BitArray().Sub(
if rs.ProposalBlockParts.HashesTo(prs.ProposalBlockPartsHash) {
if index, ok := rs.ProposalBlockParts.BitArray().Sub(
prs.ProposalBlockBitArray).PickRandom(); ok { prs.ProposalBlockBitArray).PickRandom(); ok {
msg := &PartMessage{ msg := &PartMessage{
Height: rs.Height, Height: rs.Height,
Round: rs.Round, Round: rs.Round,
Type: partTypeProposalBlock, Type: partTypeProposalBlock,
Part: rs.ProposalBlockPartSet.GetPart(uint16(index)),
Part: rs.ProposalBlockParts.GetPart(uint16(index)),
} }
peer.Send(DataCh, msg) peer.Send(DataCh, msg)
ps.SetHasProposalBlockPart(rs.Height, rs.Round, uint16(index)) ps.SetHasProposalBlockPart(rs.Height, rs.Round, uint16(index))
@ -532,15 +532,15 @@ OUTER_LOOP:
continue OUTER_LOOP continue OUTER_LOOP
} }
// Send proposal POL part?
if rs.ProposalPOLPartSet != nil {
if index, ok := rs.ProposalPOLPartSet.BitArray().Sub(
// Send proposal POL parts?
if rs.ProposalPOLParts.HashesTo(prs.ProposalPOLPartsHash) {
if index, ok := rs.ProposalPOLParts.BitArray().Sub(
prs.ProposalPOLBitArray).PickRandom(); ok { prs.ProposalPOLBitArray).PickRandom(); ok {
msg := &PartMessage{ msg := &PartMessage{
Height: rs.Height, Height: rs.Height,
Round: rs.Round, Round: rs.Round,
Type: partTypeProposalPOL, Type: partTypeProposalPOL,
Part: rs.ProposalPOLPartSet.GetPart(uint16(index)),
Part: rs.ProposalPOLParts.GetPart(uint16(index)),
} }
peer.Send(DataCh, msg) peer.Send(DataCh, msg)
ps.SetHasProposalPOLPart(rs.Height, rs.Round, uint16(index)) ps.SetHasProposalPOLPart(rs.Height, rs.Round, uint16(index))
@ -642,18 +642,18 @@ OUTER_LOOP:
// Read only when returned by PeerState.GetRoundState(). // Read only when returned by PeerState.GetRoundState().
type PeerRoundState struct { type PeerRoundState struct {
Height uint32 // Height peer is at
Round uint16 // Round peer is at
Step RoundStep // Step peer is at
StartTime time.Time // Estimated start of round 0 at this height
Proposal bool // True if peer has proposal for this round
ProposalBlockHash []byte // Block parts merkle root
ProposalBlockBitArray BitArray // Block parts bitarray
ProposalPOLHash []byte // POL parts merkle root
ProposalPOLBitArray BitArray // POL parts bitarray
Prevotes BitArray // All votes peer has for this round
Precommits BitArray // All precommits peer has for this round
Commits BitArray // All commits peer has for this height
Height uint32 // Height peer is at
Round uint16 // Round peer is at
Step RoundStep // Step peer is at
StartTime time.Time // Estimated start of round 0 at this height
Proposal bool // True if peer has proposal for this round
ProposalBlockPartsHash []byte // Block parts merkle root
ProposalBlockBitArray BitArray // Block parts bitarray
ProposalPOLPartsHash []byte // POL parts merkle root
ProposalPOLBitArray BitArray // POL parts bitarray
Prevotes BitArray // All votes peer has for this round
Precommits BitArray // All precommits peer has for this round
Commits BitArray // All commits peer has for this height
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -693,7 +693,9 @@ func (ps *PeerState) SetHasProposal(proposal *Proposal) {
} }
ps.Proposal = true ps.Proposal = true
ps.ProposalBlockPartsHash = proposal.BlockPartsHash
ps.ProposalBlockBitArray = NewBitArray(uint(proposal.BlockPartsTotal)) ps.ProposalBlockBitArray = NewBitArray(uint(proposal.BlockPartsTotal))
ps.ProposalPOLPartsHash = proposal.POLPartsHash
ps.ProposalPOLBitArray = NewBitArray(uint(proposal.POLPartsTotal)) ps.ProposalPOLBitArray = NewBitArray(uint(proposal.POLPartsTotal))
} }
@ -774,9 +776,9 @@ 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.ProposalBlockHash = nil
ps.ProposalBlockPartsHash = nil
ps.ProposalBlockBitArray = BitArray{} ps.ProposalBlockBitArray = BitArray{}
ps.ProposalPOLHash = nil
ps.ProposalPOLPartsHash = nil
ps.ProposalPOLBitArray = BitArray{} ps.ProposalPOLBitArray = BitArray{}
// We'll update the BitArray capacity later. // We'll update the BitArray capacity later.
ps.Prevotes = BitArray{} ps.Prevotes = BitArray{}


+ 54
- 53
consensus/state.go View File

@ -49,25 +49,25 @@ var (
// Immutable when returned from ConsensusState.GetRoundState() // Immutable when returned from ConsensusState.GetRoundState()
type RoundState struct { type RoundState struct {
Height uint32 // Height we are working on
Round uint16
Step RoundStep
StartTime time.Time
CommitTime time.Time // Time when +2/3 commits were found
Validators *state.ValidatorSet
Proposal *Proposal
ProposalBlock *Block
ProposalBlockPartSet *PartSet
ProposalPOL *POL
ProposalPOLPartSet *PartSet
LockedBlock *Block
LockedBlockPartSet *PartSet
LockedPOL *POL // Rarely needed, so no LockedPOLPartSet.
Prevotes *VoteSet
Precommits *VoteSet
Commits *VoteSet
LastCommits *VoteSet
PrivValidator *PrivValidator
Height uint32 // Height we are working on
Round uint16
Step RoundStep
StartTime time.Time
CommitTime time.Time // Time when +2/3 commits were found
Validators *state.ValidatorSet
Proposal *Proposal
ProposalBlock *Block
ProposalBlockParts *PartSet
ProposalPOL *POL
ProposalPOLParts *PartSet
LockedBlock *Block
LockedBlockParts *PartSet
LockedPOL *POL // Rarely needed, so no LockedPOLParts.
Prevotes *VoteSet
Precommits *VoteSet
Commits *VoteSet
LastCommits *VoteSet
PrivValidator *PrivValidator
} }
func (rs *RoundState) String() string { func (rs *RoundState) String() string {
@ -95,9 +95,9 @@ func (rs *RoundState) StringWithIndent(indent string) string {
indent, rs.CommitTime, indent, rs.CommitTime,
indent, rs.Validators.StringWithIndent(indent+" "), indent, rs.Validators.StringWithIndent(indent+" "),
indent, rs.Proposal, indent, rs.Proposal,
indent, rs.ProposalBlockPartSet.Description(), rs.ProposalBlock.Description(),
indent, rs.ProposalPOLPartSet.Description(), rs.ProposalPOL.Description(),
indent, rs.LockedBlockPartSet.Description(), rs.LockedBlock.Description(),
indent, rs.ProposalBlockParts.Description(), rs.ProposalBlock.Description(),
indent, rs.ProposalPOLParts.Description(), rs.ProposalPOL.Description(),
indent, rs.LockedBlockParts.Description(), rs.LockedBlock.Description(),
indent, rs.LockedPOL.Description(), indent, rs.LockedPOL.Description(),
indent, rs.Prevotes.StringWithIndent(indent+" "), indent, rs.Prevotes.StringWithIndent(indent+" "),
indent, rs.Precommits.StringWithIndent(indent+" "), indent, rs.Precommits.StringWithIndent(indent+" "),
@ -163,11 +163,11 @@ func (cs *ConsensusState) updateToState(state *state.State) {
cs.Validators = validators cs.Validators = validators
cs.Proposal = nil cs.Proposal = nil
cs.ProposalBlock = nil cs.ProposalBlock = nil
cs.ProposalBlockPartSet = nil
cs.ProposalBlockParts = nil
cs.ProposalPOL = nil cs.ProposalPOL = nil
cs.ProposalPOLPartSet = nil
cs.ProposalPOLParts = nil
cs.LockedBlock = nil cs.LockedBlock = nil
cs.LockedBlockPartSet = nil
cs.LockedBlockParts = nil
cs.LockedPOL = nil cs.LockedPOL = nil
cs.Prevotes = NewVoteSet(height, 0, VoteTypePrevote, validators) cs.Prevotes = NewVoteSet(height, 0, VoteTypePrevote, validators)
cs.Precommits = NewVoteSet(height, 0, VoteTypePrecommit, validators) cs.Precommits = NewVoteSet(height, 0, VoteTypePrecommit, validators)
@ -207,9 +207,9 @@ func (cs *ConsensusState) setupRound(round uint16) {
cs.Validators = validators cs.Validators = validators
cs.Proposal = nil cs.Proposal = nil
cs.ProposalBlock = nil cs.ProposalBlock = nil
cs.ProposalBlockPartSet = nil
cs.ProposalBlockParts = nil
cs.ProposalPOL = nil cs.ProposalPOL = nil
cs.ProposalPOLPartSet = nil
cs.ProposalPOLParts = nil
cs.Prevotes = NewVoteSet(cs.Height, round, VoteTypePrevote, validators) cs.Prevotes = NewVoteSet(cs.Height, round, VoteTypePrevote, validators)
cs.Prevotes.AddFromCommits(cs.Commits) cs.Prevotes.AddFromCommits(cs.Commits)
cs.Precommits = NewVoteSet(cs.Height, round, VoteTypePrecommit, validators) cs.Precommits = NewVoteSet(cs.Height, round, VoteTypePrecommit, validators)
@ -237,15 +237,15 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
} }
var block *Block var block *Block
var blockPartSet *PartSet
var blockParts *PartSet
var pol *POL var pol *POL
var polPartSet *PartSet
var polParts *PartSet
// Decide on block and POL // Decide on block and POL
if cs.LockedBlock != nil { if cs.LockedBlock != nil {
// If we're locked onto a block, just choose that. // If we're locked onto a block, just choose that.
block = cs.LockedBlock block = cs.LockedBlock
blockPartSet = cs.LockedBlockPartSet
blockParts = cs.LockedBlockParts
pol = cs.LockedPOL pol = cs.LockedPOL
} else { } else {
var validation Validation var validation Validation
@ -276,26 +276,26 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
Txs: txs, Txs: txs,
}, },
} }
blockPartSet = NewPartSetFromData(BinaryBytes(block))
blockParts = NewPartSetFromData(BinaryBytes(block))
pol = cs.LockedPOL // If exists, is a PoUnlock. pol = cs.LockedPOL // If exists, is a PoUnlock.
} }
if pol != nil { if pol != nil {
polPartSet = NewPartSetFromData(BinaryBytes(pol))
polParts = NewPartSetFromData(BinaryBytes(pol))
} }
// Make proposal // Make proposal
proposal := NewProposal(cs.Height, cs.Round, proposal := NewProposal(cs.Height, cs.Round,
blockPartSet.Total(), blockPartSet.RootHash(),
polPartSet.Total(), polPartSet.RootHash())
blockParts.Total(), blockParts.RootHash(),
polParts.Total(), polParts.RootHash())
cs.PrivValidator.Sign(proposal) cs.PrivValidator.Sign(proposal)
// Set fields // Set fields
cs.Proposal = proposal cs.Proposal = proposal
cs.ProposalBlock = block cs.ProposalBlock = block
cs.ProposalBlockPartSet = blockPartSet
cs.ProposalBlockParts = blockParts
cs.ProposalPOL = pol cs.ProposalPOL = pol
cs.ProposalPOLPartSet = polPartSet
cs.ProposalPOLParts = polParts
} }
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) *Vote { func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) *Vote {
@ -344,7 +344,7 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) *Vote
if len(hash) == 0 { if len(hash) == 0 {
// +2/3 prevoted nil. Just unlock. // +2/3 prevoted nil. Just unlock.
cs.LockedBlock = nil cs.LockedBlock = nil
cs.LockedBlockPartSet = nil
cs.LockedBlockParts = nil
return nil return nil
} else if cs.ProposalBlock.HashesTo(hash) { } else if cs.ProposalBlock.HashesTo(hash) {
// +2/3 prevoted for proposal block // +2/3 prevoted for proposal block
@ -355,7 +355,7 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) *Vote
return nil return nil
} }
cs.LockedBlock = cs.ProposalBlock cs.LockedBlock = cs.ProposalBlock
cs.LockedBlockPartSet = cs.ProposalBlockPartSet
cs.LockedBlockParts = cs.ProposalBlockParts
return cs.signAddVote(VoteTypePrecommit, hash) return cs.signAddVote(VoteTypePrecommit, hash)
} else if cs.LockedBlock.HashesTo(hash) { } else if cs.LockedBlock.HashesTo(hash) {
// +2/3 prevoted for already locked block // +2/3 prevoted for already locked block
@ -364,7 +364,7 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) *Vote
// We don't have the block that hashes to hash. // We don't have the block that hashes to hash.
// Unlock if we're locked. // Unlock if we're locked.
cs.LockedBlock = nil cs.LockedBlock = nil
cs.LockedBlockPartSet = nil
cs.LockedBlockParts = nil
return nil return nil
} }
} else { } else {
@ -396,13 +396,13 @@ func (cs *ConsensusState) RunActionCommit(height uint32, round uint16) *Vote {
// TODO: Identify these strange cases. // TODO: Identify these strange cases.
var block *Block var block *Block
var blockPartSet *PartSet
var blockParts *PartSet
if cs.LockedBlock.HashesTo(hash) { if cs.LockedBlock.HashesTo(hash) {
block = cs.LockedBlock block = cs.LockedBlock
blockPartSet = cs.LockedBlockPartSet
blockParts = cs.LockedBlockParts
} else if cs.ProposalBlock.HashesTo(hash) { } else if cs.ProposalBlock.HashesTo(hash) {
block = cs.ProposalBlock block = cs.ProposalBlock
blockPartSet = cs.ProposalBlockPartSet
blockParts = cs.ProposalBlockParts
} else { } else {
return nil return nil
} }
@ -416,7 +416,7 @@ func (cs *ConsensusState) RunActionCommit(height uint32, round uint16) *Vote {
// Keep block in cs.Proposal* // Keep block in cs.Proposal*
if !cs.ProposalBlock.HashesTo(hash) { if !cs.ProposalBlock.HashesTo(hash) {
cs.ProposalBlock = block cs.ProposalBlock = block
cs.ProposalBlockPartSet = blockPartSet
cs.ProposalBlockParts = blockParts
} }
// Save to blockStore // Save to blockStore
@ -457,6 +457,7 @@ func (cs *ConsensusState) RunActionFinalize(height uint32, round uint16) {
} }
// What was staged becomes committed. // What was staged becomes committed.
// XXX it's possible that this node never received the block to stage!!!
cs.updateToState(cs.stagedState) cs.updateToState(cs.stagedState)
} }
@ -482,8 +483,8 @@ func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
} }
cs.Proposal = proposal cs.Proposal = proposal
cs.ProposalBlockPartSet = NewPartSetFromMetadata(proposal.BlockPartsTotal, proposal.BlockPartsHash)
cs.ProposalPOLPartSet = NewPartSetFromMetadata(proposal.POLPartsTotal, proposal.POLPartsHash)
cs.ProposalBlockParts = NewPartSetFromMetadata(proposal.BlockPartsTotal, proposal.BlockPartsHash)
cs.ProposalPOLParts = NewPartSetFromMetadata(proposal.POLPartsTotal, proposal.POLPartsHash)
return nil return nil
} }
@ -498,18 +499,18 @@ func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part
} }
// We're not expecting a block part. // We're not expecting a block part.
if cs.ProposalBlockPartSet != nil {
if cs.ProposalBlockParts != nil {
return false, nil // TODO: bad peer? Return error? return false, nil // TODO: bad peer? Return error?
} }
added, err = cs.ProposalBlockPartSet.AddPart(part)
added, err = cs.ProposalBlockParts.AddPart(part)
if err != nil { if err != nil {
return added, err return added, err
} }
if added && cs.ProposalBlockPartSet.IsComplete() {
if added && cs.ProposalBlockParts.IsComplete() {
var n int64 var n int64
var err error var err error
cs.ProposalBlock = ReadBlock(cs.ProposalBlockPartSet.GetReader(), &n, &err)
cs.ProposalBlock = ReadBlock(cs.ProposalBlockParts.GetReader(), &n, &err)
return true, err return true, err
} }
return true, nil return true, nil
@ -525,18 +526,18 @@ func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *
} }
// We're not expecting a POL part. // We're not expecting a POL part.
if cs.ProposalPOLPartSet != nil {
if cs.ProposalPOLParts != nil {
return false, nil // TODO: bad peer? Return error? return false, nil // TODO: bad peer? Return error?
} }
added, err = cs.ProposalPOLPartSet.AddPart(part)
added, err = cs.ProposalPOLParts.AddPart(part)
if err != nil { if err != nil {
return added, err return added, err
} }
if added && cs.ProposalPOLPartSet.IsComplete() {
if added && cs.ProposalPOLParts.IsComplete() {
var n int64 var n int64
var err error var err error
cs.ProposalPOL = ReadPOL(cs.ProposalPOLPartSet.GetReader(), &n, &err)
cs.ProposalPOL = ReadPOL(cs.ProposalPOLParts.GetReader(), &n, &err)
return true, err return true, err
} }
return true, nil return true, nil


+ 3
- 3
consensus/state_test.go View File

@ -123,15 +123,15 @@ func TestRunActionPropose(t *testing.T) {
cs.RunActionPropose(1, 0) cs.RunActionPropose(1, 0)
rs := cs.GetRoundState() rs := cs.GetRoundState()
// Check that Proposal, ProposalBlock, ProposalBlockPartSet are set.
// Check that Proposal, ProposalBlock, ProposalBlockParts are set.
if rs.Proposal == nil { if rs.Proposal == nil {
t.Error("rs.Proposal should be set") t.Error("rs.Proposal should be set")
} }
if rs.ProposalBlock == nil { if rs.ProposalBlock == nil {
t.Error("rs.ProposalBlock should be set") t.Error("rs.ProposalBlock should be set")
} }
if rs.ProposalBlockPartSet.Total() == 0 {
t.Error("rs.ProposalBlockPartSet should be set")
if rs.ProposalBlockParts.Total() == 0 {
t.Error("rs.ProposalBlockParts should be set")
} }
} }


Loading…
Cancel
Save