From 206cdb5b68d3226eb4a771b374093a51999b3b17 Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Tue, 13 Nov 2018 09:43:28 +0800 Subject: core: Reduce call to Application.VerifyBlock (#317) --- core/consensus.go | 3 +-- core/leader-selector.go | 24 +++++++++++++++++++----- core/leader-selector_test.go | 28 ++++++++++++++++++++++++++++ core/types/block.go | 18 +++++++++++++----- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/core/consensus.go b/core/consensus.go index 89f2242..d12d30a 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -1002,9 +1002,8 @@ func (con *Consensus) preProcessBlock(b *types.Block) (err error) { // deliverBlock deliver a block to application layer. func (con *Consensus) deliverBlock(b *types.Block) { - // TODO(mission): clone types.FinalizationResult con.logger.Debug("Calling Application.BlockDelivered", "block", b) - con.app.BlockDelivered(b.Hash, b.Position, b.Finalization) + con.app.BlockDelivered(b.Hash, b.Position, b.Finalization.Clone()) if b.Position.Round+roundShift == con.roundToNotify { // Only the first block delivered of that round would // trigger this noitification. diff --git a/core/leader-selector.go b/core/leader-selector.go index 247ce89..a68f8ab 100644 --- a/core/leader-selector.go +++ b/core/leader-selector.go @@ -101,13 +101,17 @@ func (l *leaderSelector) leaderBlockHash() common.Hash { defer l.lock.Unlock() newPendingBlocks := []*types.Block{} for _, b := range l.pendingBlocks { + ok, dist := l.potentialLeader(b) + if !ok { + continue + } ok, err := l.validLeader(b) if err != nil { l.logger.Error("Error checking validLeader", "error", err, "block", b) continue } if ok { - l.updateLeader(b) + l.updateLeader(b, dist) } else { newPendingBlocks = append(newPendingBlocks, b) } @@ -126,6 +130,10 @@ func (l *leaderSelector) processBlock(block *types.Block) error { } l.lock.Lock() defer l.lock.Unlock() + ok, dist := l.potentialLeader(block) + if !ok { + return nil + } ok, err = l.validLeader(block) if err != nil { return err @@ -134,14 +142,20 @@ func (l *leaderSelector) processBlock(block *types.Block) error { l.pendingBlocks = append(l.pendingBlocks, block) return nil } - l.updateLeader(block) + l.updateLeader(block, dist) return nil } -func (l *leaderSelector) updateLeader(block *types.Block) { + +func (l *leaderSelector) potentialLeader(block *types.Block) (bool, *big.Int) { dist := l.distance(block.CRSSignature) cmp := l.minCRSBlock.Cmp(dist) if cmp > 0 || (cmp == 0 && block.Hash.Less(l.minBlockHash)) { - l.minCRSBlock = dist - l.minBlockHash = block.Hash + return true, dist } + return false, dist +} + +func (l *leaderSelector) updateLeader(block *types.Block, dist *big.Int) { + l.minCRSBlock = dist + l.minBlockHash = block.Hash } diff --git a/core/leader-selector_test.go b/core/leader-selector_test.go index f2c88f1..2edad60 100644 --- a/core/leader-selector_test.go +++ b/core/leader-selector_test.go @@ -150,6 +150,34 @@ func (s *LeaderSelectorTestSuite) TestValidLeaderFn() { s.Len(leader.pendingBlocks, 0) } +func (s *LeaderSelectorTestSuite) TestPotentialLeader() { + leader := s.newLeader() + blocks := make(map[common.Hash]*types.Block) + for i := 0; i < 10; i++ { + if i > 0 { + s.mockValidLeaderDefault = false + } + prv, err := ecdsa.NewPrivateKey() + s.Require().NoError(err) + block := &types.Block{ + ProposerID: types.NewNodeID(prv.PublicKey()), + Hash: common.NewRandomHash(), + } + s.Require().NoError( + NewAuthenticator(prv).SignCRS(block, leader.hashCRS)) + ok, _ := leader.potentialLeader(block) + s.Require().NoError(leader.processBlock(block)) + if i > 0 { + if ok { + s.Contains(leader.pendingBlocks, block) + } else { + s.NotContains(leader.pendingBlocks, block) + } + blocks[block.Hash] = block + } + } +} + func TestLeaderSelector(t *testing.T) { suite.Run(t, new(LeaderSelectorTestSuite)) } diff --git a/core/types/block.go b/core/types/block.go index 27416d8..b24e1f7 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -83,6 +83,18 @@ type FinalizationResult struct { Height uint64 `json:"height"` } +// Clone returns a deep copy of FinalizationResult +func (f FinalizationResult) Clone() FinalizationResult { + frcopy := FinalizationResult{ + ParentHash: f.ParentHash, + Timestamp: f.Timestamp, + Height: f.Height, + } + frcopy.Randomness = make([]byte, len(f.Randomness)) + copy(frcopy.Randomness, f.Randomness) + return frcopy +} + type rlpFinalizationResult struct { ParentHash common.Hash Randomness []byte @@ -223,9 +235,7 @@ func (b *Block) Clone() (bcopy *Block) { bcopy.Position.Height = b.Position.Height bcopy.Signature = b.Signature.Clone() bcopy.CRSSignature = b.CRSSignature.Clone() - bcopy.Finalization.ParentHash = b.Finalization.ParentHash - bcopy.Finalization.Timestamp = b.Finalization.Timestamp - bcopy.Finalization.Height = b.Finalization.Height + bcopy.Finalization = b.Finalization.Clone() bcopy.Witness.Height = b.Witness.Height bcopy.Witness.Data = make([]byte, len(b.Witness.Data)) copy(bcopy.Witness.Data, b.Witness.Data) @@ -235,8 +245,6 @@ func (b *Block) Clone() (bcopy *Block) { bcopy.Payload = make([]byte, len(b.Payload)) copy(bcopy.Payload, b.Payload) bcopy.PayloadHash = b.PayloadHash - bcopy.Finalization.Randomness = make([]byte, len(b.Finalization.Randomness)) - copy(bcopy.Finalization.Randomness, b.Finalization.Randomness) return } -- cgit v1.2.3