gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/proto/merkleroots.go (about)

     1  package proto
     2  
     3  // TODO currently the cached trees are not persisted and we build them at
     4  // startup. For petabytes of data this might take a long time.
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  
    10  	"gitlab.com/NebulousLabs/errors"
    11  	"gitlab.com/SiaPrime/SiaPrime/build"
    12  	"gitlab.com/SiaPrime/SiaPrime/crypto"
    13  )
    14  
    15  // merkleRootsCacheHeight is the height of the subTrees in cachedSubTrees. A
    16  // height of 7 means that 128 sector roots are covered by a single cached
    17  // subTree.
    18  const merkleRootsCacheHeight = 7
    19  
    20  // merkleRootsPerCache is the number of merkle roots in a cached subTree of
    21  // merkleRootsCacheHeight height.
    22  const merkleRootsPerCache = 1 << merkleRootsCacheHeight
    23  
    24  type (
    25  	// merkleRoots is a helper struct that makes it easier to add/insert/remove
    26  	// merkleRoots within a SafeContract.
    27  	// Modifying the merkleRoots is not ACID. This means that the SafeContract
    28  	// has to make sure it uses the WAL correctly to guarantee ACID updates to
    29  	// the underlying file.
    30  	merkleRoots struct {
    31  		// cachedSubTrees are cached trees that can be used to more efficiently
    32  		// compute the merkle root of a contract.
    33  		cachedSubTrees []*cachedSubTree
    34  		// uncachedRoots contains the sector roots that are not part of a
    35  		// cached subTree. The uncachedRoots slice should never get longer than
    36  		// 2^merkleRootsCacheHeight since that would simply result in a new
    37  		// cached subTree in cachedSubTrees.
    38  		uncachedRoots []crypto.Hash
    39  
    40  		// rootsFile is the rootsFile of the safe contract that contains the roots.
    41  		rootsFile *fileSection
    42  		// numMerkleRoots is the number of merkle roots in file.
    43  		numMerkleRoots int
    44  	}
    45  
    46  	// cachedSubTree is a cached subTree of a merkle tree. A height of 0 means
    47  	// that the sum is the hash of a leaf. A subTree of height 1 means sum is
    48  	// the root of 2 leaves. A subTree of height 2 contains the root of 4
    49  	// leaves and so on.
    50  	cachedSubTree struct {
    51  		height int         // height of the subTree
    52  		sum    crypto.Hash // root of the subTree
    53  	}
    54  )
    55  
    56  // parseRootsFromData takes some data and splits it up into sector roots. It will return an error if the size of the data is not a multiple of crypto.HashSize.
    57  func parseRootsFromData(b []byte) ([]crypto.Hash, error) {
    58  	var roots []crypto.Hash
    59  	if len(b)%crypto.HashSize != 0 {
    60  		return roots, errors.New("roots have unexpected length and might be corrupted")
    61  	}
    62  
    63  	var root crypto.Hash
    64  	for len(b) > 0 {
    65  		copy(root[:], b[:crypto.HashSize])
    66  		roots = append(roots, root)
    67  		b = b[crypto.HashSize:]
    68  	}
    69  	return roots, nil
    70  }
    71  
    72  // loadExistingMerkleRoots reads creates a merkleRoots object from existing
    73  // merkle roots. If the file has an unexpected length, we truncate it and
    74  // return a boolean to indicate that the last write was incomplete and that the
    75  // unapplied wal transactions should be applied after loading the roots.
    76  func loadExistingMerkleRoots(file *fileSection) (*merkleRoots, bool, error) {
    77  	mr := &merkleRoots{
    78  		rootsFile: file,
    79  	}
    80  	applyTxns := false
    81  	// Get the filesize and truncate the file if necessary.
    82  	size, err := file.Size()
    83  	if err != nil {
    84  		return nil, applyTxns, err
    85  	}
    86  	if mod := size % crypto.HashSize; mod != 0 {
    87  		if err := file.Truncate(size - mod); err != nil {
    88  			return nil, applyTxns, err
    89  		}
    90  		applyTxns = true
    91  	}
    92  	// Get the number of roots stored in the file.
    93  	mr.numMerkleRoots, err = mr.lenFromFile()
    94  	if err != nil {
    95  		return nil, applyTxns, err
    96  	}
    97  	// Read the roots from the file without reading all of them at once.
    98  	readOff := int64(0)
    99  	rootsData := make([]byte, rootsDiskLoadBulkSize)
   100  	for {
   101  		n, err := file.ReadAt(rootsData, readOff)
   102  		if err == io.ErrUnexpectedEOF && n == 0 {
   103  			break
   104  		}
   105  		if err == io.EOF && n == 0 {
   106  			break
   107  		}
   108  		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
   109  			return nil, applyTxns, err
   110  		}
   111  		roots, err := parseRootsFromData(rootsData[:n])
   112  		if err != nil {
   113  			return nil, applyTxns, err
   114  		}
   115  		mr.appendRootMemory(roots...)
   116  		readOff += int64(n)
   117  	}
   118  	return mr, applyTxns, nil
   119  }
   120  
   121  // newCachedSubTree creates a cachedSubTree from exactly
   122  // 2^merkleRootsCacheHeight roots.
   123  func newCachedSubTree(roots []crypto.Hash) *cachedSubTree {
   124  	// Sanity check the input length.
   125  	if len(roots) != merkleRootsPerCache {
   126  		build.Critical("can't create a cached subTree from the provided number of roots")
   127  	}
   128  	return &cachedSubTree{
   129  		height: int(merkleRootsCacheHeight + sectorHeight),
   130  		sum:    cachedMerkleRoot(roots),
   131  	}
   132  }
   133  
   134  // newMerkleRoots creates a new merkleRoots object. This doesn't load existing
   135  // roots from file and will assume that the file doesn't contain any roots.
   136  // Don't use this on a file that contains roots.
   137  func newMerkleRoots(file *fileSection) *merkleRoots {
   138  	return &merkleRoots{
   139  		rootsFile: file,
   140  	}
   141  }
   142  
   143  // fileOffsetFromRootIndex calculates the offset of the merkle root at index i from
   144  // the beginning of the contract file.
   145  func fileOffsetFromRootIndex(i int) int64 {
   146  	return crypto.HashSize * int64(i)
   147  }
   148  
   149  // appendRootMemory appends a root to the in-memory structure of the merkleRoots. If
   150  // the length of the uncachedRoots grows too large they will be compressed into
   151  // a cachedSubTree.
   152  func (mr *merkleRoots) appendRootMemory(roots ...crypto.Hash) {
   153  	for _, root := range roots {
   154  		mr.uncachedRoots = append(mr.uncachedRoots, root)
   155  		if len(mr.uncachedRoots) == merkleRootsPerCache {
   156  			mr.cachedSubTrees = append(mr.cachedSubTrees, newCachedSubTree(mr.uncachedRoots))
   157  			mr.uncachedRoots = mr.uncachedRoots[:0]
   158  		}
   159  	}
   160  }
   161  
   162  // delete deletes the sector root at a certain index by replacing it with the
   163  // last root and truncates the file to truncateSize after that. This ensures
   164  // that the operation is indempotent.
   165  func (mr *merkleRoots) delete(i int, lastRoot crypto.Hash, truncateSize int64) error {
   166  	// Swap the element at index i with the lastRoot. This might actually
   167  	// increase mr.numMerkleRoots since there is a chance that i points to an
   168  	// index after the end of the file. That's why the insert is executed first
   169  	// before truncating the file or decreasing the numMerkleRoots field.
   170  	if err := mr.insert(i, lastRoot); err != nil {
   171  		return errors.AddContext(err, "failed to swap deleted root with newRoot")
   172  	}
   173  	// Truncate the file to truncateSize.
   174  	if err := mr.rootsFile.Truncate(truncateSize); err != nil {
   175  		return errors.AddContext(err, "failed to truncate file")
   176  	}
   177  	// Adjust the numMerkleRoots field. If the number of roots didn't change we
   178  	// are done.
   179  	rootsBefore := mr.numMerkleRoots
   180  	mr.numMerkleRoots = int(truncateSize / crypto.HashSize)
   181  	if rootsBefore == mr.numMerkleRoots {
   182  		return nil
   183  	}
   184  	// Sanity check the number of roots.
   185  	if rootsBefore != mr.numMerkleRoots+1 {
   186  		build.Critical("a delete should never delete more than one root at once")
   187  	}
   188  	// If the last element is uncached we can simply remove it from the slice.
   189  	if len(mr.uncachedRoots) > 0 {
   190  		mr.uncachedRoots = mr.uncachedRoots[:len(mr.uncachedRoots)-1]
   191  		return nil
   192  	}
   193  	// If it is not uncached we need to delete the last cached tree and load
   194  	// its elements into mr.uncachedRoots. This should give us
   195  	// merkleRootsPerCache-1 uncached roots since we already truncated the file
   196  	// by 1 root.
   197  	if err := mr.moveLastCachedSubTreeToUncached(); err != nil {
   198  		return err
   199  	}
   200  	return nil
   201  }
   202  
   203  // insert inserts a root by replacing a root at an existing index.
   204  func (mr *merkleRoots) insert(index int, root crypto.Hash) error {
   205  	// If the index does point to an offset beyond the end of the file we fill
   206  	// in the blanks with empty merkle roots. This usually just means that the
   207  	// machine crashed during the recovery process and that the next few
   208  	// updates are probably going to be delete operations that take care of the
   209  	// blank roots.
   210  	for index > mr.numMerkleRoots {
   211  		if err := mr.push(crypto.Hash{}); err != nil {
   212  			return errors.AddContext(err, "failed to extend roots")
   213  		}
   214  	}
   215  	if index == mr.numMerkleRoots {
   216  		return mr.push(root)
   217  	}
   218  	// Replaced the root on disk.
   219  	_, err := mr.rootsFile.WriteAt(root[:], fileOffsetFromRootIndex(index))
   220  	if err != nil {
   221  		return errors.AddContext(err, "failed to insert root on disk")
   222  	}
   223  
   224  	// Find out if the root is in mr.cachedSubTree or mr.uncachedRoots.
   225  	i, cached := mr.isIndexCached(index)
   226  	// If the root was not cached we can simply replace it in mr.uncachedRoots.
   227  	if !cached {
   228  		mr.uncachedRoots[i] = root
   229  		return nil
   230  	}
   231  	// If the root was cached we need to rebuild the cache.
   232  	if err := mr.rebuildCachedTree(i); err != nil {
   233  		return errors.AddContext(err, "failed to rebuild cache for inserted root")
   234  	}
   235  	return nil
   236  }
   237  
   238  // set replaces the full set of roots.
   239  func (mr *merkleRoots) set(roots []crypto.Hash) error {
   240  	for i, root := range roots {
   241  		_, err := mr.rootsFile.WriteAt(root[:], fileOffsetFromRootIndex(i))
   242  		if err != nil {
   243  			return errors.AddContext(err, "failed to insert root on disk")
   244  		}
   245  	}
   246  	truncateSize := int64(len(roots)) * crypto.HashSize
   247  	if err := mr.rootsFile.Truncate(truncateSize); err != nil {
   248  		return errors.AddContext(err, "failed to truncate file")
   249  	}
   250  	return nil
   251  }
   252  
   253  // isIndexCached determines if the root at index i is already cached in
   254  // mr.cachedSubTree or if it is still in mr.uncachedRoots. It will return true
   255  // or false and the index of the root in the corresponding data structure.
   256  func (mr *merkleRoots) isIndexCached(i int) (int, bool) {
   257  	if i/merkleRootsPerCache == len(mr.cachedSubTrees) {
   258  		// Root is not cached. Return the false and the position in
   259  		// mr.uncachedRoots
   260  		return i - len(mr.cachedSubTrees)*merkleRootsPerCache, false
   261  	}
   262  	return i / merkleRootsPerCache, true
   263  }
   264  
   265  // lenFromFile returns the number of merkle roots by computing it from the
   266  // filesize.
   267  func (mr *merkleRoots) lenFromFile() (int, error) {
   268  	size, err := mr.rootsFile.Size()
   269  	if err != nil {
   270  		return 0, err
   271  	}
   272  
   273  	// Sanity check contract file length.
   274  	if size%crypto.HashSize != 0 {
   275  		return 0, errors.New("contract file has unexpected length and might be corrupted")
   276  	}
   277  	return int(size / crypto.HashSize), nil
   278  }
   279  
   280  // len returns the number of merkle roots. It should always return the same
   281  // number as lenFromFile.
   282  func (mr *merkleRoots) len() int {
   283  	return mr.numMerkleRoots
   284  }
   285  
   286  // moveLastCachedSubTreeToUncached deletes the last cached subTree and appends
   287  // its elements to the uncached roots.
   288  func (mr *merkleRoots) moveLastCachedSubTreeToUncached() error {
   289  	mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
   290  	rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
   291  	roots, err := mr.merkleRootsFromIndexFromDisk(rootIndex, mr.numMerkleRoots)
   292  	if err != nil {
   293  		return errors.AddContext(err, "failed to read cached tree's roots")
   294  	}
   295  	mr.uncachedRoots = append(mr.uncachedRoots, roots...)
   296  	return nil
   297  }
   298  
   299  // push appends a merkle root to the end of the contract. If the number of
   300  // uncached merkle roots grows too big we cache them in a new subTree.
   301  func (mr *merkleRoots) push(root crypto.Hash) error {
   302  	// Sanity check the number of uncached roots before adding a new one.
   303  	if len(mr.uncachedRoots) == merkleRootsPerCache {
   304  		build.Critical("the number of uncachedRoots is too big. They should've been cached by now")
   305  	}
   306  	// Calculate the root offset within the file and write it to disk.
   307  	rootOffset := fileOffsetFromRootIndex(mr.len())
   308  	if _, err := mr.rootsFile.WriteAt(root[:], rootOffset); err != nil {
   309  		return err
   310  	}
   311  	// Add the root to the unached roots.
   312  	mr.appendRootMemory(root)
   313  
   314  	// Increment the number of roots.
   315  	mr.numMerkleRoots++
   316  	return nil
   317  }
   318  
   319  // root returns the root of the merkle roots.
   320  func (mr *merkleRoots) root() crypto.Hash {
   321  	tree := crypto.NewTree()
   322  	for _, st := range mr.cachedSubTrees {
   323  		if err := tree.PushSubTree(st.height, st.sum[:]); err != nil {
   324  			// This should never fail.
   325  			build.Critical(err)
   326  		}
   327  	}
   328  	for _, root := range mr.uncachedRoots {
   329  		tree.Push(root[:])
   330  	}
   331  	return tree.Root()
   332  }
   333  
   334  // checkNewRoot returns the root of the merkleTree after appending the checkNewRoot
   335  // without actually appending it.
   336  func (mr *merkleRoots) checkNewRoot(newRoot crypto.Hash) crypto.Hash {
   337  	tree := crypto.NewCachedTree(sectorHeight)
   338  	for _, st := range mr.cachedSubTrees {
   339  		if err := tree.PushSubTree(st.height, st.sum); err != nil {
   340  			// This should never fail.
   341  			build.Critical(err)
   342  		}
   343  	}
   344  	for _, root := range mr.uncachedRoots {
   345  		tree.Push(root)
   346  	}
   347  	// Push the new root.
   348  	tree.Push(newRoot)
   349  	return tree.Root()
   350  }
   351  
   352  // merkleRoots reads all the merkle roots from disk and returns them.
   353  func (mr *merkleRoots) merkleRoots() (roots []crypto.Hash, err error) {
   354  	// Get roots.
   355  	roots, err = mr.merkleRootsFromIndexFromDisk(0, mr.numMerkleRoots)
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	// Sanity check: should have read exactly numMerkleRoots roots.
   360  	if len(roots) != mr.numMerkleRoots {
   361  		build.Critical(fmt.Sprintf("Number of merkle roots on disk (%v) doesn't match numMerkleRoots (%v)",
   362  			len(roots), mr.numMerkleRoots))
   363  	}
   364  	return
   365  }
   366  
   367  // merkleRootsFrom index reads all the merkle roots in range [from;to)
   368  func (mr *merkleRoots) merkleRootsFromIndexFromDisk(from, to int) ([]crypto.Hash, error) {
   369  	merkleRoots := make([]crypto.Hash, 0, to-from)
   370  	remainingData := fileOffsetFromRootIndex(to) - fileOffsetFromRootIndex(from)
   371  	readOff := fileOffsetFromRootIndex(from)
   372  	var rootsData []byte
   373  	for remainingData > 0 {
   374  		if remainingData > rootsDiskLoadBulkSize {
   375  			rootsData = make([]byte, rootsDiskLoadBulkSize)
   376  		} else {
   377  			rootsData = make([]byte, remainingData)
   378  		}
   379  		n, err := mr.rootsFile.ReadAt(rootsData, readOff)
   380  		if err == io.ErrUnexpectedEOF || err == io.EOF {
   381  			return nil, errors.New("merkleRootsFromIndexFromDisk failed: roots have unexpected length")
   382  		}
   383  		if err != nil {
   384  			return nil, err
   385  		}
   386  		roots, err := parseRootsFromData(rootsData)
   387  		if err != nil {
   388  			return nil, err
   389  		}
   390  		merkleRoots = append(merkleRoots, roots...)
   391  		readOff += int64(n)
   392  		remainingData -= int64(n)
   393  	}
   394  	return merkleRoots, nil
   395  }
   396  
   397  // prepareDelete is a helper function that returns the lastRoot and trunateSize
   398  // arguments for a certain index to call delete with.
   399  func (mr *merkleRoots) prepareDelete(index int) (lastRoot crypto.Hash, truncateSize int64, err error) {
   400  	roots, err := mr.merkleRootsFromIndexFromDisk(mr.numMerkleRoots-1, mr.numMerkleRoots)
   401  	if err != nil {
   402  		return crypto.Hash{}, 0, errors.AddContext(err, "failed to get last root")
   403  	}
   404  	if len(roots) != 1 {
   405  		return crypto.Hash{}, 0, fmt.Errorf("expected exactly 1 root but got %v", len(roots))
   406  	}
   407  	return roots[0], int64((mr.numMerkleRoots - 1) * crypto.HashSize), nil
   408  }
   409  
   410  // rebuildCachedTree rebuilds the tree in mr.cachedSubTree at index i.
   411  func (mr *merkleRoots) rebuildCachedTree(index int) error {
   412  	// Find the index of the first root of the cached tree on disk.
   413  	rootIndex := index * merkleRootsPerCache
   414  	// Read all the roots necessary for creating the cached tree.
   415  	roots, err := mr.merkleRootsFromIndexFromDisk(rootIndex, rootIndex+(1<<merkleRootsCacheHeight))
   416  	if err != nil {
   417  		return errors.AddContext(err, "failed to read sectors for rebuilding cached tree")
   418  	}
   419  	// Replace the old cached tree.
   420  	mr.cachedSubTrees[index] = newCachedSubTree(roots)
   421  	return nil
   422  }