github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/chunked_upload_hasher.go (about)

     1  package sdk
     2  
     3  import (
     4  	"crypto/md5"
     5  	"encoding/hex"
     6  	"hash"
     7  	"sync"
     8  
     9  	"github.com/0chain/errors"
    10  	"github.com/0chain/gosdk/constants"
    11  	"github.com/0chain/gosdk/core/util"
    12  )
    13  
    14  // Hasher interface to gather all hasher related functions.
    15  // A hasher is used to calculate the hash of a file, fixed merkle tree, and validation merkle tree.
    16  type Hasher interface {
    17  	// GetFileHash get file hash
    18  	GetFileHash() (string, error)
    19  	// WriteToFile write bytes to file hasher
    20  	WriteToFile(buf []byte) error
    21  
    22  	GetFixedMerkleRoot() (string, error)
    23  	// WriteToFixedMT write bytes to FMT hasher
    24  	WriteToFixedMT(buf []byte) error
    25  
    26  	GetValidationRoot() (string, error)
    27  	// WriteToValidationMT write bytes Validation Tree hasher
    28  	WriteToValidationMT(buf []byte) error
    29  	// Finalize will let merkle tree know that tree is finalized with the content it has received
    30  	Finalize() error
    31  }
    32  
    33  // see more detail about hash on  https://github.com/0chain/blobber/wiki/Protocols#file-hash
    34  type hasher struct {
    35  	File         hash.Hash             `json:"-"`
    36  	FixedMT      *util.FixedMerkleTree `json:"fixed_merkle_tree"`
    37  	ValidationMT *util.ValidationTree  `json:"validation_merkle_tree"`
    38  }
    39  
    40  // CreateHasher creat Hasher instance
    41  func CreateHasher(dataSize int64) Hasher {
    42  	return &hasher{
    43  		File:         md5.New(),
    44  		FixedMT:      util.NewFixedMerkleTree(),
    45  		ValidationMT: util.NewValidationTree(dataSize),
    46  	}
    47  }
    48  
    49  func CreateFileHasher() Hasher {
    50  	return &hasher{
    51  		File: md5.New(),
    52  	}
    53  }
    54  
    55  func (h *hasher) GetFileHash() (string, error) {
    56  	if h == nil {
    57  		return "", errors.Throw(constants.ErrInvalidParameter, "h")
    58  	}
    59  
    60  	if h.File == nil {
    61  		return "", errors.Throw(constants.ErrInvalidParameter, "h.File")
    62  	}
    63  	return hex.EncodeToString(h.File.Sum(nil)), nil
    64  }
    65  
    66  // WriteToFile write bytes to file hasher
    67  func (h *hasher) WriteToFile(buf []byte) error {
    68  	if h == nil {
    69  		return errors.Throw(constants.ErrInvalidParameter, "h")
    70  	}
    71  
    72  	if h.File == nil {
    73  		return errors.Throw(constants.ErrInvalidParameter, "h.File")
    74  	}
    75  
    76  	_, err := h.File.Write(buf)
    77  	return err
    78  }
    79  
    80  func (h *hasher) GetFixedMerkleRoot() (string, error) {
    81  	if h == nil {
    82  		return "", errors.Throw(constants.ErrInvalidParameter, "h")
    83  	}
    84  
    85  	if h.FixedMT == nil {
    86  		return "", errors.Throw(constants.ErrInvalidParameter, "h.Challenge")
    87  	}
    88  
    89  	return h.FixedMT.GetMerkleRoot(), nil
    90  }
    91  
    92  func (h *hasher) WriteToFixedMT(buf []byte) error {
    93  	if h == nil {
    94  		return errors.Throw(constants.ErrInvalidParameter, "h")
    95  	}
    96  
    97  	if h.FixedMT == nil {
    98  		return errors.Throw(constants.ErrInvalidParameter, "h.Challenge")
    99  	}
   100  	_, err := h.FixedMT.Write(buf)
   101  	return err
   102  }
   103  
   104  func (h *hasher) GetValidationRoot() (string, error) {
   105  	if h == nil {
   106  		return "", errors.Throw(constants.ErrInvalidParameter, "h")
   107  	}
   108  
   109  	if h.ValidationMT == nil {
   110  		return "", errors.Throw(constants.ErrInvalidParameter, "h.Content")
   111  	}
   112  
   113  	return hex.EncodeToString(h.ValidationMT.GetValidationRoot()), nil
   114  }
   115  
   116  func (h *hasher) WriteToValidationMT(buf []byte) error {
   117  	if h == nil {
   118  		return errors.Throw(constants.ErrInvalidParameter, "h")
   119  	}
   120  
   121  	if h.ValidationMT == nil {
   122  		return errors.Throw(constants.ErrInvalidParameter, "h.Content")
   123  	}
   124  	_, err := h.ValidationMT.Write(buf)
   125  	return err
   126  }
   127  
   128  func (h *hasher) Finalize() error {
   129  	var (
   130  		wg      sync.WaitGroup
   131  		errChan = make(chan error, 2)
   132  	)
   133  	wg.Add(2)
   134  	go func() {
   135  		if err := h.FixedMT.Finalize(); err != nil {
   136  			errChan <- err
   137  		}
   138  		wg.Done()
   139  	}()
   140  	go func() {
   141  		if err := h.ValidationMT.Finalize(); err != nil {
   142  			errChan <- err
   143  		}
   144  		wg.Done()
   145  	}()
   146  	wg.Wait()
   147  	close(errChan)
   148  	for err := range errChan {
   149  		return err
   150  	}
   151  	return nil
   152  }