Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
vgonkivs committed Jul 31, 2023
1 parent b175c32 commit 3ffa595
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 172 deletions.
306 changes: 159 additions & 147 deletions cmd/celestia/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,13 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"

"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"

"github.com/celestiaorg/celestia-node/api/rpc/client"
"github.com/celestiaorg/celestia-node/blob"
options "github.com/celestiaorg/celestia-node/cmd"
"github.com/celestiaorg/celestia-node/nodebuilder"
blob_api "github.com/celestiaorg/celestia-node/nodebuilder/blob"
"github.com/celestiaorg/celestia-node/share"
)
Expand All @@ -29,159 +24,182 @@ type response struct {
Error string `json:"error,omitempty"`
}

var rpcClient blob_api.API

var blobCmd = &cobra.Command{
Use: "blob [method] [params...]",
Use: "blob [subcommand]",
Short: "Allow to interact with the Blob Service via JSON-RPC",
Args: cobra.MinimumNArgs(2),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
blobApi := client.Modules["blob"]
methods := reflect.VisibleFields(reflect.TypeOf(blobApi).Elem())
var methodNames []string
for _, m := range methods {
methodNames = append(methodNames, m.Name+"\t"+parseSignatureForHelpstring(m))
Args: cobra.NoArgs,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
client, err := getRPCClient(cmd.Context())
if err != nil {
return err
}
return methodNames, cobra.ShellCompDirectiveNoFileComp

rpcClient = client.Blob
return nil
},
}

var getCmd = &cobra.Command{
Use: "Get [params]",
Args: cobra.ExactArgs(3),
Short: "Returns blob for the given namespace by commitment at a particular height",
Run: func(cmd *cobra.Command, args []string) {
client, err := getRPCClient(cmd.Context())
num, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
panic(err)
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing height: uint64 could not be parsed"),
)
os.Exit(1)
}
defer client.Close()

var requestFn func([]string, *blob_api.API) (interface{}, error)
// 2. Namespace
namespace, err := parseV0Namespace(args[1])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
}

// switch over method names
switch args[0] {
default:
panic("invalid method requested")
case "Submit":
requestFn = handleSubmit
case "Get":
requestFn = handleGet
case "GetAll":
requestFn = handleGetAll
case "GetProof":
requestFn = handleGetProof
// 3: Commitment
commitment, err := base64.StdEncoding.DecodeString(args[2])
if err != nil {
fmt.Fprintln(os.Stderr,
errors.New("error decoding commitment: base64 string could not be decoded"),
)
os.Exit(1)
}

blob, err := rpcClient.Get(cmd.Context(), num, namespace, commitment)
if err == nil {
if data, decodeErr := tryDecode(blob.Data); decodeErr == nil {
blob.Data = data
}
}

output := prepareOutput(requestFn(args[1:], &client.Blob))
fmt.Println(string(output))
output := prepareOutput(blob, err)
fmt.Fprintln(os.Stdout, string(output))
},
}

func handleGet(params []string, client *blob_api.API) (interface{}, error) {
// 1. Height
num, err := strconv.ParseUint(params[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("error parsing height: uint64 could not be parsed")
}

// 2. Namespace
namespace, err := parseV0Namespace(params[1])
if err != nil {
return nil, fmt.Errorf("error parsing namespace: %v", err)
}
var getAllCmd = &cobra.Command{
Use: "GetAll [params]",
Args: cobra.ExactArgs(2),
Short: "Returns all blobs for the given namespace at a particular height",
Run: func(cmd *cobra.Command, args []string) {
num, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing height: uint64 could not be parsed"),
)
os.Exit(1)
}

// 3: Commitment
commitment, err := base64.StdEncoding.DecodeString(params[2])
if err != nil {
return nil, errors.New("error decoding commitment: base64 string could not be decoded")
}
// 2. Namespace
namespace, err := parseV0Namespace(args[1])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
}

blob, err := client.Get(context.Background(), num, namespace, commitment)
if err != nil {
return nil, err
}
blobs, err := rpcClient.GetAll(cmd.Context(), num, []share.Namespace{namespace})
if err == nil {
for _, b := range blobs {
if data, err := tryDecode(b.Data); err == nil {
b.Data = data
}
}
}

if data, err := tryDecode(blob.Data); err == nil {
blob.Data = data
}
return blob, nil
output := prepareOutput(blobs, err)
fmt.Fprintln(os.Stdout, string(output))
},
}

func handleGetAll(params []string, client *blob_api.API) (interface{}, error) {
// 1. Height
num, err := strconv.ParseUint(params[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("error parsing height: uint64 could not be parsed")
}

// 2. Namespace
namespace, err := parseV0Namespace(params[1])
if err != nil {
return nil, fmt.Errorf("error parsing namespace: %v", err)
}
var submitCmd = &cobra.Command{
Use: "Submit [params]",
Args: cobra.ExactArgs(2),
Short: "Submit a blob at the given namespace. Note: only one blob is allowed to submit through the RPC.",
Run: func(cmd *cobra.Command, args []string) {
// 1. Namespace
namespace, err := parseV0Namespace(args[0])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
}

blobs, err := client.GetAll(context.Background(), num, []share.Namespace{namespace})
if err != nil {
return nil, fmt.Errorf("error getting blobs: %s", err)
}
// 2. Blob data
var blobData []byte
switch {
case strings.HasPrefix(args[1], "0x"):
decoded, err := hex.DecodeString(args[1][2:])
if err != nil {
fmt.Fprintln(os.Stderr, errors.New("error decoding blob: hex string could not be decoded"))
os.Exit(1)
}
blobData = decoded
case strings.HasPrefix(args[1], "\""):
// user input an utf string that needs to be encoded to base64
src := []byte(args[1])
blobData = make([]byte, base64.StdEncoding.EncodedLen(len(src)))
base64.StdEncoding.Encode(blobData, []byte(args[1]))
default:
// otherwise, we assume the user has already encoded their input to base64
blobData, err = base64.StdEncoding.DecodeString(args[1])
if err != nil {
fmt.Fprintln(os.Stderr, errors.New("error decoding blob data: base64 string could not be decoded"))
os.Exit(1)
}
}

for _, b := range blobs {
if data, err := tryDecode(b.Data); err == nil {
b.Data = data
parsedBlob, err := blob.NewBlobV0(namespace, blobData)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf("error creating blob: %v", err))
os.Exit(1)
}
}
return blobs, err
}

func handleSubmit(params []string, client *blob_api.API) (interface{}, error) {
// 1. Namespace
var err error
namespace, err := parseV0Namespace(params[0])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
height, err := rpcClient.Submit(cmd.Context(), []*blob.Blob{parsedBlob})
output := prepareOutput(height, err)

fmt.Fprintln(os.Stdout, string(output))
},
}

// 2. Blob data
var blobData []byte
switch {
case strings.HasPrefix(params[1], "0x"):
decoded, err := hex.DecodeString(params[1][2:])
var getProofCmd = &cobra.Command{
Use: "GetProof [params]",
Args: cobra.ExactArgs(3),
Short: "Retrieves a blob in the given namespaces at the given height by commitment and returns its Proof.",
Run: func(cmd *cobra.Command, args []string) {
// 1. Height
num, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return nil, errors.New("error decoding blob: hex string could not be decoded")
fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing height: uint64 could not be parsed"))
os.Exit(1)
}
blobData = decoded
case strings.HasPrefix(params[1], "\""):
// user input an utf string that needs to be encoded to base64
src := []byte(params[1])
blobData = make([]byte, base64.StdEncoding.EncodedLen(len(src)))
base64.StdEncoding.Encode(blobData, []byte(params[1]))
default:
// otherwise, we assume the user has already encoded their input to base64
blobData, err = base64.StdEncoding.DecodeString(params[1])

// 2. NamespaceID
namespace, err := parseV0Namespace(args[1])
if err != nil {
return nil, errors.New("error decoding blob data: base64 string could not be decoded")
fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing namespace: %v", err))
os.Exit(1)
}
}

parsedBlob, err := blob.NewBlobV0(namespace, blobData)
if err != nil {
return nil, fmt.Errorf("error creating blob: %v", err)
}
return client.Submit(context.Background(), []*blob.Blob{parsedBlob})
}

func handleGetProof(params []string, client *blob_api.API) (interface{}, error) {
// 1. Height
num, err := strconv.ParseUint(params[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("error parsing height: uint64 could not be parsed")
}

// 2. NamespaceID
namespace, err := parseV0Namespace(params[1])
if err != nil {
return nil, fmt.Errorf("error parsing namespace: %v", err)
}
// 3: Commitment
commitment, err := base64.StdEncoding.DecodeString(args[2])
if err != nil {
fmt.Fprintln(os.Stderr, errors.New("error decoding commitment: base64 string could not be decoded"))
}

// 3: Commitment
commitment, err := base64.StdEncoding.DecodeString(params[2])
if err != nil {
return nil, errors.New("error decoding commitment: base64 string could not be decoded")
}
return client.GetProof(context.Background(), num, namespace, commitment)
proof, err := rpcClient.GetProof(cmd.Context(), num, namespace, commitment)
output := prepareOutput(proof, err)
fmt.Fprintln(os.Stdout, string(output))
},
}

func prepareOutput(data interface{}, err error) []byte {
Expand All @@ -195,7 +213,8 @@ func prepareOutput(data interface{}, err error) []byte {
Error: errStr,
}, "", " ")
if err != nil {
panic(err)
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
return bytes
}
Expand All @@ -207,27 +226,20 @@ func tryDecode(data []byte) ([]byte, error) {
}

func getRPCClient(ctx context.Context) (*client.Client, error) {
expanded, err := homedir.Expand(filepath.Clean(options.StorePath(ctx)))
if err != nil {
return nil, err
}
key := os.Getenv(authEnvKey)
addr := os.Getenv(addrEnvKey)
port := os.Getenv(portEnvKey)

store, err := nodebuilder.OpenStoreReadOnly(expanded)
if err != nil {
return nil, err
if authTokenFlag == "" {
authTokenFlag = key
}
defer store.Close()

cfg, err := store.Config()
if err != nil {
return nil, err
if addr == "" {
addr = defaultAddress
}
addr := cfg.RPC.Address
port := cfg.RPC.Port
listenAddr := "http://" + addr + ":" + port

if authTokenFlag == "" {
authTokenFlag = os.Getenv(authEnvKey)
if port == "" {
port = defaultPort
}

listenAddr := "http://" + addr + ":" + port
return client.NewClient(ctx, listenAddr, authTokenFlag)
}
1 change: 1 addition & 0 deletions cmd/celestia/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func init() {
false,
"Print JSON-RPC request along with the response",
)
blobCmd.AddCommand(getCmd, getAllCmd, submitCmd, getProofCmd)
rpcCmd.AddCommand(blobCmd)
rootCmd.AddCommand(rpcCmd)
}
Expand Down
Loading

0 comments on commit 3ffa595

Please sign in to comment.