Skip to content

Commit

Permalink
feat(shwap): Shwap add readFrom Writeto methods to shwap ids (#3605)
Browse files Browse the repository at this point in the history
  • Loading branch information
walldiss authored Jul 30, 2024
1 parent c81e6d1 commit 062f499
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 6 deletions.
29 changes: 29 additions & 0 deletions share/shwap/eds_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"io"
)

// EdsIDSize defines the byte size of the EdsID.
Expand Down Expand Up @@ -45,13 +46,41 @@ func EdsIDFromBinary(data []byte) (EdsID, error) {
return eid, nil
}

// ReadFrom reads the binary form of EdsID from the provided reader.
func (eid *EdsID) ReadFrom(r io.Reader) (int64, error) {
data := make([]byte, EdsIDSize)
n, err := r.Read(data)
if err != nil {
return int64(n), err
}
if n != EdsIDSize {
return int64(n), fmt.Errorf("EdsID: expected %d bytes, got %d", EdsIDSize, n)
}
id, err := EdsIDFromBinary(data)
if err != nil {
return int64(n), fmt.Errorf("EdsIDFromBinary: %w", err)
}
*eid = id
return int64(n), nil
}

// 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
}

// WriteTo writes the binary form of EdsID to the provided writer.
func (eid EdsID) WriteTo(w io.Writer) (int64, error) {
data, err := eid.MarshalBinary()
if err != nil {
return 0, err
}
n, err := w.Write(data)
return int64(n), err
}

// 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) Validate() error {
Expand Down
18 changes: 18 additions & 0 deletions share/shwap/eds_id_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package shwap

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -21,3 +22,20 @@ func TestEdsID(t *testing.T) {
err = idOut.Validate()
require.NoError(t, err)
}

func TestEdsIDReaderWriter(t *testing.T) {
id, err := NewEdsID(2)
require.NoError(t, err)

buf := bytes.NewBuffer(nil)
n, err := id.WriteTo(buf)
require.NoError(t, err)
require.Equal(t, int64(EdsIDSize), n)

eidOut := EdsID{}
n, err = eidOut.ReadFrom(buf)
require.NoError(t, err)
require.Equal(t, int64(EdsIDSize), n)

require.EqualValues(t, id, eidOut)
}
36 changes: 30 additions & 6 deletions share/shwap/namespace_data.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,59 @@
package shwap

import (
"errors"
"fmt"
"io"

"github.com/celestiaorg/go-libp2p-messenger/serde"

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

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

// Flatten combines all shares from all rows within the namespace into a single slice.
func (ns NamespacedData) Flatten() []share.Share {
func (nd NamespacedData) Flatten() []share.Share {
var shares []share.Share
for _, row := range ns {
for _, row := range nd {
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.AxisRoots, namespace share.Namespace) error {
func (nd NamespacedData) Validate(root *share.AxisRoots, 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))
if len(rowIdxs) != len(nd) {
return fmt.Errorf("expected %d rows, found %d rows", len(rowIdxs), len(nd))
}

for i, row := range ns {
for i, row := range nd {
if err := row.Validate(root, namespace, rowIdxs[i]); err != nil {
return fmt.Errorf("validating row: %w", err)
}
}
return nil
}

// ReadFrom reads the binary form of NamespacedData from the provided reader.
func (nd *NamespacedData) ReadFrom(reader io.Reader) error {
var data []RowNamespaceData
for {
var pbRow pb.RowNamespaceData
_, err := serde.Read(reader, &pbRow)
if err != nil {
if errors.Is(err, io.EOF) {
// all rows have been read
*nd = data
return nil
}
return err
}
row := RowNamespaceDataFromProto(&pbRow)
data = append(data, row)
}
}
29 changes: 29 additions & 0 deletions share/shwap/namespace_data_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package shwap

import (
"fmt"
"io"

"github.com/celestiaorg/celestia-node/share"
)
Expand Down Expand Up @@ -58,6 +59,24 @@ func NamespaceDataIDFromBinary(data []byte) (NamespaceDataID, error) {
return ndid, nil
}

// ReadFrom reads the binary form of NamespaceDataID from the provided reader.
func (ndid *NamespaceDataID) ReadFrom(r io.Reader) (int64, error) {
data := make([]byte, NamespaceDataIDSize)
n, err := r.Read(data)
if err != nil {
return int64(n), err
}
if n != NamespaceDataIDSize {
return int64(n), fmt.Errorf("NamespaceDataID: expected %d bytes, got %d", NamespaceDataIDSize, n)
}
id, err := NamespaceDataIDFromBinary(data)
if err != nil {
return int64(n), fmt.Errorf("NamespaceDataIDFromBinary: %w", err)
}
*ndid = id
return int64(n), nil
}

// MarshalBinary encodes NamespaceDataID into binary form.
// NOTE: Proto is avoided because
// * Its size is not deterministic which is required for IPLD.
Expand All @@ -67,6 +86,16 @@ func (ndid NamespaceDataID) MarshalBinary() ([]byte, error) {
return ndid.appendTo(data), nil
}

// WriteTo writes the binary form of NamespaceDataID to the provided writer.
func (ndid NamespaceDataID) WriteTo(w io.Writer) (int64, error) {
data, err := ndid.MarshalBinary()
if err != nil {
return 0, err
}
n, err := w.Write(data)
return int64(n), err
}

// Validate checks if the NamespaceDataID is valid. It checks the validity of the EdsID and the
// DataNamespace.
func (ndid NamespaceDataID) Validate() error {
Expand Down
20 changes: 20 additions & 0 deletions share/shwap/namespace_data_id_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package shwap

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -25,3 +26,22 @@ func TestNamespaceDataID(t *testing.T) {
err = sidOut.Validate()
require.NoError(t, err)
}

func TestNamespaceDataIDReaderWriter(t *testing.T) {
ns := sharetest.RandV0Namespace()

id, err := NewNamespaceDataID(1, ns)
require.NoError(t, err)

buf := bytes.NewBuffer(nil)
n, err := id.WriteTo(buf)
require.NoError(t, err)
require.Equal(t, int64(NamespaceDataIDSize), n)

ndidOut := NamespaceDataID{}
n, err = ndidOut.ReadFrom(buf)
require.NoError(t, err)
require.Equal(t, int64(NamespaceDataIDSize), n)

require.EqualValues(t, id, ndidOut)
}
27 changes: 27 additions & 0 deletions share/shwap/row_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package shwap
import (
"encoding/binary"
"fmt"
"io"
)

// RowIDSize defines the size in bytes of RowID, consisting of the size of EdsID and 2 bytes for
Expand Down Expand Up @@ -55,12 +56,38 @@ func RowIDFromBinary(data []byte) (RowID, error) {
return rid, nil
}

func (rid *RowID) ReadFrom(r io.Reader) (int64, error) {
data := make([]byte, RowIDSize)
n, err := r.Read(data)
if err != nil {
return int64(n), err
}
if n != RowIDSize {
return int64(n), fmt.Errorf("RowID: expected %d bytes, got %d", RowIDSize, n)
}
id, err := RowIDFromBinary(data)
if err != nil {
return int64(n), fmt.Errorf("RowIDFromBinary: %w", err)
}
*rid = id
return int64(n), nil
}

// MarshalBinary encodes the RowID into a binary form for storage or network transmission.
func (rid RowID) MarshalBinary() ([]byte, error) {
data := make([]byte, 0, RowIDSize)
return rid.appendTo(data), nil
}

func (rid RowID) WriteTo(w io.Writer) (int64, error) {
data, err := rid.MarshalBinary()
if err != nil {
return 0, err
}
n, err := w.Write(data)
return int64(n), err
}

// Verify validates the RowID fields and verifies that RowIndex is within the bounds of
// the square size
func (rid RowID) Verify(edsSize int) error {
Expand Down
20 changes: 20 additions & 0 deletions share/shwap/row_id_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package shwap

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -23,3 +24,22 @@ func TestRowID(t *testing.T) {
err = idOut.Verify(edsSize)
require.NoError(t, err)
}

func TestRowIDReaderWriter(t *testing.T) {
edsSize := 4

id, err := NewRowID(2, 1, edsSize)
require.NoError(t, err)

buf := bytes.NewBuffer(nil)
n, err := id.WriteTo(buf)
require.NoError(t, err)
require.Equal(t, int64(RowIDSize), n)

ridOut := RowID{}
n, err = ridOut.ReadFrom(buf)
require.NoError(t, err)
require.Equal(t, int64(RowIDSize), n)

require.EqualValues(t, id, ridOut)
}
29 changes: 29 additions & 0 deletions share/shwap/row_namespace_data_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package shwap

import (
"fmt"
"io"

"github.com/celestiaorg/celestia-node/share"
)
Expand Down Expand Up @@ -65,6 +66,24 @@ func RowNamespaceDataIDFromBinary(data []byte) (RowNamespaceDataID, error) {
return rndid, nil
}

// ReadFrom reads the binary form of RowNamespaceDataID from the provided reader.
func (s *RowNamespaceDataID) ReadFrom(r io.Reader) (int64, error) {
data := make([]byte, RowNamespaceDataIDSize)
n, err := r.Read(data)
if err != nil {
return int64(n), err
}
if n != RowNamespaceDataIDSize {
return int64(n), fmt.Errorf("RowNamespaceDataID: expected %d bytes, got %d", RowNamespaceDataIDSize, n)
}
id, err := RowNamespaceDataIDFromBinary(data)
if err != nil {
return int64(n), fmt.Errorf("RowNamespaceDataIDFromBinary: %w", err)
}
*s = id
return int64(n), nil
}

// MarshalBinary encodes RowNamespaceDataID into binary form.
// NOTE: Proto is avoided because
// * Its size is not deterministic which is required for IPLD.
Expand All @@ -74,6 +93,16 @@ func (s RowNamespaceDataID) MarshalBinary() ([]byte, error) {
return s.appendTo(data), nil
}

// WriteTo writes the binary form of RowNamespaceDataID to the provided writer.
func (s RowNamespaceDataID) WriteTo(w io.Writer) (int64, error) {
data, err := s.MarshalBinary()
if err != nil {
return 0, err
}
n, err := w.Write(data)
return int64(n), err
}

// Verify validates the RowNamespaceDataID and verifies the embedded RowID.
func (s RowNamespaceDataID) Verify(edsSize int) error {
if err := s.RowID.Verify(edsSize); err != nil {
Expand Down
21 changes: 21 additions & 0 deletions share/shwap/row_namespace_data_id_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package shwap

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -26,3 +27,23 @@ func TestRowNamespaceDataID(t *testing.T) {
err = sidOut.Verify(edsSize)
require.NoError(t, err)
}

func TestRowNamespaceDataIDReaderWriter(t *testing.T) {
edsSize := 4
ns := sharetest.RandV0Namespace()

id, err := NewRowNamespaceDataID(1, 1, ns, edsSize)
require.NoError(t, err)

buf := bytes.NewBuffer(nil)
n, err := id.WriteTo(buf)
require.NoError(t, err)
require.Equal(t, int64(RowNamespaceDataIDSize), n)

rndidOut := RowNamespaceDataID{}
n, err = rndidOut.ReadFrom(buf)
require.NoError(t, err)
require.Equal(t, int64(RowNamespaceDataIDSize), n)

require.EqualValues(t, id, rndidOut)
}
Loading

0 comments on commit 062f499

Please sign in to comment.