Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
fix(da): update go-da interface v0.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tuxcanfly committed Feb 12, 2024
1 parent 5892064 commit 509a5c1
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 148 deletions.
103 changes: 54 additions & 49 deletions celestia/celestia.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ import (
"context"
"encoding/binary"
"log"
"math"
"strings"

"github.com/celestiaorg/celestia-app/pkg/appconsts"
"github.com/celestiaorg/celestia-app/x/blob/types"
rpc "github.com/celestiaorg/celestia-node/api/rpc/client"
"github.com/celestiaorg/celestia-node/blob"
"github.com/celestiaorg/celestia-node/share"
"github.com/celestiaorg/nmt"
sdktypes "github.com/cosmos/cosmos-sdk/types"
auth "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/rollkit/go-da"
)
Expand Down Expand Up @@ -54,11 +50,14 @@ func (c *CelestiaDA) MaxBlobSize(ctx context.Context) (uint64, error) {
}

// Get returns Blob for each given ID, or an error.
func (c *CelestiaDA) Get(ctx context.Context, ids []da.ID) ([]da.Blob, error) {
func (c *CelestiaDA) Get(ctx context.Context, ids []da.ID, ns da.Namespace) ([]da.Blob, error) {
if ns == nil {
ns = c.namespace
}

Check warning on line 56 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L55-L56

Added lines #L55 - L56 were not covered by tests
var blobs []da.Blob
for _, id := range ids {
height, commitment := splitID(id)
blob, err := c.client.Blob.Get(ctx, height, c.namespace, commitment)
height, commitment := SplitID(id)
blob, err := c.client.Blob.Get(ctx, height, ns, commitment)
if err != nil {
return nil, err
}
Expand All @@ -68,74 +67,76 @@ func (c *CelestiaDA) Get(ctx context.Context, ids []da.ID) ([]da.Blob, error) {
}

// GetIDs returns IDs of all Blobs located in DA at given height.
func (c *CelestiaDA) GetIDs(ctx context.Context, height uint64) ([]da.ID, error) {
func (c *CelestiaDA) GetIDs(ctx context.Context, height uint64, ns da.Namespace) ([]da.ID, error) {
var ids []da.ID
blobs, err := c.client.Blob.GetAll(ctx, height, []share.Namespace{c.namespace})
blobs, err := c.client.Blob.GetAll(ctx, height, []share.Namespace{ns})
if err != nil {
if strings.Contains(err.Error(), blob.ErrBlobNotFound.Error()) {
return nil, nil
}
return nil, err
}
for _, b := range blobs {
ids = append(ids, makeID(height, b.Commitment))
ids = append(ids, MakeID(height, b.Commitment))
}
return ids, nil
}

// Commit creates a Commitment for each given Blob.
func (c *CelestiaDA) Commit(ctx context.Context, daBlobs []da.Blob) ([]da.Commitment, error) {
_, commitments, err := c.blobsAndCommitments(daBlobs)
func (c *CelestiaDA) Commit(ctx context.Context, daBlobs []da.Blob, ns da.Namespace) ([]da.Commitment, error) {
if ns == nil {
ns = c.namespace
}

Check warning on line 89 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L88-L89

Added lines #L88 - L89 were not covered by tests
_, commitments, err := c.blobsAndCommitments(daBlobs, ns)
return commitments, err
}

// Submit submits the Blobs to Data Availability layer.
func (c *CelestiaDA) Submit(ctx context.Context, daBlobs []da.Blob, gasPrice float64) ([]da.ID, []da.Proof, error) {
blobs, commitments, err := c.blobsAndCommitments(daBlobs)
func (c *CelestiaDA) Submit(ctx context.Context, daBlobs []da.Blob, gasPrice float64, ns da.Namespace) ([]da.ID, error) {
if ns == nil {
ns = c.namespace
}

Check warning on line 98 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L97-L98

Added lines #L97 - L98 were not covered by tests
blobs, _, err := c.blobsAndCommitments(daBlobs, ns)
if err != nil {
return nil, nil, err
return nil, err

Check warning on line 101 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L101

Added line #L101 was not covered by tests
}
options := blob.DefaultSubmitOptions()
// if gas price was configured globally use that as the default
if c.gasPrice >= 0 && gasPrice < 0 {
gasPrice = c.gasPrice
height, err := c.client.Blob.Submit(ctx, blobs, blob.GasPrice(gasPrice))
if err != nil {
return nil, err

Check warning on line 105 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L105

Added line #L105 was not covered by tests
}
if gasPrice >= 0 {
blobSizes := make([]uint32, len(blobs))
for i, blob := range blobs {
blobSizes[i] = uint32(len(blob.Data))
}
options.GasLimit = types.EstimateGas(blobSizes, appconsts.DefaultGasPerBlobByte, auth.DefaultTxSizeCostPerByte)
options.Fee = sdktypes.NewInt(int64(math.Ceil(gasPrice * float64(options.GasLimit)))).Int64()
log.Println("successfully submitted blobs", "height", height, "gasPrice", gasPrice)
ids := make([]da.ID, len(blobs))
for i, blob := range blobs {
ids[i] = MakeID(height, blob.Commitment)
}
height, err := c.client.Blob.Submit(ctx, blobs, options)
if err != nil {
return nil, nil, err
}
log.Println("successfully submitted blobs", "height", height, "gas", options.GasLimit, "fee", options.Fee)
ids := make([]da.ID, len(daBlobs))
proofs := make([]da.Proof, len(daBlobs))
for i, commitment := range commitments {
ids[i] = makeID(height, commitment)
proof, err := c.client.Blob.GetProof(ctx, height, c.namespace, commitment)
return ids, nil
}

func (c *CelestiaDA) GetProofs(ctx context.Context, daIDs []da.ID, ns da.Namespace) ([]da.Proof, error) {

Check warning on line 115 in celestia/celestia.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint

exported: exported method CelestiaDA.GetProofs should have comment or be unexported (revive)
if ns == nil {
ns = c.namespace
}
proofs := make([]da.Proof, len(daIDs))
for i, id := range daIDs {
height, commitment := SplitID(id)
proof, err := c.client.Blob.GetProof(ctx, height, ns, commitment)

Check warning on line 122 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L115-L122

Added lines #L115 - L122 were not covered by tests
if err != nil {
return nil, nil, err
return nil, err

Check warning on line 124 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L124

Added line #L124 was not covered by tests
}
// TODO(tzdybal): does always len(*proof) == 1?
proofs[i], err = (*proof)[0].MarshalJSON()
proofs[i], err = proof.MarshalJSON()

Check warning on line 126 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L126

Added line #L126 was not covered by tests
if err != nil {
return nil, nil, err
return nil, err

Check warning on line 128 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L128

Added line #L128 was not covered by tests
}
}
return ids, proofs, nil
return proofs, nil

Check warning on line 131 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L131

Added line #L131 was not covered by tests
}

// blobsAndCommitments converts []da.Blob to []*blob.Blob and generates corresponding []da.Commitment
func (c *CelestiaDA) blobsAndCommitments(daBlobs []da.Blob) ([]*blob.Blob, []da.Commitment, error) {
func (c *CelestiaDA) blobsAndCommitments(daBlobs []da.Blob, ns da.Namespace) ([]*blob.Blob, []da.Commitment, error) {
var blobs []*blob.Blob
var commitments []da.Commitment
for _, daBlob := range daBlobs {
b, err := blob.NewBlobV0(c.namespace, daBlob)
b, err := blob.NewBlobV0(ns, daBlob)
if err != nil {
return nil, nil, err
}
Expand All @@ -151,7 +152,10 @@ func (c *CelestiaDA) blobsAndCommitments(daBlobs []da.Blob) ([]*blob.Blob, []da.
}

// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs.
func (c *CelestiaDA) Validate(ctx context.Context, ids []da.ID, daProofs []da.Proof) ([]bool, error) {
func (c *CelestiaDA) Validate(ctx context.Context, ids []da.ID, daProofs []da.Proof, ns da.Namespace) ([]bool, error) {
if ns == nil {
ns = c.namespace
}

Check warning on line 158 in celestia/celestia.go

View check run for this annotation

Codecov / codecov/patch

celestia/celestia.go#L157-L158

Added lines #L157 - L158 were not covered by tests
var included []bool
var proofs []*blob.Proof
for _, daProof := range daProofs {
Expand All @@ -163,11 +167,11 @@ func (c *CelestiaDA) Validate(ctx context.Context, ids []da.ID, daProofs []da.Pr
proofs = append(proofs, proof)
}
for i, id := range ids {
height, commitment := splitID(id)
height, commitment := SplitID(id)
// TODO(tzdybal): for some reason, if proof doesn't match commitment, API returns (false, "blob: invalid proof")
// but analysis of the code in celestia-node implies this should never happen - maybe it's caused by openrpc?
// there is no way of gently handling errors here, but returned value is fine for us
isIncluded, _ := c.client.Blob.Included(ctx, height, c.namespace, proofs[i], commitment)
isIncluded, _ := c.client.Blob.Included(ctx, height, ns, proofs[i], commitment)
included = append(included, isIncluded)
}
return included, nil
Expand All @@ -178,18 +182,19 @@ func (c *CelestiaDA) Validate(ctx context.Context, ids []da.ID, daProofs []da.Pr
// This is 8 as uint64 consist of 8 bytes.
const heightLen = 8

func makeID(height uint64, commitment da.Commitment) da.ID {
func MakeID(height uint64, commitment da.Commitment) da.ID {

Check warning on line 185 in celestia/celestia.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint

exported: exported function MakeID should have comment or be unexported (revive)
id := make([]byte, heightLen+len(commitment))
binary.LittleEndian.PutUint64(id, height)
copy(id[heightLen:], commitment)
return id
}

func splitID(id da.ID) (uint64, da.Commitment) {
func SplitID(id da.ID) (uint64, da.Commitment) {

Check warning on line 192 in celestia/celestia.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint

exported: exported function SplitID should have comment or be unexported (revive)
if len(id) <= heightLen {
return 0, nil
}
return binary.LittleEndian.Uint64(id[:heightLen]), id[heightLen:]
commitment := id[heightLen:]
return binary.LittleEndian.Uint64(id[:heightLen]), commitment
}

var _ da.DA = &CelestiaDA{}
49 changes: 26 additions & 23 deletions celestia/celestia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ func setup(t *testing.T) *mockDA {

t.Logf("mock json-rpc server listening on: %s", mockService.server.URL)

ctx := context.TODO()
client, err := rpc.NewClient(ctx, mockService.server.URL, "test")
nsHex, err := hex.DecodeString("0000c9761e8b221ae42f")
assert.NoError(t, err)
ns, err := hex.DecodeString("0000c9761e8b221ae42f")
ns, err := share.NewBlobNamespaceV0(nsHex)
assert.NoError(t, err)
namespace, err := share.NewBlobNamespaceV0(ns)

ctx := context.TODO()
client, err := rpc.NewClient(ctx, mockService.server.URL, "test")
assert.NoError(t, err)
da := NewCelestiaDA(client, namespace, -1, ctx)
da := NewCelestiaDA(client, ns, -1, ctx)
assert.Equal(t, da.client, client)

return &mockDA{mockService, *da}
Expand All @@ -54,89 +55,91 @@ func TestCelestiaDA(t *testing.T) {
m := setup(t)
defer teardown(m)

nsHex, err := hex.DecodeString("0000c9761e8b221ae42f")
assert.NoError(t, err)
ns, err := share.NewBlobNamespaceV0(nsHex)
assert.NoError(t, err)

assert.NoError(t, err)
t.Run("MaxBlobSize", func(t *testing.T) {
maxBlobSize, err := m.MaxBlobSize(ctx)
assert.NoError(t, err)
assert.Equal(t, uint64(DefaultMaxBytes), maxBlobSize)
})

t.Run("Get_empty", func(t *testing.T) {
blobs, err := m.Get(ctx, nil)
blobs, err := m.Get(ctx, nil, ns)
assert.NoError(t, err)
assert.Equal(t, 0, len(blobs))
})

t.Run("GetIDs_empty", func(t *testing.T) {
blobs, err := m.GetIDs(ctx, 0)
blobs, err := m.GetIDs(ctx, 0, ns)
assert.NoError(t, err)
assert.Equal(t, 0, len(blobs))
})

t.Run("Commit_empty", func(t *testing.T) {
commitments, err := m.Commit(ctx, nil)
commitments, err := m.Commit(ctx, nil, ns)
assert.NoError(t, err)
assert.Equal(t, 0, len(commitments))
})

t.Run("Submit_empty", func(t *testing.T) {
blobs, proofs, err := m.Submit(ctx, nil, -1)
blobs, err := m.Submit(ctx, nil, -1, ns)
assert.NoError(t, err)
assert.Equal(t, 0, len(blobs))
assert.Equal(t, 0, len(proofs))
})

t.Run("Validate_empty", func(t *testing.T) {
valids, err := m.Validate(ctx, nil, nil)
valids, err := m.Validate(ctx, nil, nil, ns)
assert.NoError(t, err)
assert.Equal(t, 0, len(valids))
})

t.Run("Get_existing", func(t *testing.T) {
commitment, err := hex.DecodeString("1b454951cd722b2cf7be5b04554b76ccf48f65a7ad6af45055006994ce70fd9d")
assert.NoError(t, err)
blobs, err := m.Get(ctx, []ID{makeID(42, commitment)})
blobs, err := m.Get(ctx, []ID{MakeID(42, commitment)}, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(blobs))
blob1 := blobs[0]
assert.Equal(t, "This is an example of some blob data", string(blob1))
})

t.Run("GetIDs_existing", func(t *testing.T) {
ids, err := m.GetIDs(ctx, 42)
ids, err := m.GetIDs(ctx, 42, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(ids))
id1 := ids[0]
commitment, err := hex.DecodeString("1b454951cd722b2cf7be5b04554b76ccf48f65a7ad6af45055006994ce70fd9d")
assert.NoError(t, err)
assert.Equal(t, makeID(42, commitment), id1)
assert.Equal(t, MakeID(42, commitment), id1)
})

t.Run("Commit_existing", func(t *testing.T) {
commitments, err := m.Commit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}})
commitments, err := m.Commit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(commitments))
})

t.Run("Submit_existing", func(t *testing.T) {
blobs, proofs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, -1)
blobs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, -1, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(blobs))
assert.Equal(t, 1, len(proofs))
})

t.Run("Submit_existing_with_gasprice_global", func(t *testing.T) {
m.CelestiaDA.gasPrice = 0.01
blobs, proofs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, -1)
blobs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, -1, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(blobs))
assert.Equal(t, 1, len(proofs))
})

t.Run("Submit_existing_with_gasprice_override", func(t *testing.T) {
blobs, proofs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, 0.5)
blobs, err := m.Submit(ctx, []Blob{[]byte{0x00, 0x01, 0x02}}, 0.5, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(blobs))
assert.Equal(t, 1, len(proofs))
})

t.Run("Validate_existing", func(t *testing.T) {
Expand All @@ -145,9 +148,9 @@ func TestCelestiaDA(t *testing.T) {
proof := nmt.NewInclusionProof(0, 4, [][]byte{[]byte("test")}, true)
proofJSON, err := proof.MarshalJSON()
assert.NoError(t, err)
ids := []ID{makeID(42, commitment)}
ids := []ID{MakeID(42, commitment)}
proofs := []Proof{proofJSON}
valids, err := m.Validate(ctx, ids, proofs)
valids, err := m.Validate(ctx, ids, proofs, ns)
assert.NoError(t, err)
assert.Equal(t, 1, len(valids))
})
Expand Down
2 changes: 1 addition & 1 deletion celestia/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type MockBlobAPI struct {
}

// Submit mocks the blob.Submit method
func (m *MockBlobAPI) Submit(ctx context.Context, blobs []*blob.Blob, options *blob.SubmitOptions) (uint64, error) {
func (m *MockBlobAPI) Submit(ctx context.Context, blobs []*blob.Blob, gasPrice float64) (uint64, error) {
m.height += 1
return m.height, nil
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/celestia-da/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func WithDataAvailabilityService(flags []*pflag.FlagSet) func(*cobra.Command) {
grpcFlags := &pflag.FlagSet{}
grpcFlags.String(grpcAddrFlag, "http://127.0.0.1:26658", "celestia-node RPC endpoint address")
grpcFlags.String(grpcTokenFlag, "", "celestia-node RPC auth token")
grpcFlags.String(grpcNamespaceFlag, "", "celestia namespace to use (hex encoded)")
grpcFlags.String(grpcNamespaceFlag, "", "celestia namespace to use (hex encoded) [Deprecated]")
grpcFlags.String(grpcListenFlag, "127.0.0.1:0", "gRPC service listen address")
grpcFlags.String(grpcNetworkFlag, "tcp", "gRPC service listen network type must be \"tcp\", \"tcp4\", \"tcp6\", \"unix\" or \"unixpacket\"")
grpcFlags.Float64(grpcGasPriceFlag, -1, "gas price for estimating fee (utia/gas) default: -1 for default fees")
Expand Down
Loading

0 comments on commit 509a5c1

Please sign in to comment.