func (b *BlockChain) CalcSequenceLock(tx *soterutil.Tx, utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) {
	b.chainLock.Lock()
	defer b.chainLock.Unlock()
	return b.calcSequenceLock(b.bestChain.Tip(), tx, utxoView, mempool)
}
CalcSequenceLock computes a relative lock-time SequenceLock for the passed
transaction using the passed UtxoViewpoint to obtain the past median time
for blocks in which the referenced inputs of the transactions were included
within. The generated SequenceLock lock can be used in conjunction with a
block height, and adjusted median block time to determine if all the inputs
referenced within a transaction have reached sufficient maturity allowing
the candidate transaction to be included in a block.

This function is safe for concurrent access.
package blockchain
import (
	"container/list"
	"fmt"
	"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/soterutil"
	"github.com/soteria-dag/soterd/txscript"
	"github.com/soteria-dag/soterd/wire"
)
const (
	maxOrphanBlocks = 100
)
type BlockLocator []*chainhash.Hash
type orphanBlock struct {
	block      *soterutil.Block
	expiration time.Time
}
type BestState struct {
	Hash        chainhash.Hash  
	Height      int32           
	Bits        uint32          
	BlockSize   uint64          
	BlockWeight uint64          
	NumTxns     uint64          
	TotalTxns   uint64          
	MedianTime  time.Time       
}
func newBestState(node *blockNode, blockSize, blockWeight, numTxns,
	totalTxns uint64, medianTime time.Time) *BestState {
	return &BestState{
		Hash:        node.hash,
		Height:      node.height,
		Bits:        node.bits,
		BlockSize:   blockSize,
		BlockWeight: blockWeight,
		NumTxns:     numTxns,
		TotalTxns:   totalTxns,
		MedianTime:  medianTime,
	}
}
type BlockChain struct {
	db           database.DB
	chainParams  *chaincfg.Params
	timeSource   MedianTimeSource
	sigCache     *txscript.SigCache
	indexManager IndexManager
	hashCache    *txscript.HashCache
	minRetargetTimespan int64  
	maxRetargetTimespan int64  
	blocksPerRetarget   int32  
	chainLock sync.RWMutex
	index     *blockIndex
	bestChain *chainView
	orphanLock   sync.RWMutex
	orphans      map[chainhash.Hash]*orphanBlock
	prevOrphans  map[chainhash.Hash][]*orphanBlock
	oldestOrphan *orphanBlock
	stateLock     sync.RWMutex
	stateSnapshot *BestState
	warningCaches    []thresholdStateCache
	deploymentCaches []thresholdStateCache
	unknownRulesWarned    bool
	unknownVersionsWarned bool
	notificationsLock sync.RWMutex
	notifications     []NotificationCallback
}
func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
	exists, err := b.blockExists(hash)
	if err != nil {
		return false, err
	}
	return exists || b.IsKnownOrphan(hash), nil
}
func (b *BlockChain) IsKnownOrphan(hash *chainhash.Hash) bool {
	b.orphanLock.RLock()
	_, exists := b.orphans[*hash]
	b.orphanLock.RUnlock()
	return exists
}
func (b *BlockChain) GetOrphanRoot(hash *chainhash.Hash) *chainhash.Hash {
	b.orphanLock.RLock()
	defer b.orphanLock.RUnlock()
	orphanRoot := hash
	prevHash := hash
	for {
		orphan, exists := b.orphans[*prevHash]
		if !exists {
			break
		}
		orphanRoot = prevHash
		prevHash = &orphan.block.MsgBlock().Header.PrevBlock
	}
	return orphanRoot
}
func (b *BlockChain) removeOrphanBlock(orphan *orphanBlock) {
	b.orphanLock.Lock()
	defer b.orphanLock.Unlock()
	orphanHash := orphan.block.Hash()
	delete(b.orphans, *orphanHash)
	prevHash := &orphan.block.MsgBlock().Header.PrevBlock
	orphans := b.prevOrphans[*prevHash]
	for i := 0; i < len(orphans); i++ {
		hash := orphans[i].block.Hash()
		if hash.IsEqual(orphanHash) {
			copy(orphans[i:], orphans[i+1:])
			orphans[len(orphans)-1] = nil
			orphans = orphans[:len(orphans)-1]
			i--
		}
	}
	b.prevOrphans[*prevHash] = orphans
	if len(b.prevOrphans[*prevHash]) == 0 {
		delete(b.prevOrphans, *prevHash)
	}
}
func (b *BlockChain) addOrphanBlock(block *soterutil.Block) {
	for _, oBlock := range b.orphans {
		if time.Now().After(oBlock.expiration) {
			b.removeOrphanBlock(oBlock)
			continue
		}
		if b.oldestOrphan == nil || oBlock.expiration.Before(b.oldestOrphan.expiration) {
			b.oldestOrphan = oBlock
		}
	}
	if len(b.orphans)+1 > maxOrphanBlocks {
		b.removeOrphanBlock(b.oldestOrphan)
		b.oldestOrphan = nil
	}
	b.orphanLock.Lock()
	defer b.orphanLock.Unlock()
	expiration := time.Now().Add(time.Hour)
	oBlock := &orphanBlock{
		block:      block,
		expiration: expiration,
	}
	b.orphans[*block.Hash()] = oBlock
	prevHash := &block.MsgBlock().Header.PrevBlock
	b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock)
}
type SequenceLock struct {
	Seconds     int64
	BlockHeight int32
}