func (c *chainView) Equals(other *chainView) bool {
	c.mtx.Lock()
	other.mtx.Lock()
	equals := len(c.nodes) == len(other.nodes) && c.tip() == other.tip()
	other.mtx.Unlock()
	c.mtx.Unlock()
	return equals
}
Equals returns whether or not two chain views are the same.  Uninitialized
views (tip set to nil) are considered equal.

This function is safe for concurrent access.
package blockchain
import (
	"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 chainView struct {
	mtx   sync.Mutex
	nodes []*blockNode
}
func newChainView(tip *blockNode) *chainView {
	var c chainView
	c.setTip(tip)
	return &c
}
func (c *chainView) genesis() *blockNode {
	if len(c.nodes) == 0 {
		return nil
	}
	return c.nodes[0]
}
func (c *chainView) Genesis() *blockNode {
	c.mtx.Lock()
	genesis := c.genesis()
	c.mtx.Unlock()
	return genesis
}
func (c *chainView) tip() *blockNode {
	if len(c.nodes) == 0 {
		return nil
	}
	return c.nodes[len(c.nodes)-1]
}
func (c *chainView) Tip() *blockNode {
	c.mtx.Lock()
	tip := c.tip()
	c.mtx.Unlock()
	return tip
}
func (c *chainView) setTip(node *blockNode) {
	if node == nil {
		c.nodes = c.nodes[:0]
		return
	}
	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))
		c.nodes = c.nodes[0:needed]
		for i := prevLen; i < needed; i++ {
			c.nodes[i] = nil
		}
	}
	for node != nil && c.nodes[node.height] != node {
		c.nodes[node.height] = node
		node = node.parent
	}
}
func (c *chainView) SetTip(node *blockNode) {
	c.mtx.Lock()
	c.setTip(node)
	c.mtx.Unlock()
}
func (c *chainView) height() int32 {
	return int32(len(c.nodes) - 1)
}
func (c *chainView) Height() int32 {
	c.mtx.Lock()
	height := c.height()
	c.mtx.Unlock()
	return height
}
func (c *chainView) nodeByHeight(height int32) *blockNode {
	if height < 0 || height >= int32(len(c.nodes)) {
		return nil
	}
	return c.nodes[height]
}
func (c *chainView) NodeByHeight(height int32) *blockNode {
	c.mtx.Lock()
	node := c.nodeByHeight(height)
	c.mtx.Unlock()
	return node
}