Skip to content

Commit

Permalink
refactor(share/shwap): shwap types improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Wondertan committed May 28, 2024
1 parent 4ff30e8 commit 6e9f1da
Show file tree
Hide file tree
Showing 20 changed files with 458 additions and 428 deletions.
17 changes: 0 additions & 17 deletions share/availability.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,12 @@ import (
"context"
"errors"

"github.com/celestiaorg/celestia-app/pkg/da"
"github.com/celestiaorg/rsmt2d"

"github.com/celestiaorg/celestia-node/header"
)

// ErrNotAvailable is returned whenever DA sampling fails.
var ErrNotAvailable = errors.New("share: data not available")

// Root represents root commitment to multiple Shares.
// In practice, it is a commitment to all the Data in a square.
type Root = da.DataAvailabilityHeader

// NewRoot generates Root(DataAvailabilityHeader) using the
// provided extended data square.
func NewRoot(eds *rsmt2d.ExtendedDataSquare) (*Root, error) {
dah, err := da.NewDataAvailabilityHeader(eds)
if err != nil {
return nil, err
}
return &dah, nil
}

// Availability defines interface for validation of Shares' availability.
//
//go:generate mockgen -destination=availability/mocks/availability.go -package=mocks . Availability
Expand Down
31 changes: 31 additions & 0 deletions share/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package share

import (
"github.com/celestiaorg/celestia-app/pkg/da"
"github.com/celestiaorg/rsmt2d"
)

// Root represents root commitment to multiple Shares.
// In practice, it is a commitment to all the Data in a square.
type Root = da.DataAvailabilityHeader

// NewRoot generates Root(DataAvailabilityHeader) using the
// provided extended data square.
func NewRoot(eds *rsmt2d.ExtendedDataSquare) (*Root, error) {
dah, err := da.NewDataAvailabilityHeader(eds)
if err != nil {
return nil, err
}
return &dah, nil
}

// RowsWithNamespace inspects the Root for the Namespace and provides
// a slices of Row indexes containing the namespace.
func RowsWithNamespace(root *Root, namespace Namespace) (idxs []int) {
for i, row := range root.RowRoots {
if !namespace.IsOutsideRange(row, row) {
idxs = append(idxs, i)
}
}
return
}
13 changes: 0 additions & 13 deletions share/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,3 @@ func RootHashForCoordinates(r *Root, axisType rsmt2d.Axis, rowIdx, colIdx uint)
}
return r.ColumnRoots[colIdx]
}

// FilterRootByNamespace returns the row roots from the given share.Root that contain the namespace.
// It also returns the half open range of the roots that contain the namespace.
func FilterRootByNamespace(root *Root, namespace Namespace) (rowRoots [][]byte, from, to int) {
for i, rowRoot := range root.RowRoots {
if !namespace.IsOutsideRange(rowRoot, rowRoot) {
rowRoots = append(rowRoots, rowRoot)
to = i
}
}
to++
return rowRoots, to - len(rowRoots), to
}
92 changes: 0 additions & 92 deletions share/shwap/data_id.go

This file was deleted.

25 changes: 10 additions & 15 deletions share/shwap/eds_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,7 @@ func NewEdsID(height uint64, root *share.Root) (EdsID, error) {
eid := EdsID{
Height: height,
}
return eid, eid.Verify(root)
}

// MarshalBinary encodes an EdsID into its binary form, primarily for storage or network
// transmission.
func (eid EdsID) MarshalBinary() []byte {
data := make([]byte, 0, EdsIDSize)
return eid.appendTo(data)
return eid, eid.Validate(root)
}

// EdsIDFromBinary decodes a byte slice into an EdsID, validating the length of the data.
Expand All @@ -44,9 +37,16 @@ func EdsIDFromBinary(data []byte) (EdsID, error) {
return rid, nil
}

// Verify checks the integrity of an EdsID's fields against the provided Root.
// MarshalBinary encodes an EdsID into its binary form, primarily for storage or network
// transmission.
func (eid EdsID) MarshalBinary() ([]byte, error) {
data := make([]byte, 0, EdsIDSize)
return eid.appendTo(data), nil
}

// Validate checks the integrity of an EdsID's fields against the provided Root.
// It ensures that the EdsID is not constructed with a zero Height and that the root is not nil.
func (eid EdsID) Verify(root *share.Root) error {
func (eid EdsID) Validate(root *share.Root) error {
if root == nil {
return fmt.Errorf("provided Root is nil")
}
Expand All @@ -56,11 +56,6 @@ func (eid EdsID) Verify(root *share.Root) error {
return nil
}

// GetHeight returns the Height of the EdsID.
func (eid EdsID) GetHeight() uint64 {
return eid.Height
}

// appendTo helps in the binary encoding of EdsID by appending the binary form of Height to the
// given byte slice.
func (eid EdsID) appendTo(data []byte) []byte {
Expand Down
6 changes: 4 additions & 2 deletions share/shwap/eds_id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ func TestEdsID(t *testing.T) {
id, err := NewEdsID(2, root)
require.NoError(t, err)

data := id.MarshalBinary()
data, err := id.MarshalBinary()
require.NoError(t, err)

idOut, err := EdsIDFromBinary(data)
require.NoError(t, err)
assert.EqualValues(t, id, idOut)

err = idOut.Verify(root)
err = idOut.Validate(root)
require.NoError(t, err)
}
61 changes: 61 additions & 0 deletions share/shwap/namespace_data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package shwap

import (
"fmt"

"github.com/celestiaorg/rsmt2d"

"github.com/celestiaorg/celestia-node/share"
)

// NamespacedData stores collections of RowNamespaceData, each representing shares and their proofs
// within a namespace.
type NamespacedData []RowNamespaceData

// NamespacedDataFromEDS extracts shares for a specific namespace from an EDS, considering
// each row independently.
func NamespacedDataFromEDS(
square *rsmt2d.ExtendedDataSquare,
namespace share.Namespace,
) (NamespacedData, error) {
root, err := share.NewRoot(square)
if err != nil {
return nil, fmt.Errorf("error computing root: %w", err)
}

rowIdxs := share.RowsWithNamespace(root, namespace)
rows := make(NamespacedData, len(rowIdxs))
for i, idx := range rowIdxs {
shares := square.Row(uint(idx))
rows[i], err = RowNamespaceDataFromShares(shares, namespace, idx)
if err != nil {
return nil, fmt.Errorf("failed to process row %d: %w", idx, err)
}
}

return rows, nil
}

// Flatten combines all shares from all rows within the namespace into a single slice.
func (ns NamespacedData) Flatten() []share.Share {
var shares []share.Share
for _, row := range ns {
shares = append(shares, row.Shares...)
}
return shares
}

// Validate checks the integrity of the NamespacedData against a provided root and namespace.
func (ns NamespacedData) Validate(root *share.Root, namespace share.Namespace) error {
rowIdxs := share.RowsWithNamespace(root, namespace)
if len(rowIdxs) != len(ns) {
return fmt.Errorf("expected %d rows, found %d rows", len(rowIdxs), len(ns))
}

for i, row := range ns {
if err := row.Validate(root, namespace, rowIdxs[i]); err != nil {
return fmt.Errorf("validating row: %w", err)
}
}
return nil
}
25 changes: 12 additions & 13 deletions share/shwap/namespaced_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestNamespacedRowFromShares(t *testing.T) {
require.NoError(t, err)
extended := slices.Concat(shares, parity)

nr, err := NamespacedRowFromShares(extended, minNamespace, 0)
nr, err := RowNamespaceDataFromShares(extended, minNamespace, 0)
require.NoError(t, err)
require.Equal(t, namespacedAmount, len(nr.Shares))
}
Expand All @@ -46,7 +46,7 @@ func TestNamespacedRowFromSharesNonIncluded(t *testing.T) {
require.NoError(t, err)
extended := slices.Concat(shares, parity)

nr, err := NamespacedRowFromShares(extended, absentNs, 0)
nr, err := RowNamespaceDataFromShares(extended, absentNs, 0)
require.NoError(t, err)
require.Len(t, nr.Shares, 0)
require.True(t, nr.Proof.IsOfAbsence())
Expand All @@ -58,12 +58,12 @@ func TestNamespacedSharesFromEDS(t *testing.T) {
namespace := sharetest.RandV0Namespace()
for amount := 1; amount < sharesAmount; amount++ {
eds, root := edstest.RandEDSWithNamespace(t, namespace, amount, odsSize)
nd, err := NewNamespacedSharesFromEDS(eds, namespace)
nd, err := NamespacedDataFromEDS(eds, namespace)
require.NoError(t, err)
require.True(t, len(nd) > 0)
require.Len(t, nd.Flatten(), amount)

err = nd.Verify(root, namespace)
err = nd.Validate(root, namespace)
require.NoError(t, err)
}
}
Expand All @@ -74,17 +74,16 @@ func TestValidateNamespacedRow(t *testing.T) {
namespace := sharetest.RandV0Namespace()
for amount := 1; amount < sharesAmount; amount++ {
eds, root := edstest.RandEDSWithNamespace(t, namespace, amount, odsSize)
nd, err := NewNamespacedSharesFromEDS(eds, namespace)
nd, err := NamespacedDataFromEDS(eds, namespace)
require.NoError(t, err)
require.True(t, len(nd) > 0)

_, from, to := share.FilterRootByNamespace(root, namespace)
require.Len(t, nd, to-from)
idx := from
for _, row := range nd {
err = row.Validate(root, namespace, idx)
rowIdxs := share.RowsWithNamespace(root, namespace)
require.Len(t, nd, len(rowIdxs))

for i, rowIdx := range rowIdxs {
err = nd[i].Validate(root, namespace, rowIdx)
require.NoError(t, err)
idx++
}
}
}
Expand All @@ -93,12 +92,12 @@ func TestNamespacedRowProtoEncoding(t *testing.T) {
const odsSize = 8
namespace := sharetest.RandV0Namespace()
eds, _ := edstest.RandEDSWithNamespace(t, namespace, odsSize, odsSize)
nd, err := NewNamespacedSharesFromEDS(eds, namespace)
nd, err := NamespacedDataFromEDS(eds, namespace)
require.NoError(t, err)
require.True(t, len(nd) > 0)

expected := nd[0]
pb := expected.ToProto()
ndOut := NamespacedRowFromProto(pb)
ndOut := RowNamespaceDataFromProto(pb)
require.Equal(t, expected, ndOut)
}
Loading

0 comments on commit 6e9f1da

Please sign in to comment.