diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2019-03-27 15:02:27 +0800 |
---|---|---|
committer | Jimmy Hu <jimmy.hu@dexon.org> | 2019-03-27 15:25:10 +0800 |
commit | f848ee5128563138b1757034ea7d387c77679728 (patch) | |
tree | ce9083e8ae66ea7234d36241a3b1cf8b65fca2a8 /core | |
parent | 495b3737414685d609f7b41355928c699189d6ad (diff) | |
download | tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar.gz tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar.bz2 tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar.lz tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar.xz tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.tar.zst tangerine-consensus-f848ee5128563138b1757034ea7d387c77679728.zip |
core: Update BA to the latest version (#519)
* core: fastPreCom should not propose fastCom in RBA
* add test for fix
* core: update BA
* core: fix test
Diffstat (limited to 'core')
-rw-r--r-- | core/agreement-state.go | 22 | ||||
-rw-r--r-- | core/agreement-state_test.go | 53 | ||||
-rw-r--r-- | core/agreement.go | 26 | ||||
-rw-r--r-- | core/agreement_test.go | 30 | ||||
-rw-r--r-- | core/leader-selector.go | 2 |
5 files changed, 59 insertions, 74 deletions
diff --git a/core/agreement-state.go b/core/agreement-state.go index 73d7b7a..0d1ae58 100644 --- a/core/agreement-state.go +++ b/core/agreement-state.go @@ -132,11 +132,14 @@ func (s *preCommitState) clocks() int { return 2 } func (s *preCommitState) nextState() (agreementState, error) { s.a.lock.RLock() defer s.a.lock.RUnlock() - hash := s.a.lockValue - if hash == types.NullBlockHash { - hash = s.a.leader.leaderBlockHash() + if s.a.lockValue == types.SkipBlockHash || + s.a.lockValue == types.NullBlockHash { + hash := s.a.leader.leaderBlockHash() + s.a.recv.ProposeVote(types.NewVote(types.VotePreCom, hash, s.a.period)) + } else { + s.a.recv.ProposeVote(types.NewVote( + types.VotePreCom, s.a.lockValue, s.a.period)) } - s.a.recv.ProposeVote(types.NewVote(types.VotePreCom, hash, s.a.period)) return newCommitState(s.a), nil } @@ -154,16 +157,7 @@ func (s *commitState) clocks() int { return 2 } func (s *commitState) nextState() (agreementState, error) { s.a.lock.Lock() defer s.a.lock.Unlock() - hash, ok := s.a.countVoteNoLock(s.a.period, types.VotePreCom) - if ok && hash != types.SkipBlockHash { - if s.a.period > s.a.lockIter { - s.a.lockValue = hash - s.a.lockIter = s.a.period - } - } else { - hash = types.SkipBlockHash - } - s.a.recv.ProposeVote(types.NewVote(types.VoteCom, hash, s.a.period)) + s.a.recv.ProposeVote(types.NewVote(types.VoteCom, s.a.lockValue, s.a.period)) return newForwardState(s.a), nil } diff --git a/core/agreement-state_test.go b/core/agreement-state_test.go index c4197b5..b3dcd67 100644 --- a/core/agreement-state_test.go +++ b/core/agreement-state_test.go @@ -221,11 +221,22 @@ func (s *AgreementStateTestSuite) TestPreCommitState() { s.Require().Len(s.voteChan, 1) vote := <-s.voteChan s.Equal(types.VotePreCom, vote.Type) - s.NotEqual(common.Hash{}, vote.BlockHash) + s.NotEqual(types.SkipBlockHash, vote.BlockHash) s.Equal(stateCommit, newState.state()) - // Else, preCom-vote on lockValue. + // If lockvalue == SKIP, propose preCom-vote for the leader block. + a.data.lockValue = types.SkipBlockHash a.data.period = 2 + newState, err = state.nextState() + s.Require().NoError(err) + s.Require().Len(s.voteChan, 1) + vote = <-s.voteChan + s.Equal(types.VotePreCom, vote.Type) + s.NotEqual(types.SkipBlockHash, vote.BlockHash) + s.Equal(stateCommit, newState.state()) + + // Else, preCom-vote on lockValue. + a.data.period = 3 hash := common.NewRandomHash() a.data.lockValue = hash newState, err = state.nextState() @@ -243,47 +254,15 @@ func (s *AgreementStateTestSuite) TestCommitState() { s.Equal(stateCommit, state.state()) s.Equal(2, state.clocks()) - // If there are 2f+1 preCom-votes for block v or null, - // propose a com-vote for block v. + // Commit on lock value. a.data.period = 1 - block := s.proposeBlock(a.data.leader) - s.Require().NoError(a.processBlock(block)) - for nID := range a.notarySet { - vote := s.prepareVote(nID, types.VotePreCom, block.Hash, 1) - s.Require().NoError(a.processVote(vote)) - } + a.data.lockValue = common.NewRandomHash() newState, err := state.nextState() s.Require().NoError(err) s.Require().Len(s.voteChan, 1) - s.Equal(block.Hash, a.data.lockValue) - s.Equal(uint64(1), a.data.lockIter) vote := <-s.voteChan s.Equal(types.VoteCom, vote.Type) - s.Equal(block.Hash, vote.BlockHash) - s.Equal(stateForward, newState.state()) - - // Else, com-vote on SKIP. - a.data.period = 2 - newState, err = state.nextState() - s.Require().NoError(err) - s.Require().Len(s.voteChan, 1) - vote = <-s.voteChan - s.Equal(types.VoteCom, vote.Type) - s.Equal(types.SkipBlockHash, vote.BlockHash) - s.Equal(stateForward, newState.state()) - - // If there are 2f+1 preCom-votes for SKIP, it's same as the 'else' condition. - a.data.period = 3 - for nID := range a.notarySet { - vote := s.prepareVote(nID, types.VotePreCom, types.SkipBlockHash, 3) - s.Require().NoError(a.processVote(vote)) - } - newState, err = state.nextState() - s.Require().NoError(err) - s.Require().Len(s.voteChan, 1) - vote = <-s.voteChan - s.Equal(types.VoteCom, vote.Type) - s.Equal(types.SkipBlockHash, vote.BlockHash) + s.Equal(a.data.lockValue, vote.BlockHash) s.Equal(stateForward, newState.state()) } diff --git a/core/agreement.go b/core/agreement.go index d53440b..d4f1bbd 100644 --- a/core/agreement.go +++ b/core/agreement.go @@ -181,7 +181,7 @@ func (a *agreement) restart( a.data.blocks = make(map[types.NodeID]*types.Block) a.data.requiredVote = len(notarySet)*2/3 + 1 a.data.leader.restart(crs) - a.data.lockValue = types.NullBlockHash + a.data.lockValue = types.SkipBlockHash a.data.lockIter = 0 a.data.isLeader = a.data.ID == leader if a.doneChan != nil { @@ -461,11 +461,17 @@ func (a *agreement) processVote(vote *types.Vote) error { hash != types.SkipBlockHash { if vote.Type == types.VoteFast { if !a.hasVoteFast { - a.data.recv.ProposeVote( - types.NewVote(types.VoteFastCom, hash, vote.Period)) - a.data.lockValue = hash - a.data.lockIter = 1 - a.hasVoteFast = true + if a.state.state() == stateFast || + a.state.state() == stateFastVote { + a.data.recv.ProposeVote( + types.NewVote(types.VoteFastCom, hash, vote.Period)) + a.hasVoteFast = true + + } + if a.data.lockIter == 0 { + a.data.lockValue = hash + a.data.lockIter = 1 + } } } else { a.hasOutput = true @@ -494,18 +500,12 @@ func (a *agreement) processVote(vote *types.Vote) error { if hash, ok := a.data.countVoteNoLock(vote.Period, vote.Type); ok && hash != types.SkipBlockHash { // Condition 1. - if a.data.period >= vote.Period && vote.Period > a.data.lockIter && - vote.BlockHash != a.data.lockValue { + if vote.Period > a.data.lockIter { a.data.lockValue = hash a.data.lockIter = vote.Period - return nil } // Condition 2. if vote.Period > a.data.period { - if vote.Period > a.data.lockIter { - a.data.lockValue = hash - a.data.lockIter = vote.Period - } a.fastForward <- vote.Period if a.doneChan != nil { close(a.doneChan) diff --git a/core/agreement_test.go b/core/agreement_test.go index 175249f..cb4b2a9 100644 --- a/core/agreement_test.go +++ b/core/agreement_test.go @@ -176,31 +176,43 @@ func (s *AgreementTestSuite) prepareVote( } func (s *AgreementTestSuite) TestSimpleConfirm() { - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { + a, leaderNode := s.newAgreement(4, 0, func(*types.Block) (bool, error) { return true, nil }) + s.Require().Equal(s.ID, leaderNode) // FastState a.nextState() // FastVoteState - a.nextState() - // InitialState - a.nextState() - // PreCommitState s.Require().Len(s.blockChan, 1) blockHash := <-s.blockChan block, exist := s.block[blockHash] s.Require().True(exist) + s.Require().Equal(s.ID, block.ProposerID) s.Require().NoError(a.processBlock(block)) + // Wait some time for go routine in processBlock to finish. + time.Sleep(500 * time.Millisecond) s.Require().Len(s.voteChan, 1) - vote := <-s.voteChan - s.Equal(types.VoteInit, vote.Type) - s.Equal(blockHash, vote.BlockHash) + fastVote := <-s.voteChan + s.Equal(types.VoteFast, fastVote.Type) + s.Equal(blockHash, fastVote.BlockHash) + s.Require().Len(s.voteChan, 0) + a.nextState() + // InitialState + a.nextState() + // PreCommitState a.nextState() // CommitState s.Require().Len(s.voteChan, 1) - vote = <-s.voteChan + vote := <-s.voteChan s.Equal(types.VotePreCom, vote.Type) s.Equal(blockHash, vote.BlockHash) + // Fast-votes should be ignored. + for nID := range s.signers { + v := s.copyVote(fastVote, nID) + s.Require().NoError(a.processVote(v)) + } + s.Require().Len(s.voteChan, 0) + s.Equal(uint64(1), a.data.lockIter) for nID := range s.signers { v := s.copyVote(vote, nID) s.Require().NoError(a.processVote(v)) diff --git a/core/leader-selector.go b/core/leader-selector.go index 214b4cb..8c06328 100644 --- a/core/leader-selector.go +++ b/core/leader-selector.go @@ -93,7 +93,7 @@ func (l *leaderSelector) restart(crs common.Hash) { l.numCRS = numCRS l.hashCRS = crs l.minCRSBlock = maxHash - l.minBlockHash = common.Hash{} + l.minBlockHash = types.NullBlockHash l.pendingBlocks = make(map[common.Hash]*types.Block) } |