github.com/edxfund/validator@v1.8.16-0.20181020093046-c1def72855da/core/qztree.go (about) 1 // Copyright 2018 The EDX Authors 2 // This file is part of the EDX library. 3 // 4 // The edx library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The edx library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "container/list" 21 "sync" 22 ) 23 24 type Node interface { 25 Hash() uint64 26 BlockNumber() uint64 27 ParentHash() uint64 28 Td() uint64 29 } 30 31 type QZTree struct { 32 self Node 33 children *list.List 34 //for quick search 35 parent *QZTree 36 wg sync.RWMutex 37 38 } 39 40 func NewQZTree(root Node) *QZTree { 41 return &QZTree{ 42 self: root, 43 children: list.New(), 44 } 45 } 46 47 func (t *QZTree) Node() Node { return t.self } 48 func (t *QZTree) Children() *list.List { return t.children } 49 func (t *QZTree) Parent() *QZTree { return t.parent } 50 func (t *QZTree) FindNode(node Node, compare func(n1, n2 Node) bool) *QZTree { 51 t.wg.Lock() 52 defer t.wg.Unlock() 53 return t.findNode(node,compare) 54 } 55 func (t *QZTree) findNode(node Node, compare func(n1, n2 Node) bool) *QZTree { 56 if compare(t.self, node) { 57 return t 58 } else { 59 var res *QZTree 60 for i := t.children.Front(); i != nil; i = i.Next() { 61 res = (i.Value).(*QZTree).findNode(node, compare) 62 if res != nil { 63 break 64 } 65 } 66 return res 67 } 68 } 69 func (t *QZTree) AddNode(node Node) bool { 70 t.wg.Lock() 71 defer t.wg.Unlock() 72 return t.addNode(node) 73 } 74 //insert node , whose parent 75 func (t *QZTree) addNode(node Node) bool { 76 77 parent := t.findNode(node, func(n1, n2 Node) bool { 78 return n1.Hash() == n2.ParentHash() 79 }) 80 if parent != nil { 81 82 exist := false 83 for i := parent.children.Front(); i != nil; i = i.Next() { 84 if i.Value.(*QZTree).self.Hash() == node.Hash() { 85 exist = true 86 break 87 } 88 } 89 if !exist { 90 parent.children.PushBack(&QZTree{self: node, children: list.New(), parent: parent}) 91 } 92 93 //make a qztree 94 return true 95 } else { 96 return false 97 } 98 } 99 func (t *QZTree) getMaxTdPath() (uint64, *QZTree) { 100 td := t.self.Td() 101 maxTd := uint64(0) 102 var maxNode *QZTree 103 maxNode = nil 104 for i := t.children.Front(); i != nil; i = i.Next() { 105 curTd, node := i.Value.(*QZTree).getMaxTdPath() 106 //fmt.Println("node hash: %V, td: %V",node.self.Hash(),curTd) 107 if curTd > maxTd { 108 maxNode = node 109 maxTd = curTd 110 } 111 } 112 if maxNode != nil { 113 return maxTd, maxNode 114 } else { 115 return td, t 116 } 117 } 118 119 // find a max td path on node's branch, if node is nil find max of all 120 func (t *QZTree) GetMaxTdPath(node Node) *QZTree { 121 t.wg.Lock() 122 defer t.wg.Unlock() 123 if node != nil { 124 nodeTree := t.findNode(node, func(n1, n2 Node) bool { 125 return n1.Hash() == n2.Hash() 126 }) 127 if nodeTree != nil { 128 _, node := nodeTree.getMaxTdPath() 129 return node 130 } else { 131 return nil 132 } 133 134 } else { 135 _, node := t.getMaxTdPath() 136 return node 137 } 138 139 } 140 func (t *QZTree) MergeTree(newT *QZTree) bool { 141 t.wg.Lock() 142 defer t.wg.Unlock() 143 return t.mergeTree(newT) 144 } 145 func (t *QZTree) mergeTree(newT *QZTree) bool { 146 parent := t.findNode(newT.self, func(n1, n2 Node) bool { 147 return n1.Hash() == n2.ParentHash() 148 }) 149 if parent != nil { 150 //check for duplication 151 duplication := false 152 for i := t.children.Front(); i != nil; i = i.Next() { 153 if i.Value.(*QZTree).self.Hash() == newT.self.Hash() { 154 duplication = true 155 } 156 } 157 if !duplication { 158 parent.children.PushBack(newT) 159 } 160 161 return !duplication 162 } else { 163 return false 164 } 165 } 166 167 func (t *QZTree) dfIterator(check func(node Node) bool) bool { 168 if check(t.self) { 169 return true 170 } else { 171 for i := t.children.Front(); i != nil; i = i.Next() { 172 res := i.Value.(*QZTree).dfIterator(check) 173 if res { 174 return true 175 } 176 } 177 return false 178 } 179 } 180 func (t *QZTree) wfIterator(check func(node Node) bool) bool { 181 if check(t.self) { 182 return true 183 } else { 184 res := false 185 for i := t.children.Front(); i != nil; i = i.Next() { 186 if check(i.Value.(*QZTree).self) { 187 res = true 188 break 189 } 190 191 } 192 if !res { 193 for i := t.children.Front(); i != nil; i = i.Next() { 194 if i.Value.(*QZTree).wfIterator(check) { 195 res = true 196 break 197 } 198 199 } 200 } 201 return res 202 } 203 } 204 205 // using routine "proc" to iterate all node, it breaks when "proc" return true 206 func (t *QZTree) Iterator(deepFirst bool, proc func(node Node) bool) { 207 t.wg.Lock() 208 defer t.wg.Unlock() 209 if deepFirst { 210 t.dfIterator(proc) 211 } else { 212 t.wfIterator(proc) 213 } 214 } 215 func (t *QZTree) Remove(node Node, removeNode bool){ 216 t.wg.Lock() 217 defer t.wg.Unlock() 218 t.remove(node,removeNode) 219 } 220 func (t *QZTree) remove(node Node, removeNode bool) { 221 var target *QZTree 222 if node != nil { 223 target = t.findNode(node, func(n1, n2 Node) bool { 224 return n1.Hash() == n2.Hash() 225 }) 226 } else { 227 target = t 228 } 229 if target != nil { 230 231 for i := target.children.Front(); i != nil; i = i.Next() { 232 i.Value.(*QZTree).Remove(nil, false) 233 } 234 target.children.Init() 235 if node != nil && removeNode { 236 ls := target.parent.children 237 for it := ls.Front(); it != nil; it = it.Next() { 238 if it.Value.(*QZTree).self.Hash() == node.Hash() { 239 ls.Remove(it) 240 break 241 } 242 } 243 } 244 } 245 246 }