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  }