Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: GetProofs introduction #38

Merged
merged 3 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ go-da defines a generic Data Availability interface for modular blockchains.
| `MaxBlobSize` | | `uint64` |
| `Get` | `ids []ID, namespace Namespace` | `[]Blobs` |
| `GetIDs` | `height uint64, namespace Namespace` | `[]ID` |
| `GetProofs` | `ids []id, namespace Namespace` | `[]Proof` |
| `Commit` | `blobs []Blob, namespace Namespace` | `[]Commitment` |
| `Validate` | `ids []Blob, proofs []Proof, namespace Namespace` | `[]bool` |
| `Submit` | `blobs []Blob, gasPrice float64, namespace Namespace` | `[]ID, []Proof` |
| `Submit` | `blobs []Blob, gasPrice float64, namespace Namespace` | `[]ID` |

NOTE: The `Namespace` parameter in the interface methods is optional and used
only on DA layers that support the functionality, for example Celestia
Expand Down
10 changes: 6 additions & 4 deletions da.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ type DA interface {
// GetIDs returns IDs of all Blobs located in DA at given height.
GetIDs(ctx context.Context, height uint64, namespace Namespace) ([]ID, error)

// GetProofs returns inclusion Proofs for all Blobs located in DA at given height.
GetProofs(ctx context.Context, ids []ID, namespace Namespace) ([]Proof, error)

// Commit creates a Commitment for each given Blob.
Commit(ctx context.Context, blobs []Blob, namespace Namespace) ([]Commitment, error)

// Submit submits the Blobs to Data Availability layer.
//
// This method is synchronous. Upon successful submission to Data Availability layer, it returns ID identifying blob
// in DA and Proof of inclusion.
// If options is nil, default options are used.
Submit(ctx context.Context, blobs []Blob, gasPrice float64, namespace Namespace) ([]ID, []Proof, error)
// This method is synchronous. Upon successful submission to Data Availability layer, it returns the IDs identifying blobs
// in DA.
Submit(ctx context.Context, blobs []Blob, gasPrice float64, namespace Namespace) ([]ID, error)

// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs.
Validate(ctx context.Context, ids []ID, proofs []Proof, namespace Namespace) ([]bool, error)
Expand Down
15 changes: 14 additions & 1 deletion proto/da/da.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ service DAService {
// GetIDs returns IDs of all Blobs located in DA at given height.
rpc GetIDs(GetIDsRequest) returns (GetIDsResponse) {}

// GetProofs returns inclusion Proofs for all Blobs located in DA at given height.
rpc GetProofs(GetProofsRequest) returns (GetProofsResponse) {}

// Commit creates a Commitment for each given Blob.
rpc Commit(CommitRequest) returns (CommitResponse) {}

Expand Down Expand Up @@ -78,6 +81,17 @@ message GetIDsResponse {
repeated ID ids = 1;
}

// GetProofsRequest is the request type for the GetProofs rpc method.
message GetProofsRequest {
repeated ID ids = 1;
Namespace namespace = 2;
}

// GetProofsResponse is the response type for the GetProofs rpc method.
message GetProofsResponse {
repeated Proof proofs = 1;
}

// CommitRequest is the request type for the Commit rpc method.
message CommitRequest {
repeated Blob blobs = 1;
Expand All @@ -99,7 +113,6 @@ message SubmitRequest {
// SubmitResponse is the response type for the Submit rpc method.
message SubmitResponse {
repeated ID ids = 1;
repeated Proof proofs = 2;
}

// ValidateRequest is the request type for the Validate rpc method.
Expand Down
22 changes: 17 additions & 5 deletions proxy/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@
return idsPB2DA(resp.Ids), nil
}

// GetProofs returns inclusion Proofs for all Blobs located in DA at given height.
func (c *Client) GetProofs(ctx context.Context, ids []da.ID, namespace da.Namespace) ([]da.Proof, error) {
req := &pbda.GetProofsRequest{Ids: make([]*pbda.ID, len(ids)), Namespace: &pbda.Namespace{Value: namespace}}
for i := range ids {
req.Ids[i] = &pbda.ID{Value: ids[i]}
}
resp, err := c.client.GetProofs(ctx, req)
if err != nil {
return nil, err
}

Check warning on line 87 in proxy/client.go

View check run for this annotation

Codecov / codecov/patch

proxy/client.go#L86-L87

Added lines #L86 - L87 were not covered by tests

return proofsPB2DA(resp.Proofs), nil
}

// Commit creates a Commitment for each given Blob.
func (c *Client) Commit(ctx context.Context, blobs []da.Blob, namespace da.Namespace) ([]da.Commitment, error) {
req := &pbda.CommitRequest{
Expand All @@ -91,7 +105,7 @@
}

// Submit submits the Blobs to Data Availability layer.
func (c *Client) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, namespace da.Namespace) ([]da.ID, []da.Proof, error) {
func (c *Client) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, namespace da.Namespace) ([]da.ID, error) {
req := &pbda.SubmitRequest{
Blobs: blobsDA2PB(blobs),
GasPrice: gasPrice,
Expand All @@ -100,17 +114,15 @@

resp, err := c.client.Submit(ctx, req)
if err != nil {
return nil, nil, err
return nil, err

Check warning on line 117 in proxy/client.go

View check run for this annotation

Codecov / codecov/patch

proxy/client.go#L117

Added line #L117 was not covered by tests
}

ids := make([]da.ID, len(resp.Ids))
proofs := make([]da.Proof, len(resp.Proofs))
for i := range resp.Ids {
ids[i] = resp.Ids[i].Value
proofs[i] = resp.Proofs[i].Value
}

return ids, proofs, nil
return ids, nil
}

// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs.
Expand Down
16 changes: 12 additions & 4 deletions proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,30 @@
return &pbda.CommitResponse{Commitments: commitsDA2PB(commits)}, nil
}

func (p *proxySrv) GetProofs(ctx context.Context, request *pbda.GetProofsRequest) (*pbda.GetProofsResponse, error) {
ids := idsPB2DA(request.Ids)
proofs, err := p.target.GetProofs(ctx, ids, request.Namespace.GetValue())
if err != nil {
return nil, err
}

Check warning on line 64 in proxy/server.go

View check run for this annotation

Codecov / codecov/patch

proxy/server.go#L63-L64

Added lines #L63 - L64 were not covered by tests

return &pbda.GetProofsResponse{Proofs: proofsDA2PB(proofs)}, nil
}

func (p *proxySrv) Submit(ctx context.Context, request *pbda.SubmitRequest) (*pbda.SubmitResponse, error) {
blobs := blobsPB2DA(request.Blobs)

ids, proofs, err := p.target.Submit(ctx, blobs, request.GasPrice, request.Namespace.GetValue())
ids, err := p.target.Submit(ctx, blobs, request.GasPrice, request.Namespace.GetValue())
if err != nil {
return nil, err
}

resp := &pbda.SubmitResponse{
Ids: make([]*pbda.ID, len(ids)),
Proofs: make([]*pbda.Proof, len(proofs)),
Ids: make([]*pbda.ID, len(ids)),
}

for i := range ids {
resp.Ids[i] = &pbda.ID{Value: ids[i]}
resp.Proofs[i] = &pbda.Proof{Value: proofs[i]}
}

return resp, nil
Expand Down
22 changes: 18 additions & 4 deletions test/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ func (d *DummyDA) GetIDs(ctx context.Context, height uint64, _ da.Namespace) ([]
return ids, nil
}

// GetProofs returns inclusion Proofs for all Blobs located in DA at given height.
func (d *DummyDA) GetProofs(ctx context.Context, ids []da.ID, _ da.Namespace) ([]da.Proof, error) {
blobs, err := d.Get(ctx, ids, nil)

d.mu.Lock()
defer d.mu.Unlock()
if err != nil {
return nil, err
}
proofs := make([]da.Proof, len(blobs))
for i, blob := range blobs {
proofs[i] = d.getProof(ids[i], blob)
}
return proofs, nil
}

// Commit returns cryptographic Commitments for given blobs.
func (d *DummyDA) Commit(ctx context.Context, blobs []da.Blob, _ da.Namespace) ([]da.Commitment, error) {
commits := make([]da.Commitment, len(blobs))
Expand All @@ -100,20 +116,18 @@ func (d *DummyDA) Commit(ctx context.Context, blobs []da.Blob, _ da.Namespace) (
}

// Submit stores blobs in DA layer.
func (d *DummyDA) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, namespace da.Namespace) ([]da.ID, []da.Proof, error) {
func (d *DummyDA) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, _ da.Namespace) ([]da.ID, error) {
d.mu.Lock()
defer d.mu.Unlock()
ids := make([]da.ID, len(blobs))
proofs := make([]da.Proof, len(blobs))
d.height += 1
for i, blob := range blobs {
ids[i] = append(d.nextID(), d.getHash(blob)...)
proofs[i] = d.getProof(ids[i], blob)

d.data[d.height] = append(d.data[d.height], kvp{ids[i], blob})
}

return ids, proofs, nil
return ids, nil
}

// Validate checks the Proofs for given IDs.
Expand Down
39 changes: 9 additions & 30 deletions test/test_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,17 @@ func BasicDATest(t *testing.T, d da.DA) {
msg2 := []byte("message 2")

ctx := context.TODO()
id1, proof1, err := d.Submit(ctx, []da.Blob{msg1}, 0, testNamespace)
id1, err := d.Submit(ctx, []da.Blob{msg1}, 0, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, id1)
assert.NotEmpty(t, proof1)

id2, proof2, err := d.Submit(ctx, []da.Blob{msg2}, 0, testNamespace)
id2, err := d.Submit(ctx, []da.Blob{msg2}, 0, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, id2)
assert.NotEmpty(t, proof2)

id3, proof3, err := d.Submit(ctx, []da.Blob{msg1}, 0, testNamespace)
id3, err := d.Submit(ctx, []da.Blob{msg1}, 0, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, id3)
assert.NotEmpty(t, proof3)

assert.NotEqual(t, id1, id2)
assert.NotEqual(t, id1, id3)
Expand All @@ -66,33 +63,16 @@ func BasicDATest(t *testing.T, d da.DA) {
assert.NoError(t, err)
assert.NotEmpty(t, commitment2)

oks, err := d.Validate(ctx, id1, proof1, testNamespace)
ids := [][]byte{id1[0], id2[0], id3[0]}
proofs, err := d.GetProofs(ctx, ids, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, oks)
for _, ok := range oks {
assert.True(t, ok)
}

oks, err = d.Validate(ctx, id2, proof2, testNamespace)
assert.NotEmpty(t, proofs)
oks, err := d.Validate(ctx, ids, proofs, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, oks)
for _, ok := range oks {
assert.True(t, ok)
}

oks, err = d.Validate(ctx, id1, proof2, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, oks)
for _, ok := range oks {
assert.False(t, ok)
}

oks, err = d.Validate(ctx, id2, proof1, testNamespace)
assert.NoError(t, err)
assert.NotEmpty(t, oks)
for _, ok := range oks {
assert.False(t, ok)
}
}

// CheckErrors ensures that errors are handled properly by DA.
Expand All @@ -108,10 +88,9 @@ func GetIDsTest(t *testing.T, d da.DA) {
msgs := [][]byte{[]byte("msg1"), []byte("msg2"), []byte("msg3")}

ctx := context.TODO()
ids, proofs, err := d.Submit(ctx, msgs, 0, []byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0})
ids, err := d.Submit(ctx, msgs, 0, testNamespace)
assert.NoError(t, err)
assert.Len(t, ids, len(msgs))
assert.Len(t, proofs, len(msgs))

found := false
end := time.Now().Add(1 * time.Second)
Expand Down Expand Up @@ -162,7 +141,7 @@ func ConcurrentReadWriteTest(t *testing.T, d da.DA) {
go func() {
defer wg.Done()
for i := uint64(1); i <= 100; i++ {
_, _, err := d.Submit(ctx, [][]byte{[]byte("test")}, 0, []byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0})
_, err := d.Submit(ctx, [][]byte{[]byte("test")}, 0, testNamespace)
assert.NoError(t, err)
}
}()
Expand Down
Loading
Loading