Skip to content

Commit

Permalink
feat!: GetProofs introduction (#38)
Browse files Browse the repository at this point in the history
* feat!: adding Namespace to remaining endpoints (#35)

* adding namespaces

* changing submitoptions to gasprice,ns

* adding namespace to remaining endpoints

* updating readme w note

* nit: lint md013 - skip tables

---------

Co-authored-by: Javed Khan <[email protected]>

updating readme w note

feat: GetProofs introduction

updating readme

* nit

* making GetProofs take da.ID slice instead of height
  • Loading branch information
distractedm1nd authored Feb 1, 2024
1 parent 58fb4d0 commit 011ba69
Show file tree
Hide file tree
Showing 8 changed files with 585 additions and 154 deletions.
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 @@ func (c *Client) GetIDs(ctx context.Context, height uint64, namespace da.Namespa
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
}

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 @@ func (c *Client) Commit(ctx context.Context, blobs []da.Blob, namespace da.Names
}

// 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 @@ func (c *Client) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64,

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

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 @@ func (p *proxySrv) Commit(ctx context.Context, request *pbda.CommitRequest) (*pb
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
}

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

0 comments on commit 011ba69

Please sign in to comment.