func (c *dagView) BlockLocator(node *blockNode) BlockLocator {
	c.mtx.Lock()
	locator := c.blockLocator(node)
	c.mtx.Unlock()
	return locator
}
BlockLocator returns a block locator for the passed block node.  The passed
node can be nil in which case the block locator for the current tip
associated with the view will be returned.

See the BlockLocator type for details on the algorithm used to create a block
locator.

This function is safe for concurrent access.
package blockdag
import (
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"sort"
	"sync"
)
const approxNodesPerWeek = 6 * 24 * 7  
var log2FloorMasks = []uint32{0xffff0000, 0xff00, 0xf0, 0xc, 0x2}
func fastLog2Floor(n uint32) uint8 {
	rv := uint8(0)
	exponent := uint8(16)
	for i := 0; i < 5; i++ {
		if n&log2FloorMasks[i] != 0 {
			rv += exponent
			n >>= exponent
		}
		exponent >>= 1
	}
	return rv
}
type dagView struct {
	mtx      sync.Mutex
	dagTips  map[*blockNode]struct{}
	nodes    [][]*blockNode
}
func newDAGView(tips []*blockNode) *dagView {
	var c dagView
	c.nodes = make([][]*blockNode, 0)
	c.dagTips = make(map[*blockNode]struct{})
	if tips != nil && len(tips) > 0 {
		for _, tip := range tips {
			c.addTip(tip)
		}
	}
	return &c
}
func (c *dagView) genesis() *blockNode {
	if len(c.nodes) == 0 {
		return nil
	}
	return c.nodes[0][0]
}
func (c *dagView) Genesis() *blockNode {
	c.mtx.Lock()
	genesis := c.genesis()
	c.mtx.Unlock()
	return genesis
}
func (c *dagView) tips() []*blockNode {
	if len(c.nodes) == 0 {
		return nil
	}
	tips := make([]*blockNode, 0, len(c.dagTips))
	for tip := range c.dagTips {
		tips = append(tips, tip)
	}
	sort.Sort(blockSorter(tips))
	return tips
}
func (c *dagView) Tips() []*blockNode {
	c.mtx.Lock()
	tip := c.tips()
	c.mtx.Unlock()
	return tip
}
func (c *dagView) addTip(node *blockNode) {
	needed := node.height + 1
	if int32(cap(c.nodes)) < needed {
		nodes := make([][]*blockNode, needed, needed+approxNodesPerWeek)
		copy(nodes, c.nodes)
		c.nodes = nodes
	} else {
		prevLen := int32(len(c.nodes))
		if prevLen < needed {
			c.nodes = c.nodes[0:needed]
		}
	}
	if node != nil {
		c.checkAndAddNode(node.height, node)
		c.dagTips[node] = struct{}{}
	}
}
func (c *dagView) AddTip(node *blockNode) {
	c.mtx.Lock()
	c.addTip(node)
	c.mtx.Unlock()
}
func (c *dagView) checkAndAddNode(height int32, node *blockNode) bool {
	if node != nil && !c.containsAtHeight(node.height, node) {
		nodes := c.nodes[node.height]
		nodes = append(nodes, node)
		for i, nodeH := range nodes {
			if node.hash.String() < nodeH.hash.String() {  
				copy(nodes[i+1:], nodes[i:])
				nodes[i] = node
				break
			}
		}
		c.nodes[node.height] = nodes
		parents := node.parents
		for _, parent := range parents {
			c.checkAndAddNode(parent.height, parent)
		}
		return true
	}
	return false
}
func (c *dagView) removeTip(node *blockNode) {
	for tip := range c.dagTips {
		if node == tip {
			delete(c.dagTips, node)
		}
	}
}
func (c *dagView) RemoveTip(node *blockNode) {
	c.mtx.Lock()
	c.removeTip(node)
	c.mtx.Unlock()
}
func (c *dagView) containsAtHeight(height int32, node *blockNode) bool {
	if height > int32(len(c.nodes) - 1) {
		return false
	}
	nodes := c.nodes[height]
	for _, nodeH := range nodes {
		if nodeH == node {
			return true
		}
	}
	return false
}
func (c *dagView) height() int32 {
	return int32(len(c.nodes) - 1)
}
func (c *dagView) Height() int32 {
	c.mtx.Lock()
	height := c.height()
	c.mtx.Unlock()
	return height
}
func (c *dagView) nodesByHeight(height int32) []*blockNode {
	if height < 0 || height >= int32(len(c.nodes)) {
		return nil
	}
	nodes := c.nodes[height]
	if nodes != nil && len(nodes) > 1 {
		sort.Sort(blockSorter(nodes))
	}
	return nodes
}
func (c *dagView) NodesByHeight(height int32) []*blockNode {
	c.mtx.Lock()
	nodes := c.nodesByHeight(height)
	c.mtx.Unlock()
	return nodes
}
func (c *dagView) virtualHash() *chainhash.Hash {
	return generateTipsHash(c.tips())
}
func (c *dagView) count() int {
	var nodeCount = 0
	for _, height := range c.nodes {
		nodeCount += len(height)
	}
	return nodeCount
}
func (c *dagView) Equals(other *dagView) bool {
	c.mtx.Lock()
	other.mtx.Lock()
	equals := len(c.nodes) == len(other.nodes) && c.virtualHash().IsEqual(other.virtualHash())
	other.mtx.Unlock()
	c.mtx.Unlock()
	return equals
}
func (c *dagView) contains(node *blockNode) bool {
	return c.containsAtHeight(node.height, node)
}
func (c *dagView) Contains(node *blockNode) bool {
	c.mtx.Lock()
	contains := c.contains(node)
	c.mtx.Unlock()
	return contains
}
func (c dagView) next(node *blockNode) *blockNode {
	if node == nil || !c.contains(node) {
		return nil
	}
	nodes := c.nodesByHeight(node.height)
	for i, nodeH := range nodes {
		if nodeH == node && i < (len(nodes) - 1) {
			return nodes[i+1]
		}
	}
	nodes = c.nodesByHeight(node.height + 1)
	if nodes == nil {
		return nil
	} else {
		return nodes[0]
	}
}
func (c *dagView) Next(node *blockNode) *blockNode {
	c.mtx.Lock()
	next := c.next(node)
	c.mtx.Unlock()
	return next
}
func (c *dagView) blockLocator(node *blockNode) BlockLocator {
	var maxHeight int32
	if node == nil {
		tips := c.tips()
		maxHeight = tips[0].height
		node = tips[0]
		for _, tip := range tips {
			if tip.height > maxHeight {
				maxHeight = tip.height
				node = tip
			}
		}
	}
	if node == nil {
		return nil
	}
	if node.height > maxHeight {
		maxHeight = node.height
	}
	locator := make(BlockLocator, 0, 1)
	locator = append(locator, &maxHeight)
	return locator
}