Skip to content

Commit

Permalink
Reorganize EigenDA client codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
teddyknox committed May 28, 2024
1 parent 985d6ae commit 5c2ee40
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 104 deletions.
29 changes: 29 additions & 0 deletions api/clients/codecs/blob_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package codecs

import (
"fmt"
)

type BlobEncodingVersion byte

const (
// This minimal blob encoding includes a version byte, a length varuint, and 31 byte field element mapping. It does not include IFFT padding + IFFT.
DefaultBlobEncoding BlobEncodingVersion = 0x0
IFFTBlobEncoding BlobEncodingVersion = 0x01
)

type BlobCodec interface {
DecodeBlob(encodedData []byte) ([]byte, error)
EncodeBlob(rawData []byte) ([]byte, error)
}

func BlobEncodingVersionToCodec(version BlobEncodingVersion) (BlobCodec, error) {
switch version {
case DefaultBlobEncoding:
return DefaultBlobEncodingCodec{}, nil
case IFFTBlobEncoding:
return IFFTBlobEncodingCodec{}, nil
default:
return nil, fmt.Errorf("unsupported blob encoding version: %x", version)
}
}
65 changes: 65 additions & 0 deletions api/clients/codecs/default_blob_encoding_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package codecs

import (
"bytes"
"encoding/binary"
"fmt"

"github.com/Layr-Labs/eigenda/encoding/utils/codec"
)

type DefaultBlobEncodingCodec struct{}

var _ BlobCodec = DefaultBlobEncodingCodec{}

func (v DefaultBlobEncodingCodec) EncodeBlob(rawData []byte) ([]byte, error) {
// encode current blob encoding version byte
encodedData := make([]byte, 0, 1+8+len(rawData))

// append version byte
encodedData = append(encodedData, byte(DefaultBlobEncoding))

// encode data length
encodedData = append(encodedData, ConvertIntToVarUInt(len(rawData))...)

// append raw data
encodedData = append(encodedData, rawData...)

// encode modulo bn254
encodedData = codec.ConvertByPaddingEmptyByte(encodedData)

return encodedData, nil
}

func (v DefaultBlobEncodingCodec) DecodeBlob(encodedData []byte) ([]byte, error) {
// decode modulo bn254
decodedData := codec.RemoveEmptyByteFromPaddedBytes(encodedData)

// Return exact data with buffer removed
reader := bytes.NewReader(decodedData)

versionByte, err := reader.ReadByte()
if err != nil {
return nil, fmt.Errorf("failed to read version byte")
}
if DefaultBlobEncoding != BlobEncodingVersion(versionByte) {
return nil, fmt.Errorf("unsupported blob encoding version: %x", versionByte)
}

// read length uvarint
length, err := binary.ReadUvarint(reader)
if err != nil {
return nil, fmt.Errorf("failed to decode length uvarint prefix")
}

rawData := make([]byte, length)
n, err := reader.Read(rawData)
if err != nil {
return nil, fmt.Errorf("failed to copy unpadded data into final buffer, length: %d, bytes read: %d", length, n)
}
if uint64(n) != length {
return nil, fmt.Errorf("data length does not match length prefix")
}

return rawData, nil
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package clients
package codecs_test

import (
"bytes"
"crypto/rand"
"math/big"
"testing"

"github.com/Layr-Labs/eigenda/api/clients/codecs"
)

// Helper function to generate a random byte slice of a given length
Expand All @@ -20,7 +22,7 @@ func randomByteSlice(length int64) []byte {
// TestDefaultBlobEncodingCodec tests the encoding and decoding of random byte streams
func TestDefaultBlobEncodingCodec(t *testing.T) {
// Create an instance of the DefaultBlobEncodingCodec
codec := DefaultBlobEncodingCodec{}
codec := codecs.DefaultBlobEncodingCodec{}

// Number of test iterations
const iterations = 100
Expand Down Expand Up @@ -53,7 +55,7 @@ func TestDefaultBlobEncodingCodec(t *testing.T) {
}

func TestIFFTBlobEncodingCodec(t *testing.T) {
codec := IFFTBlobEncodingCodec{}
codec := codecs.IFFTBlobEncodingCodec{}

// Number of test iterations
const iterations = 100
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package clients
package codecs

import (
"bytes"
Expand All @@ -13,86 +13,9 @@ import (
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
)

type BlobEncodingVersion byte

const (
// This minimal blob encoding includes a version byte, a length varuint, and 31 byte field element mapping. It does not include IFFT padding + IFFT.
DefaultBlobEncoding BlobEncodingVersion = 0x0
IFFTBlobEncoding BlobEncodingVersion = 0x01
)

type BlobCodec interface {
DecodeBlob(encodedData []byte) ([]byte, error)
EncodeBlob(rawData []byte) ([]byte, error)
}

func BlobEncodingVersionToCodec(version BlobEncodingVersion) (BlobCodec, error) {
switch version {
case DefaultBlobEncoding:
return DefaultBlobEncodingCodec{}, nil
case IFFTBlobEncoding:
return IFFTBlobEncodingCodec{}, nil
default:
return nil, fmt.Errorf("unsupported blob encoding version: %x", version)
}
}

type DefaultBlobEncodingCodec struct{}
type IFFTBlobEncodingCodec struct{}

var _ BlobCodec = DefaultBlobEncodingCodec{}

func (v DefaultBlobEncodingCodec) EncodeBlob(rawData []byte) ([]byte, error) {
// encode current blob encoding version byte
encodedData := make([]byte, 0, 1+8+len(rawData))

// append version byte
encodedData = append(encodedData, byte(DefaultBlobEncoding))

// encode data length
encodedData = append(encodedData, ConvertIntToVarUInt(len(rawData))...)

// append raw data
encodedData = append(encodedData, rawData...)

// encode modulo bn254
encodedData = codec.ConvertByPaddingEmptyByte(encodedData)

return encodedData, nil
}

func (v DefaultBlobEncodingCodec) DecodeBlob(encodedData []byte) ([]byte, error) {
// decode modulo bn254
decodedData := codec.RemoveEmptyByteFromPaddedBytes(encodedData)

// Return exact data with buffer removed
reader := bytes.NewReader(decodedData)

versionByte, err := reader.ReadByte()
if err != nil {
return nil, fmt.Errorf("failed to read version byte")
}
if DefaultBlobEncoding != BlobEncodingVersion(versionByte) {
return nil, fmt.Errorf("unsupported blob encoding version: %x", versionByte)
}

// read length uvarint
length, err := binary.ReadUvarint(reader)
if err != nil {
return nil, fmt.Errorf("failed to decode length uvarint prefix")
}

rawData := make([]byte, length)
n, err := reader.Read(rawData)
if err != nil {
return nil, fmt.Errorf("failed to copy unpadded data into final buffer, length: %d, bytes read: %d", length, n)
}
if uint64(n) != length {
return nil, fmt.Errorf("data length does not match length prefix")
}

return rawData, nil
}
var _ BlobCodec = IFFTBlobEncodingCodec{}

func (v IFFTBlobEncodingCodec) EncodeBlob(rawData []byte) ([]byte, error) {
// encode current blob encoding version byte
Expand Down
2 changes: 1 addition & 1 deletion api/clients/utils.go → api/clients/codecs/utils.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package clients
package codecs

import "encoding/binary"

Expand Down
4 changes: 3 additions & 1 deletion api/clients/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package clients
import (
"fmt"
"time"

"github.com/Layr-Labs/eigenda/api/clients/codecs"
)

type EigenDAClientConfig struct {
Expand All @@ -28,7 +30,7 @@ type EigenDAClientConfig struct {
DisableTLS bool

// The blob encoding version to use when writing blobs from the high level interface.
PutBlobEncodingVersion BlobEncodingVersion
PutBlobEncodingVersion codecs.BlobEncodingVersion
}

func (c *EigenDAClientConfig) CheckAndSetDefaults() error {
Expand Down
9 changes: 5 additions & 4 deletions api/clients/eigenda_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net"
"time"

"github.com/Layr-Labs/eigenda/api/clients/codecs"
grpcdisperser "github.com/Layr-Labs/eigenda/api/grpc/disperser"
"github.com/Layr-Labs/eigenda/core/auth"
"github.com/Layr-Labs/eigenda/disperser"
Expand All @@ -23,7 +24,7 @@ type EigenDAClient struct {
Config EigenDAClientConfig
Log log.Logger
Client DisperserClient
PutCodec BlobCodec
PutCodec codecs.BlobCodec
}

var _ IEigenDAClient = EigenDAClient{}
Expand All @@ -43,7 +44,7 @@ func NewEigenDAClient(log log.Logger, config EigenDAClientConfig) (*EigenDAClien
llConfig := NewConfig(host, port, config.ResponseTimeout, !config.DisableTLS)
llClient := NewDisperserClient(llConfig, signer)

codec, err := BlobEncodingVersionToCodec(config.PutBlobEncodingVersion)
codec, err := codecs.BlobEncodingVersionToCodec(config.PutBlobEncodingVersion)
if err != nil {
return nil, fmt.Errorf("error initializing EigenDA client: %w", err)
}
Expand All @@ -66,8 +67,8 @@ func (m EigenDAClient) GetBlob(ctx context.Context, BatchHeaderHash []byte, Blob
return nil, fmt.Errorf("blob has length zero")
}

version := BlobEncodingVersion(data[0])
codec, err := BlobEncodingVersionToCodec(version)
version := codecs.BlobEncodingVersion(data[0])
codec, err := codecs.BlobEncodingVersionToCodec(version)
if err != nil {
return nil, fmt.Errorf("error getting blob: %w", err)
}
Expand Down
33 changes: 17 additions & 16 deletions api/clients/eigenda_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/Layr-Labs/eigenda/api/clients"
"github.com/Layr-Labs/eigenda/api/clients/codecs"
clientsmock "github.com/Layr-Labs/eigenda/api/clients/mock"
"github.com/Layr-Labs/eigenda/api/grpc/common"
grpcdisperser "github.com/Layr-Labs/eigenda/api/grpc/disperser"
Expand Down Expand Up @@ -65,10 +66,10 @@ func TestPutRetrieveBlobSuccess(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
expectedBlob := []byte("dc49e7df326cfb2e7da5cf68f263e1898443ec2e862350606e7dfbda55ad10b5d61ed1d54baf6ae7a86279c1b4fa9c49a7de721dacb211264c1f5df31bade51c")
blobInfo, err := eigendaClient.PutBlob(context.Background(), expectedBlob)
Expand Down Expand Up @@ -96,10 +97,10 @@ func TestPutBlobFailDispersal(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))
require.Error(t, err)
Expand Down Expand Up @@ -128,10 +129,10 @@ func TestPutBlobFailureInsufficentSignatures(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))
require.Error(t, err)
Expand Down Expand Up @@ -160,10 +161,10 @@ func TestPutBlobFailureGeneral(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))
require.Error(t, err)
Expand Down Expand Up @@ -192,10 +193,10 @@ func TestPutBlobFailureUnknown(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))
require.Error(t, err)
Expand Down Expand Up @@ -226,10 +227,10 @@ func TestPutBlobFinalizationTimeout(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))
require.Error(t, err)
Expand Down Expand Up @@ -285,10 +286,10 @@ func TestPutBlobIndividualRequestTimeout(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))

Expand Down Expand Up @@ -347,10 +348,10 @@ func TestPutBlobTotalTimeout(t *testing.T) {
CustomQuorumIDs: []uint{},
SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d",
DisableTLS: false,
PutBlobEncodingVersion: clients.DefaultBlobEncoding,
PutBlobEncodingVersion: codecs.DefaultBlobEncoding,
},
Client: disperserClient,
PutCodec: clients.DefaultBlobEncodingCodec{},
PutCodec: codecs.DefaultBlobEncodingCodec{},
}
blobInfo, err := eigendaClient.PutBlob(context.Background(), []byte("hello"))

Expand Down

0 comments on commit 5c2ee40

Please sign in to comment.