Skip to content

Commit

Permalink
feat(cmd/rpc): adding blob module to rpc cli and fixing namespace par…
Browse files Browse the repository at this point in the history
…sing (#2308)

This PR does the following:

### Adds blob module support
`blob.Submit` has been added with custom parsing for posting a single
blob.
`blob.GetAll` also only takes a single namespace id for now. This will
make devx easier

### Adds --print-request flag
Now the request can also be displayed along with the json response. This
will both help for debugging and building things that need to build the
requests themselves

### Fixes namespace parsing
Namespaces are now encoded correctly again. In addition, if you pass a
namespace of 8 bytes, it will zero-pad and use share/nID version 0.

### Fixes `state.SubmitPayForBlob`
Another issue was the change to an array. We now submit an array of a
single blob, and changed the order of the arguments.
The order is now: fee, gasLimit, namespaceID, blob data

### Adds formatted output
JQ is no longer needed to have an indented output. But colors are
missing

---------

Co-authored-by: rene <[email protected]>
  • Loading branch information
distractedm1nd and renaynay authored Jun 2, 2023
1 parent c6f4d68 commit 1247225
Showing 1 changed file with 158 additions and 30 deletions.
188 changes: 158 additions & 30 deletions cmd/celestia/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import (
"github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"

apptypes "github.com/celestiaorg/celestia-app/x/blob/types"
"github.com/celestiaorg/nmt/namespace"

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

Expand All @@ -28,6 +33,7 @@ const (

var requestURL string
var authTokenFlag string
var printRequest bool

type jsonRPCRequest struct {
ID int64 `json:"id"`
Expand All @@ -36,6 +42,11 @@ type jsonRPCRequest struct {
Params []interface{} `json:"params"`
}

type outputWithRequest struct {
Request jsonRPCRequest
Response json.RawMessage
}

func init() {
rpcCmd.PersistentFlags().StringVar(
&requestURL,
Expand All @@ -49,6 +60,12 @@ func init() {
"",
"Authorization token (if not provided, the "+authEnvKey+" environment variable will be used)",
)
rpcCmd.PersistentFlags().BoolVar(
&printRequest,
"print-request",
false,
"Print JSON-RPC request along with the response",
)
rootCmd.AddCommand(rpcCmd)
}

Expand Down Expand Up @@ -98,52 +115,117 @@ func parseParams(method string, params []string) []interface{} {
}
parsedParams[0] = root
// 2. NamespaceID
if strings.HasPrefix(params[1], "0x") {
decoded, err := hex.DecodeString(params[1][2:])
if err != nil {
panic("Error decoding namespace ID: hex string could not be decoded.")
}
parsedParams[1] = decoded
} else {
// otherwise, it's just a base64 string
parsedParams[1] = params[1]
nID, err := parseNamespace(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
return parsedParams
case "SubmitPayForBlob":
parsedParams[1] = nID
case "Submit":
// 1. NamespaceID
if strings.HasPrefix(params[0], "0x") {
decoded, err := hex.DecodeString(params[0][2:])
if err != nil {
panic("Error decoding namespace ID: hex string could not be decoded.")
}
parsedParams[0] = decoded
} else {
// otherwise, it's just a base64 string
parsedParams[0] = params[0]
var err error
nID, err := parseNamespace(params[0])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
// 2. Blob
// 2. Blob data
var blobData []byte
switch {
case strings.HasPrefix(params[1], "0x"):
decoded, err := hex.DecodeString(params[1][2:])
if err != nil {
panic("Error decoding blob: hex string could not be decoded.")
}
parsedParams[0] = decoded
blobData = decoded
case strings.HasPrefix(params[1], "\""):
// user input an utf string that needs to be encoded to base64
parsedParams[1] = base64.StdEncoding.EncodeToString([]byte(params[1]))
base64.StdEncoding.Encode(blobData, []byte(params[1]))
default:
// otherwise, we assume the user has already encoded their input to base64
parsedParams[1] = params[1]
blobData, err = base64.StdEncoding.DecodeString(params[1])
if err != nil {
panic("Error decoding blob data: base64 string could not be decoded.")
}
}
// 3. Fee (state.Int is a string)
parsedParams[2] = params[2]
// 4. GasLimit (uint64)
num, err := strconv.ParseUint(params[3], 10, 64)
parsedBlob, err := blob.NewBlob(0, nID, blobData)
if err != nil {
panic(fmt.Sprintf("Error creating blob: %v", err))
}
parsedParams[0] = []*blob.Blob{parsedBlob}
// param count doesn't match input length, so cut off nil values
return parsedParams[:1]
case "SubmitPayForBlob":
// 1. Fee (state.Int is a string)
parsedParams[0] = params[0]
// 2. GasLimit (uint64)
num, err := strconv.ParseUint(params[1], 10, 64)
if err != nil {
panic("Error parsing gas limit: uint64 could not be parsed.")
}
parsedParams[3] = num
parsedParams[1] = num
// 3. NamespaceID
nID, err := parseNamespace(params[2])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
// 4. Blob data
var blobData []byte
switch {
case strings.HasPrefix(params[3], "0x"):
decoded, err := hex.DecodeString(params[3][2:])
if err != nil {
panic("Error decoding blob: hex string could not be decoded.")
}
blobData = decoded
case strings.HasPrefix(params[3], "\""):
// user input an utf string that needs to be encoded to base64
base64.StdEncoding.Encode(blobData, []byte(params[3]))
default:
// otherwise, we assume the user has already encoded their input to base64
blobData, err = base64.StdEncoding.DecodeString(params[3])
if err != nil {
panic("Error decoding blob: base64 string could not be decoded.")
}
}
parsedParams[2] = []*apptypes.Blob{{
NamespaceId: nID[1:],
Data: blobData,
ShareVersion: 0,
NamespaceVersion: 0,
}}
return parsedParams[:3]
case "Get":
// 1. Height
num, err := strconv.ParseUint(params[0], 10, 64)
if err != nil {
panic("Error parsing gas limit: uint64 could not be parsed.")
}
parsedParams[0] = num
// 2. NamespaceID
nID, err := parseNamespace(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
parsedParams[1] = nID
// 3: Commitment
commitment, err := base64.StdEncoding.DecodeString(params[2])
if err != nil {
panic("Error decoding commitment: base64 string could not be decoded.")
}
parsedParams[2] = commitment
return parsedParams
case "GetAll": // NOTE: Over the cli, you can only pass one namespace
// 1. Height
num, err := strconv.ParseUint(params[0], 10, 64)
if err != nil {
panic("Error parsing gas limit: uint64 could not be parsed.")
}
parsedParams[0] = num
// 2. NamespaceID
nID, err := parseNamespace(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
}
parsedParams[1] = []namespace.ID{nID}
return parsedParams
case "QueryDelegation", "QueryUnbonding", "BalanceForAddress":
var err error
Expand Down Expand Up @@ -284,7 +366,27 @@ func sendJSONRPCRequest(namespace, method string, params []interface{}) {
log.Fatalf("Error reading response body: %v", err) //nolint:gocritic
}

fmt.Println(string(responseBody))
rawResponseJSON, err := parseJSON(string(responseBody))
if err != nil {
panic(err)
}
if printRequest {
output, err := json.MarshalIndent(outputWithRequest{
Request: request,
Response: rawResponseJSON,
}, "", " ")
if err != nil {
panic(fmt.Sprintf("Error marshaling JSON-RPC response: %v", err))
}
fmt.Println(string(output))
return
}

output, err := json.MarshalIndent(rawResponseJSON, "", " ")
if err != nil {
panic(fmt.Sprintf("Error marshaling JSON-RPC response: %v", err))
}
fmt.Println(string(output))
}

func parseAddressFromString(addrStr string) (state.Address, error) {
Expand Down Expand Up @@ -322,6 +424,32 @@ func parseSignatureForHelpstring(methodSig reflect.StructField) string {
return simplifiedSignature
}

func parseNamespace(param string) (namespace.ID, error) {
var nID []byte
var err error
if strings.HasPrefix(param, "0x") {
decoded, err := hex.DecodeString(param[2:])
if err != nil {
return nil, fmt.Errorf("error decoding namespace ID: %w", err)
}
nID = decoded
} else {
// otherwise, it's just a base64 string
nID, err = base64.StdEncoding.DecodeString(param)
if err != nil {
return nil, fmt.Errorf("error decoding namespace ID: %w", err)
}
}
// if the namespace ID is 8 bytes, add v0 share + namespace prefix and zero pad
if len(nID) == 8 {
nID, err = share.NewNamespaceV0(nID)
if err != nil {
return nil, err
}
}
return nID, nil
}

func parseJSON(param string) (json.RawMessage, error) {
var raw json.RawMessage
err := json.Unmarshal([]byte(param), &raw)
Expand Down

0 comments on commit 1247225

Please sign in to comment.