Skip to content

Commit

Permalink
feat!: modularize client and upgrade to node v0.13.4 (#117)
Browse files Browse the repository at this point in the history
This PR gives celestia-openrpc parity with the latest celestia-node
version.

It also modularizes the project, so that users can create clients
without needing to report all modules. This is good for integrations
where the codebase wants to minimize dependencies and we only need blob
module for example.

In addition, I have updated the README and added examples in the
`examples/` directory.

A workflow is added that tests the equivalence between node and
celestia-openrpc. This workflow can be set as a requirement once the
test in node is merged and released:
celestiaorg/celestia-node#3405

Note: We must release ASAP, otherwise the new code examples inside of
the golang client tutorial will not work
  • Loading branch information
distractedm1nd authored May 16, 2024
1 parent ac20f5a commit d3100e0
Show file tree
Hide file tree
Showing 26 changed files with 929 additions and 720 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ on:
- major

jobs:
# TODO: Uncomment once test is available in released node.
#api-equivalence:
#uses: ./github/workflows/test-equivalence.yml
#with:
#GO_VERSION: "1.22"

lint:
uses: ./.github/workflows/lint.yml
with:
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/test-equivalence.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# api-equivalence workflow ensures that the API structs between the two repositories are consistent
# This workflow is triggered by ci_release.yml workflow
name: api-equivalence
on:
workflow_call:
inputs:
GO_VERSION:
description: "Go version to use"
type: string
required: true

jobs:
test-equivalence:
name: Test API Equivalence
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
repository: celestiaorg/celestia-node
ref: v0.13.4
- uses: actions/setup-go@v5
with:
go-version: ${{ inputs.GO_VERSION }}

- name: Run Structs Equivalence Test
run: cd celestia-node && go test -v -tags=conformance ./api -run TestAPIEquivalence
66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,67 @@
# celestia-openrpc

OpenRPC is a client of [celestia-node RPC](https://docs.celestia.org/developers/node-api/), without depenencies on celestia-node/celestia-app/cosmos-sdk.
`celestia-openrpc` is a golang client for [celestia-node RPC](https://docs.celestia.org/developers/node-api/), without depenencies on celestia-node/celestia-app/cosmos-sdk.

This is a temporary measure to resolve dependency issues when celestia-node is imported by celestia.
This client library is useful for environments where dependencies on celestia-node/celestia-app/cosmos-sdk are not possible or desired.

## Examples

For a full tutorial on how to use this library, visit the official [guide](https://docs.celestia.org/developers/golang-client-tutorial).

For more examples, see the [examples](./examples) directory.

### Create a new client and submit and fetch a blob

```go
import (
"bytes"
"context"
"fmt"

client "github.com/celestiaorg/celestia-openrpc"
"github.com/celestiaorg/celestia-openrpc/types/blob"
"github.com/celestiaorg/celestia-openrpc/types/share"
"github.com/celestiaorg/rsmt2d"
)

func main() {
SubmitBlob(context.Background(), "ws://localhost:26658", "JWT_TOKEN")
}

// SubmitBlob submits a blob containing "Hello, World!" to the 0xDEADBEEF namespace. It uses the default signer on the running node.
func SubmitBlob(ctx context.Context, url string, token string) error {
client, err := client.NewClient(ctx, url, token)
if err != nil {
return err
}

// let's post to 0xDEADBEEF namespace
namespace, err := share.NewBlobNamespaceV0([]byte{0xDE, 0xAD, 0xBE, 0xEF})
if err != nil {
return err
}

// create a blob
helloWorldBlob, err := blob.NewBlobV0(namespace, []byte("Hello, World!"))
if err != nil {
return err
}

// submit the blob to the network
height, err := client.Blob.Submit(ctx, []*blob.Blob{helloWorldBlob}, blob.DefaultGasPrice())
if err != nil {
return err
}

fmt.Printf("Blob was included at height %d\n", height)

// fetch the blob back from the network
retrievedBlobs, err := client.Blob.GetAll(ctx, height, []share.Namespace{namespace})
if err != nil {
return err
}

fmt.Printf("Blobs are equal? %v\n", bytes.Equal(helloWorldBlob.Commitment, retrievedBlobs[0].Commitment))
return nil
}
```
184 changes: 0 additions & 184 deletions api.go

This file was deleted.

51 changes: 51 additions & 0 deletions builder/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package clientbuilder

import (
"context"
"fmt"
"net/http"
"reflect"
"strings"

"github.com/filecoin-project/go-jsonrpc"
)

const AuthKey = "Authorization"

// MultiClientCloser is a wrapper struct to close clients across multiple namespaces.
type MultiClientCloser struct {
closers []jsonrpc.ClientCloser
}

// Register adds a new closer to the multiClientCloser
func (m *MultiClientCloser) Register(closer jsonrpc.ClientCloser) {
m.closers = append(m.closers, closer)
}

// CloseAll closes all saved clients.
func (m *MultiClientCloser) CloseAll() {
for _, closer := range m.closers {
closer()
}
}

func NewClient(ctx context.Context, addr string, token string, client interface{}) (interface{}, error) {
var authHeader http.Header
if token != "" {
authHeader = http.Header{AuthKey: []string{fmt.Sprintf("Bearer %s", token)}}
}

v := reflect.ValueOf(client).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
name := strings.ToLower(field.Name)
module := v.Field(i).Addr().Interface()
_, err := jsonrpc.NewClient(ctx, addr, name, module, authHeader)
if err != nil {
return nil, err
}
}

return client, nil
}
Loading

0 comments on commit d3100e0

Please sign in to comment.