-
Notifications
You must be signed in to change notification settings - Fork 271
/
split_sparse_shares.go
110 lines (94 loc) · 2.82 KB
/
split_sparse_shares.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package shares
import (
"errors"
"fmt"
"github.com/celestiaorg/celestia-app/pkg/appconsts"
appns "github.com/celestiaorg/celestia-app/pkg/namespace"
coretypes "github.com/tendermint/tendermint/types"
"golang.org/x/exp/slices"
)
// SparseShareSplitter lazily splits blobs into shares that will eventually be
// included in a data square. It also has methods to help progressively count
// how many shares the blobs written take up.
type SparseShareSplitter struct {
shares []Share
}
func NewSparseShareSplitter() *SparseShareSplitter {
return &SparseShareSplitter{}
}
// Write writes the provided blob to this sparse share splitter. It returns an
// error or nil if no error is encountered.
func (sss *SparseShareSplitter) Write(blob coretypes.Blob) error {
if !slices.Contains(appconsts.SupportedShareVersions, blob.ShareVersion) {
return fmt.Errorf("unsupported share version: %d", blob.ShareVersion)
}
rawData := blob.Data
blobNamespace, err := appns.New(blob.NamespaceVersion, blob.NamespaceID)
if err != nil {
return err
}
// First share
b, err := NewBuilder(blobNamespace, blob.ShareVersion, true).Init()
if err != nil {
return err
}
if err := b.WriteSequenceLen(uint32(len(rawData))); err != nil {
return err
}
for rawData != nil {
rawDataLeftOver := b.AddData(rawData)
if rawDataLeftOver == nil {
// Just call it on the latest share
b.ZeroPadIfNecessary()
}
share, err := b.Build()
if err != nil {
return err
}
sss.shares = append(sss.shares, *share)
b, err = NewBuilder(blobNamespace, blob.ShareVersion, false).Init()
if err != nil {
return err
}
rawData = rawDataLeftOver
}
return nil
}
// WriteNamespacePaddingShares adds padding shares with the namespace of the
// last written share. This is useful to follow the non-interactive default
// rules. This function assumes that at least one share has already been
// written.
func (sss *SparseShareSplitter) WriteNamespacePaddingShares(count int) error {
if count < 0 {
return errors.New("cannot write negative namespaced shares")
}
if count == 0 {
return nil
}
if len(sss.shares) == 0 {
return errors.New("cannot write namespace padding shares on an empty SparseShareSplitter")
}
lastBlob := sss.shares[len(sss.shares)-1]
lastBlobNs, err := lastBlob.Namespace()
if err != nil {
return err
}
lastBlobInfo, err := lastBlob.InfoByte()
if err != nil {
return err
}
nsPaddingShares, err := NamespacePaddingShares(lastBlobNs, lastBlobInfo.Version(), count)
if err != nil {
return err
}
sss.shares = append(sss.shares, nsPaddingShares...)
return nil
}
// Export finalizes and returns the underlying shares.
func (sss *SparseShareSplitter) Export() []Share {
return sss.shares
}
// Count returns the current number of shares that will be made if exporting.
func (sss *SparseShareSplitter) Count() int {
return len(sss.shares)
}