|
| 1 | +package core |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "time" |
| 6 | + |
| 7 | + lru "github.com/hashicorp/golang-lru" |
| 8 | + |
| 9 | + "github.com/ethereum/go-ethereum/common" |
| 10 | + "github.com/ethereum/go-ethereum/core/rawdb" |
| 11 | + "github.com/ethereum/go-ethereum/core/types" |
| 12 | + "github.com/ethereum/go-ethereum/log" |
| 13 | +) |
| 14 | + |
| 15 | +const verifiedCacheSize = 256 |
| 16 | + |
| 17 | +type VerifyManager struct { |
| 18 | + bc *BlockChain |
| 19 | + tasks map[common.Hash]*VerifyTask |
| 20 | + peers VerifyPeers |
| 21 | + verifiedCache *lru.Cache |
| 22 | + allowUntrustedVerify bool |
| 23 | + verifyCh chan common.Hash |
| 24 | + exitCh chan struct{} |
| 25 | +} |
| 26 | + |
| 27 | +func NewVerifyManager(blockchain *BlockChain) *VerifyManager { |
| 28 | + verifiedCache, _ := lru.New(verifiedCacheSize) |
| 29 | + vm := &VerifyManager{ |
| 30 | + bc: blockchain, |
| 31 | + tasks: make(map[common.Hash]*VerifyTask), |
| 32 | + verifiedCache: verifiedCache, |
| 33 | + verifyCh: make(chan common.Hash), |
| 34 | + exitCh: make(chan struct{}), |
| 35 | + } |
| 36 | + return vm |
| 37 | +} |
| 38 | + |
| 39 | +func (vm *VerifyManager) Start() { |
| 40 | + //read disk store to initial verified cache |
| 41 | + //load unverified blocks in a normalized chain and start a batch of verify task |
| 42 | + header := vm.bc.CurrentHeader() |
| 43 | + vm.NewBlockVerifyTask(header) |
| 44 | + go vm.mainLoop() |
| 45 | +} |
| 46 | + |
| 47 | +func (vm *VerifyManager) Stop() { |
| 48 | + defer close(vm.exitCh) |
| 49 | + vm.exitCh <- struct{}{} |
| 50 | +} |
| 51 | + |
| 52 | +func (vm *VerifyManager) mainLoop() { |
| 53 | + pruneTicker := time.NewTicker(time.Second) |
| 54 | + for { |
| 55 | + select { |
| 56 | + case hash := <-vm.verifyCh: |
| 57 | + vm.cacheBlockVerified(hash) |
| 58 | + rawdb.WriteTrustBlockHash(vm.bc.db, hash) |
| 59 | + delete(vm.tasks, hash) |
| 60 | + case <-pruneTicker.C: |
| 61 | + for hash, task := range vm.tasks { |
| 62 | + if vm.bc.CurrentHeader().Number.Uint64()-task.blockHeader.Number.Uint64() > 15 { |
| 63 | + task.terminalCh <- struct{}{} |
| 64 | + delete(vm.tasks, hash) |
| 65 | + } |
| 66 | + } |
| 67 | + case <-vm.exitCh: |
| 68 | + return |
| 69 | + } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +func (vm *VerifyManager) NewBlockVerifyTask(header *types.Header) { |
| 74 | + for i := 0; i < 11; i++ { |
| 75 | + hash := header.Hash() |
| 76 | + diffLayer := vm.bc.GetTrustedDiffLayer(hash) |
| 77 | + //if this block has no diff, there is no need to verify it. |
| 78 | + if diffLayer == nil { |
| 79 | + continue |
| 80 | + } |
| 81 | + //if verified cache record that this block has been verified, skip. |
| 82 | + if _, ok := vm.verifiedCache.Get(hash); ok { |
| 83 | + continue |
| 84 | + } |
| 85 | + //if verified storage record that this block has been verified, skip. |
| 86 | + if rawdb.ReadTrustBlockHash(vm.bc.db, hash) { |
| 87 | + vm.cacheBlockVerified(hash) |
| 88 | + continue |
| 89 | + } |
| 90 | + //if there already has a verify task for this block, skip. |
| 91 | + if _, ok := vm.tasks[hash]; ok { |
| 92 | + continue |
| 93 | + } |
| 94 | + diffHash, err := GetTrustedDiffHash(diffLayer) |
| 95 | + if err != nil { |
| 96 | + log.Error("failed to get diff hash", "block", hash, "number", header.Number, "error:", err) |
| 97 | + } |
| 98 | + verifyTask := NewVerifyTask(diffHash, header, vm.peers, vm.bc.db, vm.verifyCh, vm.allowUntrustedVerify) |
| 99 | + vm.tasks[hash] = verifyTask |
| 100 | + header = vm.bc.GetHeaderByHash(header.ParentHash) |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +func (vm *VerifyManager) cacheBlockVerified(hash common.Hash) { |
| 105 | + if vm.verifiedCache.Len() >= verifiedCacheSize { |
| 106 | + vm.verifiedCache.RemoveOldest() |
| 107 | + } |
| 108 | + vm.verifiedCache.Add(hash, true) |
| 109 | +} |
| 110 | + |
| 111 | +//CheckAncestorVerified function check whether head 11 of this block has been verified. |
| 112 | +//If not, the blockchain should stop to insert new block. |
| 113 | +func (vm *VerifyManager) CheckAncestorVerified(header *types.Header) bool { |
| 114 | + pHeader := header |
| 115 | + for i := 0; i < 11; i++ { |
| 116 | + pHeader = vm.bc.GetHeaderByHash(pHeader.ParentHash) |
| 117 | + } |
| 118 | + hash := pHeader.Hash() |
| 119 | + if _, ok := vm.verifiedCache.Get(hash); ok { |
| 120 | + return true |
| 121 | + } else { |
| 122 | + return rawdb.ReadTrustBlockHash(vm.bc.db, hash) |
| 123 | + } |
| 124 | + return false |
| 125 | +} |
| 126 | + |
| 127 | +func (vm *VerifyManager) HandleRootResponse(vr *types.VerifyResult, pid string) error { |
| 128 | + if vt, ok := vm.tasks[vr.BlockHash]; ok { |
| 129 | + vt.messageCh <- VerifyMessage{verifyResult: vr, peerId: pid} |
| 130 | + return nil |
| 131 | + } |
| 132 | + return fmt.Errorf("") |
| 133 | +} |
0 commit comments