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
}
findFork returns the final common block between the provided node and the
the chain view.  It will return nil if there is no common block.  This only
differs from the exported version in that it is up to the caller to ensure
the lock is held.

See the exported FindFork comments for more details.

This function MUST be called with the view mutex locked (for reads).
/*
func (c *chainView) findFork(node *blockNode) *blockNode {
No fork point for node that doesn't exist.
if node == nil {
return nil
}

When the height of the passed node is higher than the height of the
tip of the current chain view, walk backwards through the nodes of
the other chain until the heights match (or there or no more nodes in
which case there is no common node between the two).

NOTE: This isn't strictly necessary as the following section will
find the node as well, however, it is more efficient to avoid the
contains check since it is already known that the common node can't
possibly be past the end of the current chain view.  It also allows
this code to take advantage of any potential future optimizations to
the Ancestor function such as using an O(log n) skip list.
chainHeight := c.height()
if node.height > chainHeight {
node = node.Ancestor(chainHeight)
}

Walk the other chain backwards as long as the current one does not
contain the node or there are no more nodes in which case there is no
common node between the two.
for node != nil && !c.contains(node) {
node = node.parent
}

return node
}

FindFork returns the final common block between the provided node and the
the chain view.  It will return nil if there is no common block.

For example, assume a block chain with a side chain as depicted below:
genesis -> 1 -> 2 -> ... -> 5 -> 6  -> 7  -> 8
\-> 6a -> 7a

Further, assume the view is for the longer chain depicted above.  That is to
say it consists of:
genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.

Invoking this function with block node 7a would return block node 5 while
invoking it with block node 7 would return itself since it is already part of
the branch formed by the view.

This function is safe for concurrent access.
/*
func (c *chainView) FindFork(node *blockNode) *blockNode {
c.mtx.Lock()
fork := c.findFork(node)
c.mtx.Unlock()
return fork
}

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.  This only differs from the
exported version in that it is up to the caller to ensure the lock is held.

See the exported BlockLocator function comments for more details.

This function MUST be called with the view mutex locked (for reads).
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
}