func (mr *merkleRoots) checkNewRoot(newRoot crypto.Hash) crypto.Hash {
	tree := crypto.NewCachedTree(sectorHeight)
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum); err != nil {
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root)
	}
	tree.Push(newRoot)
	return tree.Root()
}
checkNewRoot returns the root of the merkleTree after appending the checkNewRoot
without actually appending it.
package proto
import (
	"fmt"
	"io"
	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/errors"
)
const merkleRootsCacheHeight = 7
const merkleRootsPerCache = 1 << merkleRootsCacheHeight
type (
	merkleRoots struct {
		cachedSubTrees []*cachedSubTree
		uncachedRoots []crypto.Hash
		rootsFile *fileSection
		numMerkleRoots int
	}
	cachedSubTree struct {
		height int          
		sum    crypto.Hash  
	}
)
func parseRootsFromData(b []byte) ([]crypto.Hash, error) {
	var roots []crypto.Hash
	if len(b)%crypto.HashSize != 0 {
		return roots, errors.New("roots have unexpected length and might be corrupted")
	}
	var root crypto.Hash
	for len(b) > 0 {
		copy(root[:], b[:crypto.HashSize])
		roots = append(roots, root)
		b = b[crypto.HashSize:]
	}
	return roots, nil
}
func loadExistingMerkleRoots(file *fileSection) (*merkleRoots, error) {
	mr := &merkleRoots{
		rootsFile: file,
	}
	var err error
	mr.numMerkleRoots, err = mr.lenFromFile()
	if err != nil {
		return nil, err
	}
	readOff := int64(0)
	rootsData := make([]byte, rootsDiskLoadBulkSize)
	for {
		n, err := file.ReadAt(rootsData, readOff)
		if err == io.ErrUnexpectedEOF && n == 0 {
			break
		}
		if err == io.EOF && n == 0 {
			break
		}
		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
			return nil, err
		}
		roots, err := parseRootsFromData(rootsData[:n])
		if err != nil {
			return nil, err
		}
		mr.appendRootMemory(roots...)
		readOff += int64(n)
	}
	return mr, nil
}
func newCachedSubTree(roots []crypto.Hash) *cachedSubTree {
	if len(roots) != merkleRootsPerCache {
		build.Critical("can't create a cached subTree from the provided number of roots")
	}
	return &cachedSubTree{
		height: int(merkleRootsCacheHeight + sectorHeight),
		sum:    cachedMerkleRoot(roots),
	}
}
func newMerkleRoots(file *fileSection) *merkleRoots {
	return &merkleRoots{
		rootsFile: file,
	}
}
func fileOffsetFromRootIndex(i int) int64 {
	return crypto.HashSize * int64(i)
}
func (mr *merkleRoots) appendRootMemory(roots ...crypto.Hash) {
	for _, root := range roots {
		mr.uncachedRoots = append(mr.uncachedRoots, root)
		if len(mr.uncachedRoots) == merkleRootsPerCache {
			mr.cachedSubTrees = append(mr.cachedSubTrees, newCachedSubTree(mr.uncachedRoots))
			mr.uncachedRoots = mr.uncachedRoots[:0]
		}
	}
}
func (mr *merkleRoots) delete(i int, lastRoot crypto.Hash, truncateSize int64) error {
	if err := mr.insert(i, lastRoot); err != nil {
		return errors.AddContext(err, "failed to swap deleted root with newRoot")
	}
	if err := mr.rootsFile.Truncate(truncateSize); err != nil {
		return errors.AddContext(err, "failed to truncate file")
	}
	rootsBefore := mr.numMerkleRoots
	mr.numMerkleRoots = int(truncateSize / crypto.HashSize)
	if rootsBefore == mr.numMerkleRoots {
		return nil
	}
	if rootsBefore != mr.numMerkleRoots+1 {
		build.Critical("a delete should never delete more than one root at once")
	}
	if len(mr.uncachedRoots) > 0 {
		mr.uncachedRoots = mr.uncachedRoots[:len(mr.uncachedRoots)-1]
		return nil
	}
	if err := mr.moveLastCachedSubTreeToUncached(); err != nil {
		return err
	}
	return nil
}
func (mr *merkleRoots) insert(index int, root crypto.Hash) error {
	for index > mr.numMerkleRoots {
		if err := mr.push(crypto.Hash{}); err != nil {
			return errors.AddContext(err, "failed to extend roots")
		}
	}
	if index == mr.numMerkleRoots {
		return mr.push(root)
	}
	_, err := mr.rootsFile.WriteAt(root[:], fileOffsetFromRootIndex(index))
	if err != nil {
		return errors.AddContext(err, "failed to insert root on disk")
	}
	i, cached := mr.isIndexCached(index)
	if !cached {
		mr.uncachedRoots[i] = root
		return nil
	}
	if err := mr.rebuildCachedTree(i); err != nil {
		return errors.AddContext(err, "failed to rebuild cache for inserted root")
	}
	return nil
}
func (mr *merkleRoots) isIndexCached(i int) (int, bool) {
	if i/merkleRootsPerCache == len(mr.cachedSubTrees) {
		return i - len(mr.cachedSubTrees)*merkleRootsPerCache, false
	}
	return i / merkleRootsPerCache, true
}
func (mr *merkleRoots) lenFromFile() (int, error) {
	size, err := mr.rootsFile.Size()
	if err != nil {
		return 0, err
	}
	if size%crypto.HashSize != 0 {
		return 0, errors.New("contract file has unexpected length and might be corrupted")
	}
	return int(size / crypto.HashSize), nil
}
func (mr *merkleRoots) len() int {
	return mr.numMerkleRoots
}
func (mr *merkleRoots) moveLastCachedSubTreeToUncached() error {
	mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
	rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
	roots, err := mr.merkleRootsFromIndexFromDisk(rootIndex, mr.numMerkleRoots)
	if err != nil {
		return errors.AddContext(err, "failed to read cached tree's roots")
	}
	mr.uncachedRoots = append(mr.uncachedRoots, roots...)
	return nil
}
func (mr *merkleRoots) push(root crypto.Hash) error {
	if len(mr.uncachedRoots) == merkleRootsPerCache {
		build.Critical("the number of uncachedRoots is too big. They should've been cached by now")
	}
	rootOffset := fileOffsetFromRootIndex(mr.len())
	if _, err := mr.rootsFile.WriteAt(root[:], rootOffset); err != nil {
		return err
	}
	mr.appendRootMemory(root)
	mr.numMerkleRoots++
	return nil
}
func (mr *merkleRoots) root() crypto.Hash {
	tree := crypto.NewTree()
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum[:]); err != nil {
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root[:])
	}
	return tree.Root()
}