Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
vgonkivs committed Aug 1, 2023
1 parent 610c750 commit 145ea98
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 131 deletions.
226 changes: 95 additions & 131 deletions cmd/celestia/blob.go
Original file line number Diff line number Diff line change
@@ -1,236 +1,200 @@
package main

import (
"context"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"os"
"strconv"
"strings"

"github.com/spf13/cobra"

"github.com/celestiaorg/celestia-node/api/rpc/client"
"github.com/celestiaorg/celestia-node/blob"
"github.com/celestiaorg/celestia-node/share"
)

type response struct {
Result interface{} `json:"result"`
Error string `json:"error,omitempty"`
}

var rpcClient *client.Client

var blobCmd = &cobra.Command{
Use: "blob [command]",
Short: "Allows to interact with the Blob Service via JSON-RPC",
Args: cobra.NoArgs,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
client, err := getRPCClient(cmd.Context())
if err != nil {
return err
}

rpcClient = client
return nil
},
PersistentPostRun: func(_ *cobra.Command, _ []string) {
rpcClient.Close()
},
}

var getCmd = &cobra.Command{
Use: "Get [params]",
Use: "get [params]",
Args: cobra.ExactArgs(3),
Short: "Returns the blob for the given namespace by commitment at a particular height.",
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
client, err := rpcClient(cmd.Context())
if err != nil {
return err
}

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)
return fmt.Errorf("error parsing a height:%v", err)
}

// 2. Namespace
namespace, err := parseV0Namespace(args[1])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
return fmt.Errorf("error parsing a 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"),
)
os.Exit(1)
return fmt.Errorf("error parsing a commitment:%v", err)
}

blob, err := rpcClient.Blob.Get(cmd.Context(), num, namespace, commitment)
if err == nil {
if data, decodeErr := tryDecode(blob.Data); decodeErr == nil {
blob.Data = data
var output []byte
blob, err := client.Blob.Get(cmd.Context(), num, namespace, commitment)
if err != nil {
output, err = prepareOutput(err)
if err != nil {
return err
}
} else {
output, err = prepareOutput(blob)
if err != nil {
return err
}
}

output := prepareOutput(blob, err)
fmt.Fprintln(os.Stdout, string(output))
return nil
},
}

var getAllCmd = &cobra.Command{
Use: "GetAll [params]",
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)
RunE: func(cmd *cobra.Command, args []string) error {
client, err := rpcClient(cmd.Context())
if err != nil {
return err
}

height, 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)
return fmt.Errorf("error parsing a height:%v", err)
}

// 2. Namespace
namespace, err := parseV0Namespace(args[1])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
return fmt.Errorf("error parsing a namespace:%v", err)
}

blobs, err := rpcClient.Blob.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
}
var output []byte
blobs, err := client.Blob.GetAll(cmd.Context(), height, []share.Namespace{namespace})
if err != nil {
output, err = prepareOutput(err)
if err != nil {
return err
}
} else {
output, err = prepareOutput(blobs)
if err != nil {
return err
}
}

output := prepareOutput(blobs, err)
fmt.Fprintln(os.Stdout, string(output))
return nil
},
}

var submitCmd = &cobra.Command{
Use: "Submit [params]",
Use: "submit [params]",
Args: cobra.ExactArgs(2),
Short: "Submit the 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
RunE: func(cmd *cobra.Command, args []string) error {
client, err := rpcClient(cmd.Context())
if err != nil {
return err
}

namespace, err := parseV0Namespace(args[0])
if err != nil {
fmt.Fprintln(os.Stderr,
fmt.Errorf("error parsing namespace: %v", err),
)
os.Exit(1)
return fmt.Errorf("error parsing a namespace:%v", err)
}

// 2. Blob data
var blobData []byte
switch {
case strings.HasPrefix(args[1], "0x"):
decoded, err := hex.DecodeString(args[1][2:])
parsedBlob, err := blob.NewBlobV0(namespace, []byte(args[1]))
if err != nil {
return fmt.Errorf("error creating a blob:%v", err)
}

var output []byte
height, err := client.Blob.Submit(cmd.Context(), []*blob.Blob{parsedBlob})
if err != nil {
output, err = prepareOutput(err)
if err != nil {
fmt.Fprintln(os.Stderr, errors.New("error decoding blob: hex string could not be decoded"))
os.Exit(1)
return err
}
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])
} else {
output, err = prepareOutput(height)
if err != nil {
fmt.Fprintln(os.Stderr, errors.New("error decoding blob data: base64 string could not be decoded"))
os.Exit(1)
return err
}
}

parsedBlob, err := blob.NewBlobV0(namespace, blobData)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf("error creating blob: %v", err))
os.Exit(1)
}

height, err := rpcClient.Blob.Submit(cmd.Context(), []*blob.Blob{parsedBlob})
output := prepareOutput(height, err)

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

var getProofCmd = &cobra.Command{
Use: "GetProof [params]",
Use: "getProof [params]",
Args: cobra.ExactArgs(3),
Short: "Retrieves the 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)
RunE: func(cmd *cobra.Command, args []string) error {
client, err := rpcClient(cmd.Context())
if err != nil {
return err
}

height, 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)
return fmt.Errorf("error parsing a height:%v", err)
}

// 2. NamespaceID
namespace, err := parseV0Namespace(args[1])
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing namespace: %v", err))
os.Exit(1)
return fmt.Errorf("error parsing a 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"))
return fmt.Errorf("error parsing a commitment:%v", err)
}

var output []byte
proof, err := client.Blob.GetProof(cmd.Context(), height, namespace, commitment)
if err != nil {
output, err = prepareOutput(err)
if err != nil {
return err
}
} else {
output, err = prepareOutput(proof)
if err != nil {
return err
}
}

proof, err := rpcClient.Blob.GetProof(cmd.Context(), num, namespace, commitment)
output := prepareOutput(proof, err)
fmt.Fprintln(os.Stdout, string(output))
return nil
},
}

func prepareOutput(data interface{}, err error) []byte {
errStr := ""
if err != nil {
errStr = err.Error()
}

func prepareOutput(data interface{}) ([]byte, error) {
bytes, err := json.MarshalIndent(response{
Result: data,
Error: errStr,
}, "", " ")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
return nil, err
}
return bytes
}

// Golang marshals `[]byte` as a base64-encoded string, so without additional encoding data will
// not match the expectations. We need this functionality in order to get the original data.
func tryDecode(data []byte) ([]byte, error) {
return base64.StdEncoding.DecodeString(string(data))
}

func getRPCClient(ctx context.Context) (*client.Client, error) {
if authTokenFlag == "" {
authTokenFlag = os.Getenv(authEnvKey)
}

return client.NewClient(ctx, requestURL, authTokenFlag)
return bytes, nil
}
Loading

0 comments on commit 145ea98

Please sign in to comment.