diff --git a/blob/blob.go b/blob/blob.go index c5fd04c782..5c1419e363 100644 --- a/blob/blob.go +++ b/blob/blob.go @@ -8,6 +8,7 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/celestiaorg/celestia-app/pkg/appconsts" + "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-app/x/blob/types" "github.com/celestiaorg/nmt" @@ -138,3 +139,37 @@ func (b *Blob) UnmarshalJSON(data []byte) error { b.namespace = blob.Namespace return nil } + +// createBlobs creates and returns blobs from the passed shares. In case if blob is incomplete, then +// the shares of the incomplete blob will be returned. +func createBlobs(appShares []shares.Share) ([]*Blob, []shares.Share, error) { + blobs := make([]*Blob, 0) + for { + if len(appShares) == 0 { + return blobs, nil, nil + } + + length, err := appShares[0].SequenceLen() + if err != nil { + return nil, nil, err + } + + amount := shares.SparseSharesNeeded(length) + if amount > len(appShares) { + return blobs, appShares, nil + } + + b, err := parseShares(appShares[:amount]) + if err != nil { + return nil, nil, err + } + + // only 1 blob will be created bc we passed the exact amount of shares + blobs = append(blobs, b[0]) + + if amount == len(appShares) { + return blobs, nil, nil + } + appShares = appShares[amount:] + } +} diff --git a/blob/helper.go b/blob/helper.go index 5627fac998..72a56c7889 100644 --- a/blob/helper.go +++ b/blob/helper.go @@ -17,16 +17,16 @@ func SharesToBlobs(rawShares []share.Share) ([]*Blob, error) { return nil, ErrBlobNotFound } - appShares := make([]shares.Share, 0, len(rawShares)) - for _, shr := range rawShares { - bShare, err := shares.NewShare(shr) - if err != nil { - return nil, err - } - appShares = append(appShares, *bShare) + appShares, err := toAppShares(rawShares...) + if err != nil { + return nil, err } + return parseShares(appShares) +} - shareSequences, err := shares.ParseShares(appShares, true) +// parseShares takes shares and converts them to the []*Blob. +func parseShares(appShrs []shares.Share) ([]*Blob, error) { + shareSequences, err := shares.ParseShares(appShrs, true) if err != nil { return nil, err } @@ -84,14 +84,3 @@ func BlobsToShares(blobs ...*Blob) ([]share.Share, error) { } return shares.ToBytes(rawShares), nil } - -// constructAndVerifyBlob reconstruct a Blob from the passed shares and compares commitments. -func constructAndVerifyBlob(sh []share.Share, commitment Commitment) (*Blob, bool, error) { - blob, err := SharesToBlobs(sh) - if err != nil { - return nil, false, err - } - - equal := blob[0].Commitment.Equal(commitment) - return blob[0], equal, nil -} diff --git a/blob/service.go b/blob/service.go index cf3daff7de..196e464bb4 100644 --- a/blob/service.go +++ b/blob/service.go @@ -198,10 +198,10 @@ func (s *Service) getByCommitment( } var ( - rawShares = make([]share.Share, 0) + rawShares = make([]shares.Share, 0) proofs = make(Proof, 0) - amount int - blobShare *shares.Share + // expanded specifies whether blob is expanded into multiple rows + expanded bool ) namespacedShares, err := s.shareGetter.GetSharesByNamespace(ctx, header, namespace) @@ -211,83 +211,38 @@ func (s *Service) getByCommitment( } return nil, nil, err } + for _, row := range namespacedShares { - if len(row.Shares) == 0 { - break + appShares, err := toAppShares(row.Shares...) + if err != nil { + return nil, nil, err } - - rawShares = append(rawShares, row.Shares...) + rawShares = append(rawShares, appShares...) proofs = append(proofs, row.Proof) - // reconstruct the `blobShare` from the first rawShare in range - // in order to get blob's length(first share will contain this info) - if blobShare == nil { - for i, shr := range rawShares { - bShare, err := shares.NewShare(shr) - if err != nil { - return nil, nil, err - } - - // ensure that the first share is not a NamespacePaddingShare - // these shares are used to satisfy the non-interactive default rules - // and are not the part of the blob, so should be removed. - isPadding, err := bShare.IsPadding() - if err != nil { - return nil, nil, err - } - if isPadding { - continue - } - - blobShare = bShare - // save the length. - length, err := blobShare.SequenceLen() - if err != nil { - return nil, nil, err - } - amount = shares.SparseSharesNeeded(length) - rawShares = rawShares[i:] - break - } - } - - // move to the next row if the blob is incomplete. - if amount > len(rawShares) { - continue - } - - blob, same, err := constructAndVerifyBlob(rawShares[:amount], commitment) + var blobs []*Blob + blobs, rawShares, err = createBlobs(rawShares) if err != nil { return nil, nil, err } - if same { - return blob, &proofs, nil + for _, b := range blobs { + if b.Commitment.Equal(commitment) { + return b, &proofs, nil + } + if expanded { + // only the first blob in the range can be expanded + expanded = false + // leave proof only for the current row + proofs = proofs[len(proofs)-1:] + } } - // drop info of the checked blob - rawShares = rawShares[amount:] if len(rawShares) > 0 { - // save proof for the last row in case we have rawShares - proofs = proofs[len(proofs)-1:] - } else { - // otherwise clear proofs - proofs = nil + expanded = true + continue } - blobShare = nil - } - - if len(rawShares) == 0 { - return nil, nil, ErrBlobNotFound - } - - blob, same, err := constructAndVerifyBlob(rawShares, commitment) - if err != nil { - return nil, nil, err - } - if same { - return blob, &proofs, nil + proofs = nil } - return nil, nil, ErrBlobNotFound } @@ -304,3 +259,25 @@ func (s *Service) getBlobs( } return SharesToBlobs(namespacedShares.Flatten()) } + +// toAppShares converts node's raw shares to the app shares, skipping padding +func toAppShares(shrs ...share.Share) ([]shares.Share, error) { + appShrs := make([]shares.Share, 0) + for _, shr := range shrs { + bShare, err := shares.NewShare(shr) + if err != nil { + return nil, err + } + + ok, err := bShare.IsPadding() + if err != nil { + return nil, err + } + if ok { + continue + } + + appShrs = append(appShrs, *bShare) + } + return appShrs, nil +}