func (node *blockNode) Ancestors(height int32) []*blockNode {
	if height < 0 || height > node.height {
		return nil
	}
	parents := node.parents
	checked := make(map[chainhash.Hash]struct{})
	for _, parent := range parents {
		checked[parent.hash] = struct{}{}
	}
	parentsHeight := node.parentsMaxHeight()
	for {
		if parents == nil || len(parents) == 0 || parentsHeight <= height {
			break
		}
		var grandParentMaxHeight int32
		var grandParents []*blockNode
		for _, parent := range parents {
			grandParentsHeight := parent.parentsMaxHeight()
			if grandParentsHeight > grandParentMaxHeight {
				grandParentMaxHeight = grandParentsHeight
			}
			for _, grandParent := range parent.parents {
				_, exists := checked[grandParent.hash]
				if !exists {
					grandParents = append(grandParents, grandParent)
					checked[grandParent.hash] = struct{}{}
				}
			}
		}
		parents = grandParents
		parentsHeight = grandParentMaxHeight
	}
	return parents
}
Ancestors returns the ancestor block nodes at the provided height by following
the chain backwards from this node.  The returned block will be nil when a
height is requested that is after the height of the passed node or is less
than zero.

This function is safe for concurrent access.
package blockdag
import (
	"math/big"
	"sort"
	"sync"
	"time"
	"github.com/soteria-dag/soterd/chaincfg"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/database"
	"github.com/soteria-dag/soterd/wire"
)
type blockStatus byte
const (
	statusDataStored blockStatus = 1 << iota
	statusValid
	statusValidateFailed
	statusInvalidAncestor
	statusNone blockStatus = 0
)
func (status blockStatus) HaveData() bool {
	return status&statusDataStored != 0
}
func (status blockStatus) KnownValid() bool {
	return status&statusValid != 0
}
func (status blockStatus) KnownInvalid() bool {
	return status&(statusValidateFailed|statusInvalidAncestor) != 0
}
type blockNode struct {
	parents []*blockNode
	parentMetadata []*parentInfo
	parentVersion int32
	hash chainhash.Hash
	workSum *big.Int
	height int32
	version    int32
	bits       uint32
	nonce      uint32
	timestamp  int64
	merkleRoot chainhash.Hash
	status blockStatus
}
type parentInfo struct {
	hash chainhash.Hash
	data [32]byte
}
func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader,
	parentSubHeader *wire.ParentSubHeader, parents []*blockNode) {
	*node = blockNode{
		hash:       blockHeader.BlockHash(),
		workSum:    CalcWork(blockHeader.Bits),
		version:    blockHeader.Version,
		bits:       blockHeader.Bits,
		nonce:      blockHeader.Nonce,
		timestamp:  blockHeader.Timestamp.Unix(),
		merkleRoot: blockHeader.MerkleRoot,
	}
	if parentSubHeader != nil {
		node.parentVersion = parentSubHeader.Version
		parentInfos := make([]*parentInfo, 0, len(parentSubHeader.Parents))
		for _, p := range parentSubHeader.Parents {
			info := &parentInfo{
				hash: p.Hash,
				data: p.Data,
			}
			parentInfos = append(parentInfos, info)
		}
		node.parentMetadata = parentInfos
	}
	if parents != nil {
		node.parents = parents
		node.height = node.parentsMaxHeight() + 1
	}
}
func newBlockNode(blockHeader *wire.BlockHeader, parentSubHeader *wire.ParentSubHeader,
	parents []*blockNode) *blockNode {
	var node blockNode
	initBlockNode(&node, blockHeader, parentSubHeader, parents)
	return &node
}
func (node *blockNode) parentsMaxHeight() int32 {
	if node.parents == nil {
		return int32(0)
	}
	var maxHeight int32
	for _, parent := range node.parents {
		if parent.height > maxHeight {
			maxHeight = parent.height
		}
	}
	return maxHeight
}
func generateTipsHash(tips []*blockNode) *chainhash.Hash {
	tipHashes := make([]*chainhash.Hash, len(tips))
	for i, tip := range tips {
		tipHashes[i] = &tip.hash
	}
	sort.Slice(tipHashes, func(i, j int) bool {
		return tipHashes[i].String() < tipHashes[j].String()
	})
	size := chainhash.HashSize * len(tipHashes)
	var concatBytes = make([]byte, size)
	for i, tipHash := range tipHashes {
		start := i * chainhash.HashSize
		end := (i + 1) * chainhash.HashSize
		copy(concatBytes[start:end], tipHash[:])
	}
	newHash := chainhash.DoubleHashH(concatBytes[:])
	return &newHash
}
func GenerateTipsHash(hashes []*chainhash.Hash) *chainhash.Hash {
	sort.Slice(hashes, func(i, j int) bool {
		return hashes[i].String() < hashes[j].String()
	})
	size := chainhash.HashSize * len(hashes)
	var concatBytes = make([]byte, size)
	for i, tipHash := range hashes {
		start := i * chainhash.HashSize
		end := (i + 1) * chainhash.HashSize
		copy(concatBytes[start:end], tipHash[:])
	}
	newHash := chainhash.DoubleHashH(concatBytes[:])
	return &newHash
}
func (node *blockNode) Header() wire.BlockHeader {
	prevHash := &zeroHash
	if node.parents != nil {
		prevHash = generateTipsHash(node.parents)
	}
	return wire.BlockHeader{
		Version:    node.version,
		PrevBlock:  *prevHash,
		MerkleRoot: node.merkleRoot,
		Timestamp:  time.Unix(node.timestamp, 0),
		Bits:       node.bits,
		Nonce:      node.nonce,
	}
}
func (node *blockNode) ParentSubHeader() wire.ParentSubHeader {
	parents := make([]*wire.Parent, len(node.parentMetadata))
	for i, pm := range node.parentMetadata {
		parents[i] = &wire.Parent{Hash: pm.hash, Data: pm.data}
	}
	return wire.ParentSubHeader{
		Version: node.parentVersion,
		Size:    int32(len(parents)),
		Parents: parents,
	}
}