github.com/turingchain2020/turingchain@v1.1.21/blockchain/chainview.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package blockchain 6 7 import ( 8 "bytes" 9 "container/list" 10 "sync" 11 12 "github.com/turingchain2020/turingchain/common" 13 ) 14 15 const blockNodeCacheLimit = 10240 //目前best主链保存最新的10240个blocknode 16 17 // chainView provides a flat view of a specific branch of the block chain from 18 // its tip back to the genesis block and provides various convenience functions 19 // for comparing chains. 20 // 21 // For example, assume a block chain with a side chain as depicted below: 22 // genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 23 // \-> 4a -> 5a -> 6a 24 // 25 // The chain view for the branch ending in 6a consists of: 26 // genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a 27 type chainView struct { 28 mtx sync.Mutex 29 nodes map[int64]*list.Element 30 cacheQueue *list.List 31 } 32 33 //需要从数据库中获取lastblock然后组装成node节点开始创建ChainView 34 func newChainView(tip *blockNode) *chainView { 35 36 chainview := &chainView{ 37 nodes: make(map[int64]*list.Element), 38 cacheQueue: list.New(), 39 } 40 41 chainview.setTip(tip) 42 return chainview 43 } 44 45 func (c *chainView) tip() *blockNode { 46 if c.cacheQueue.Len() == 0 { 47 return nil 48 } 49 elem := c.cacheQueue.Front() 50 blocknode := elem.Value.(*blockNode) 51 return blocknode 52 } 53 54 func (c *chainView) Tip() *blockNode { 55 c.mtx.Lock() 56 tip := c.tip() 57 c.mtx.Unlock() 58 return tip 59 } 60 61 // 插入到list的头,节点超出blockNodeCacheLimit从back开始删除 62 func (c *chainView) setTip(node *blockNode) { 63 //需要检查node节点的父节点是当前的tip节点 64 if c.cacheQueue.Len() != 0 { 65 66 if node.parent != c.tip() { 67 chainlog.Error("setTip err", "node.height", node.height, "node.hash", common.ToHex(node.hash)) 68 chainlog.Error("setTip err", "c.tip().height", c.tip().height, "c.tip().hash", common.ToHex(c.tip().hash)) 69 return 70 } 71 } 72 // Create entry in cache and append to cacheQueue. 73 elem := c.cacheQueue.PushFront(node) 74 c.nodes[node.height] = elem 75 76 // Maybe expire an item. 77 if int64(c.cacheQueue.Len()) > blockNodeCacheLimit { 78 height := c.cacheQueue.Remove(c.cacheQueue.Back()).(*blockNode).height 79 delete(c.nodes, height) 80 } 81 chainlog.Debug("setTip", "node.height", node.height, "node.hash", common.ToHex(node.hash)) 82 } 83 84 func (c *chainView) SetTip(node *blockNode) { 85 c.mtx.Lock() 86 c.setTip(node) 87 c.mtx.Unlock() 88 } 89 90 // 删除tip节点,主要是节点回退时使用 91 func (c *chainView) delTip(node *blockNode) { 92 if c.tip() != node { 93 chainlog.Error("delTip err", "node.height", node.height, "node.hash", node.hash) 94 chainlog.Error("delTip err", "tip.height", c.tip().height, "tip.hash", c.tip().hash) 95 } 96 97 elem, ok := c.nodes[node.height] 98 if ok { 99 delheight := c.cacheQueue.Remove(elem).(*blockNode).height 100 if delheight != node.height { 101 chainlog.Error("delTip height err ", "height", node.height, "delheight", delheight) 102 } 103 delete(c.nodes, delheight) 104 } 105 } 106 107 func (c *chainView) DelTip(node *blockNode) { 108 c.mtx.Lock() 109 c.delTip(node) 110 c.mtx.Unlock() 111 } 112 113 // 返回 chain view tip 的height 114 func (c *chainView) height() int64 { 115 node := c.tip() 116 if node != nil { 117 return node.height 118 } 119 return -1 120 } 121 122 func (c *chainView) Height() int64 { 123 c.mtx.Lock() 124 height := c.height() 125 c.mtx.Unlock() 126 return height 127 } 128 129 //获取指定height的node 130 func (c *chainView) nodeByHeight(height int64) *blockNode { 131 if height < 0 || height > c.height() { 132 return nil 133 } 134 135 elem, ok := c.nodes[height] 136 if ok { 137 return elem.Value.(*blockNode) 138 } 139 140 return nil 141 } 142 143 // contains returns whether or not the chain view contains the passed block node. 144 func (c *chainView) contains(node *blockNode) bool { 145 return c.nodeByHeight(node.height) == node 146 } 147 148 func (c *chainView) next(node *blockNode) *blockNode { 149 if node == nil || !c.contains(node) { 150 return nil 151 } 152 153 return c.nodeByHeight(node.height + 1) 154 } 155 func (c *chainView) Next(node *blockNode) *blockNode { 156 c.mtx.Lock() 157 next := c.next(node) 158 c.mtx.Unlock() 159 return next 160 } 161 162 // findFork returns the final common block between the provided node and the 163 // the chain view. It will return nil if there is no common block. This only 164 // differs from the exported version in that it is up to the caller to ensure 165 // the lock is held. 166 167 func (c *chainView) findFork(node *blockNode) *blockNode { 168 169 if node == nil { 170 return nil 171 } 172 173 chainHeight := c.height() 174 if node.height > chainHeight { 175 node = node.Ancestor(chainHeight) 176 } 177 178 for node != nil && !c.contains(node) { 179 node = node.parent 180 } 181 182 return node 183 } 184 185 func (c *chainView) FindFork(node *blockNode) *blockNode { 186 c.mtx.Lock() 187 fork := c.findFork(node) 188 c.mtx.Unlock() 189 return fork 190 } 191 192 func (c *chainView) HaveBlock(hash []byte, height int64) bool { 193 c.mtx.Lock() 194 defer c.mtx.Unlock() 195 node := c.nodeByHeight(height) 196 if node != nil { 197 if bytes.Equal(hash, node.hash) { 198 return true 199 } 200 } 201 return false 202 }