diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go')
-rw-r--r-- | vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go | 291 |
1 files changed, 0 insertions, 291 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go deleted file mode 100644 index d7c2f8556..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// <http://www.gnu.org/licenses/>. - -package core - -import ( - "fmt" - "sync" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors for compaction chain module. -var ( - ErrBlockNotRegistered = fmt.Errorf( - "block not registered") - ErrNotInitiazlied = fmt.Errorf( - "not initialized") - ErrTSigNotReady = fmt.Errorf( - "tsig not ready") - ErrIncorrectBlockRandomnessResult = fmt.Errorf( - "incorrect block randomness result") -) - -const maxPendingPeriod = 3 * time.Second -const maxRandomnessCache = 100 - -type pendingRandomnessResult struct { - receivedTime time.Time - randResult *types.BlockRandomnessResult -} - -type finalizedBlockHeap = types.ByFinalizationHeight - -type compactionChain struct { - gov Governance - chainUnsynced uint32 - tsigVerifier *TSigVerifierCache - blocks map[common.Hash]*types.Block - blockRandomness map[common.Hash][]byte - pendingRandomness map[common.Hash]pendingRandomnessResult - processedRandomnessResult map[types.Position]struct{} - pendingBlocks []*types.Block - lock sync.RWMutex - prevBlock *types.Block -} - -func newCompactionChain(gov Governance) *compactionChain { - return &compactionChain{ - gov: gov, - tsigVerifier: NewTSigVerifierCache(gov, 7), - blocks: make(map[common.Hash]*types.Block), - blockRandomness: make(map[common.Hash][]byte), - pendingRandomness: make(map[common.Hash]pendingRandomnessResult), - processedRandomnessResult: make(map[types.Position]struct{}, maxRandomnessCache), - } -} - -// init the compaction chain module with a finalized block, or just an empty -// block for bootstrap case. -func (cc *compactionChain) init(initBlock *types.Block) { - cc.lock.Lock() - defer cc.lock.Unlock() - cc.prevBlock = initBlock - cc.pendingBlocks = []*types.Block{} - // It's the bootstrap case, compactionChain would only deliver blocks until - // tips of all chains are received. - if initBlock.Finalization.Height == 0 { - cc.chainUnsynced = utils.GetConfigWithPanic(cc.gov, 0, nil).NumChains - } -} - -func (cc *compactionChain) registerBlock(block *types.Block) { - if cc.blockRegistered(block.Hash) { - return - } - cc.lock.Lock() - defer cc.lock.Unlock() - cc.blocks[block.Hash] = block - if rand, exist := cc.pendingRandomness[block.Hash]; exist { - cc.blockRandomness[rand.randResult.BlockHash] = rand.randResult.Randomness - delete(cc.pendingRandomness, block.Hash) - } -} - -func (cc *compactionChain) blockRegistered(hash common.Hash) bool { - cc.lock.RLock() - defer cc.lock.RUnlock() - return cc.blockRegisteredNoLock(hash) -} - -func (cc *compactionChain) blockRegisteredNoLock( - hash common.Hash) (exist bool) { - _, exist = cc.blocks[hash] - return -} - -func (cc *compactionChain) processBlock(block *types.Block) error { - prevBlock := cc.lastDeliveredBlock() - if prevBlock == nil { - return ErrNotInitiazlied - } - cc.lock.Lock() - defer cc.lock.Unlock() - if prevBlock.Finalization.Height == 0 && block.Position.Height == 0 { - cc.chainUnsynced-- - } - cc.pendingBlocks = append(cc.pendingBlocks, block) - return nil -} - -func (cc *compactionChain) extractBlocks() []*types.Block { - // Check if we're synced. - if !func() bool { - cc.lock.RLock() - defer cc.lock.RUnlock() - if len(cc.pendingBlocks) == 0 { - return false - } - // Finalization.Height == 0 is syncing from bootstrap. - if cc.prevBlock.Finalization.Height == 0 { - return cc.chainUnsynced == 0 - } - return true - }() { - return []*types.Block{} - } - deliveringBlocks := make([]*types.Block, 0) - cc.lock.Lock() - defer cc.lock.Unlock() - var ( - block *types.Block - prevBlock = cc.prevBlock - ) - for len(cc.pendingBlocks) > 0 && - (len(cc.blockRandomness[cc.pendingBlocks[0].Hash]) != 0 || - cc.pendingBlocks[0].Position.Round == 0) { - delete(cc.blocks, cc.pendingBlocks[0].Hash) - block, cc.pendingBlocks = cc.pendingBlocks[0], cc.pendingBlocks[1:] - block.Finalization.ParentHash = prevBlock.Hash - block.Finalization.Height = prevBlock.Finalization.Height + 1 - if block.Position.Round != 0 { - block.Finalization.Randomness = cc.blockRandomness[block.Hash] - delete(cc.blockRandomness, block.Hash) - } - deliveringBlocks = append(deliveringBlocks, block) - prevBlock = block - } - cc.prevBlock = prevBlock - return deliveringBlocks -} - -func (cc *compactionChain) verifyRandomness( - blockHash common.Hash, round uint64, randomness []byte) (bool, error) { - if round == 0 { - return len(randomness) == 0, nil - } - // Randomness is not available at round 0. - v, ok, err := cc.tsigVerifier.UpdateAndGet(round) - if err != nil { - return false, err - } - if !ok { - return false, ErrTSigNotReady - } - return v.VerifySignature(blockHash, crypto.Signature{ - Type: "bls", - Signature: randomness}), nil -} - -func (cc *compactionChain) processFinalizedBlock(block *types.Block) error { - if block.Finalization.Height <= cc.lastDeliveredBlock().Finalization.Height { - return nil - } - // Block of round 0 should not have randomness. - if block.Position.Round == 0 && len(block.Finalization.Randomness) != 0 { - return nil - } - cc.lock.Lock() - defer cc.lock.Unlock() - // The randomness result is missed previously. - if cc.blockRegisteredNoLock(block.Hash) { - ok, err := cc.verifyRandomness( - block.Hash, block.Position.Round, block.Finalization.Randomness) - if err != nil { - return err - } - if ok { - cc.blockRandomness[block.Hash] = block.Finalization.Randomness - } - } - return nil -} - -func (cc *compactionChain) touchBlockRandomnessResult( - rand *types.BlockRandomnessResult) (first bool) { - // DO NOT LOCK THIS FUNCTION!!!!!!!! YOU WILL REGRET IT!!!!! - if _, exist := cc.processedRandomnessResult[rand.Position]; !exist { - first = true - if len(cc.processedRandomnessResult) > maxRandomnessCache { - for k := range cc.processedRandomnessResult { - // Randomly drop one element. - delete(cc.processedRandomnessResult, k) - break - } - } - cc.processedRandomnessResult[rand.Position] = struct{}{} - } - return -} - -func (cc *compactionChain) processBlockRandomnessResult( - rand *types.BlockRandomnessResult) error { - ok, err := cc.verifyRandomness( - rand.BlockHash, rand.Position.Round, rand.Randomness) - if err != nil { - return err - } - if !ok { - return ErrIncorrectBlockRandomnessResult - } - cc.lock.Lock() - defer cc.lock.Unlock() - if !cc.blockRegisteredNoLock(rand.BlockHash) { - cc.purgePending() - cc.pendingRandomness[rand.BlockHash] = pendingRandomnessResult{ - receivedTime: time.Now(), - randResult: rand, - } - return ErrBlockNotRegistered - } - cc.blockRandomness[rand.BlockHash] = rand.Randomness - return nil -} - -func (cc *compactionChain) purgePending() { - now := time.Now() - for key, rand := range cc.pendingRandomness { - if now.After(rand.receivedTime.Add(maxPendingPeriod)) { - delete(cc.pendingRandomness, key) - } - } -} - -// lastDeliveredBlock returns the last delivered block, or the one used to -// initialize this module. -func (cc *compactionChain) lastDeliveredBlock() *types.Block { - cc.lock.RLock() - defer cc.lock.RUnlock() - return cc.prevBlock -} - -// lastPendingBlock returns the last pending block. -func (cc *compactionChain) lastPendingBlock() *types.Block { - cc.lock.RLock() - defer cc.lock.RUnlock() - if len(cc.pendingBlocks) > 0 { - return cc.pendingBlocks[0] - } - return nil -} - -func (cc *compactionChain) pendingBlocksWithoutRandomness() ( - hashes common.Hashes) { - cc.lock.RLock() - defer cc.lock.RUnlock() - for _, block := range cc.pendingBlocks { - if _, exist := cc.blockRandomness[block.Hash]; !exist { - hashes = append(hashes, block.Hash) - } - } - return -} |