github.com/0chain/gosdk@v1.17.11/zboxcore/encoder/erasurecode.go (about)

     1  // Stream Encoder for erasure coding.
     2  package encoder
     3  
     4  import (
     5  	"bufio"
     6  	"bytes"
     7  
     8  	"errors"
     9  
    10  	l "github.com/0chain/gosdk/zboxcore/logger"
    11  
    12  	"github.com/klauspost/reedsolomon"
    13  )
    14  
    15  type StreamEncoder struct {
    16  	iDataShards   int
    17  	iParityShards int
    18  	erasureCode   reedsolomon.Encoder
    19  	data          [][]byte
    20  }
    21  
    22  // Creates New encoder instance and return index for further access
    23  func NewEncoder(iDataShards, iParityShards int) (*StreamEncoder, error) {
    24  	e := &StreamEncoder{}
    25  	var err error
    26  
    27  	e.erasureCode, err = reedsolomon.New(iDataShards, iParityShards, reedsolomon.WithAutoGoroutines(64*1024))
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	e.iDataShards = iDataShards
    32  	e.iParityShards = iParityShards
    33  	return e, nil
    34  }
    35  
    36  // Encodes and returns the shards on success and error on fails
    37  func (e *StreamEncoder) Encode(in []byte) ([][]byte, error) {
    38  	var err error
    39  	e.data, err = e.erasureCode.Split(in)
    40  	if err != nil {
    41  		l.Logger.Error("Split failed", err.Error())
    42  		return [][]byte{}, err
    43  	}
    44  
    45  	err = e.erasureCode.Encode(e.data)
    46  	if err != nil {
    47  		l.Logger.Error("Encode failed", err.Error())
    48  		return [][]byte{}, err
    49  	}
    50  	return e.data, nil
    51  }
    52  
    53  func (e *StreamEncoder) Decode(in [][]byte, shardSize int) ([]byte, error) {
    54  	// Verify the input
    55  	if (len(in) < e.iDataShards+e.iParityShards) || (shardSize <= 0) {
    56  		return []byte{}, errors.New("Invalid input length")
    57  	}
    58  
    59  	err := e.erasureCode.Reconstruct(in)
    60  	if err != nil {
    61  		l.Logger.Error("Reconstruct failed -", err)
    62  		return []byte{}, err
    63  	}
    64  	_, err = e.erasureCode.Verify(in)
    65  	if err != nil {
    66  		l.Logger.Error("Verification failed after reconstruction, data likely corrupted.", err.Error())
    67  		return []byte{}, err
    68  	}
    69  
    70  	var bytesBuf bytes.Buffer
    71  	bufWriter := bufio.NewWriter(&bytesBuf)
    72  	bufWriter = bufio.NewWriterSize(bufWriter, (shardSize * e.iDataShards))
    73  	err = e.erasureCode.Join(bufWriter, in, (shardSize * e.iDataShards))
    74  	if err != nil {
    75  		l.Logger.Error("join failed", err.Error())
    76  		return []byte{}, err
    77  	}
    78  	bufWriter.Flush()
    79  	outBuf := bytesBuf.Bytes()
    80  	return outBuf, nil
    81  }