Skip to content

Commit

Permalink
fix: parseNamespace for <= 10 byte namespace IDs (#2325)
Browse files Browse the repository at this point in the history
Co-authored-by: Ryan <ryanford@poluglottos.com>
  • Loading branch information
rootulp and distractedm1nd authored Jun 16, 2023
1 parent d5b571d commit 258dc78
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 29 deletions.
68 changes: 39 additions & 29 deletions cmd/celestia/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/spf13/cobra"

appns "github.com/celestiaorg/celestia-app/pkg/namespace"
"github.com/celestiaorg/nmt/namespace"

"github.com/celestiaorg/celestia-node/api/rpc/client"
Expand Down Expand Up @@ -112,17 +113,17 @@ func parseParams(method string, params []string) []interface{} {
}
parsedParams[0] = root
// 2. NamespaceID
nID, err := parseNamespace(params[1])
nID, err := parseV0NamespaceID(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
panic(fmt.Sprintf("Error parsing namespace ID: %v", err))
}
parsedParams[1] = nID
case "Submit":
// 1. NamespaceID
var err error
nID, err := parseNamespace(params[0])
nID, err := parseV0NamespaceID(params[0])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
panic(fmt.Sprintf("Error parsing namespace ID: %v", err))
}
// 2. Blob data
var blobData []byte
Expand Down Expand Up @@ -162,9 +163,9 @@ func parseParams(method string, params []string) []interface{} {
}
parsedParams[1] = num
// 3. NamespaceID
nID, err := parseNamespace(params[2])
nID, err := parseV0NamespaceID(params[2])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
panic(fmt.Sprintf("Error parsing namespace ID: %v", err))
}
// 4. Blob data
var blobData []byte
Expand Down Expand Up @@ -201,9 +202,9 @@ func parseParams(method string, params []string) []interface{} {
}
parsedParams[0] = num
// 2. NamespaceID
nID, err := parseNamespace(params[1])
nID, err := parseV0NamespaceID(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
panic(fmt.Sprintf("Error parsing namespace ID: %v", err))
}
parsedParams[1] = nID
// 3: Commitment
Expand All @@ -221,9 +222,9 @@ func parseParams(method string, params []string) []interface{} {
}
parsedParams[0] = num
// 2. NamespaceID
nID, err := parseNamespace(params[1])
nID, err := parseV0NamespaceID(params[1])
if err != nil {
panic(fmt.Sprintf("Error parsing namespace: %v", err))
panic(fmt.Sprintf("Error parsing namespace ID: %v", err))
}
parsedParams[1] = []namespace.ID{nID}
return parsedParams
Expand Down Expand Up @@ -368,7 +369,7 @@ func sendJSONRPCRequest(namespace, method string, params []interface{}) {

rawResponseJSON, err := parseJSON(string(responseBody))
if err != nil {
panic(err)
log.Fatalf("Error parsing JSON-RPC response: %v", err)
}
if printRequest {
output, err := json.MarshalIndent(outputWithRequest{
Expand Down Expand Up @@ -418,32 +419,41 @@ func parseSignatureForHelpstring(methodSig reflect.StructField) string {
return simplifiedSignature
}

func parseNamespace(param string) (namespace.ID, error) {
var nID []byte
var err error
// parseV0NamespaceID parses a namespace ID from a base64 or hex string. The param
// is expected to be the user-specified portion of a v0 namespace ID (i.e. the
// last 10 bytes).
func parseV0NamespaceID(param string) (namespace.ID, error) {
userBytes, err := decodeToBytes(param)
if err != nil {
return nil, err
}

if len(userBytes) > appns.NamespaceVersionZeroIDSize {
return nil, fmt.Errorf(
"namespace ID %v is too large to be a v0 namespace, want <= %v bytes",
userBytes, appns.NamespaceVersionZeroIDSize,
)
}
// if the namespace ID is <= 10 bytes, left pad it with 0s
return share.NewNamespaceV0(userBytes)
}

// decodeToBytes decodes a Base64 or hex input string into a byte slice.
func decodeToBytes(param string) ([]byte, 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)
}
return decoded, nil
}
// 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
}
// otherwise, it's just a base64 string
decoded, err := base64.StdEncoding.DecodeString(param)
if err != nil {
return nil, fmt.Errorf("error decoding namespace ID: %w", err)
}
return nID, nil
return decoded, nil
}

func parseJSON(param string) (json.RawMessage, error) {
var raw json.RawMessage
err := json.Unmarshal([]byte(param), &raw)
Expand Down
82 changes: 82 additions & 0 deletions cmd/celestia/rpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/celestiaorg/nmt/namespace"
)

func Test_parseNamespaceID(t *testing.T) {
type testCase struct {
name string
param string
want namespace.ID
wantErr bool
}
testCases := []testCase{
{
param: "0x0c204d39600fddd3",
name: "8 byte hex encoded namespace ID gets left padded",
want: namespace.ID{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x20, 0x4d, 0x39, 0x60, 0xf, 0xdd, 0xd3,
},
wantErr: false,
},
{
name: "10 byte hex encoded namespace ID",
param: "0x42690c204d39600fddd3",
want: namespace.ID{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x42, 0x69, 0xc, 0x20, 0x4d, 0x39, 0x60, 0xf, 0xdd, 0xd3,
},
wantErr: false,
},
{
name: "29 byte hex encoded namespace ID",
param: "0x0000000000000000000000000000000000000001010101010101010101",
want: namespace.ID{
0x0, // namespace version
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // v0 ID prefix
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // namespace ID
},
wantErr: true,
},
{
name: "11 byte hex encoded namespace ID returns error",
param: "0x42690c204d39600fddd3a3",
want: namespace.ID{},
wantErr: true,
},
{
name: "10 byte base64 encoded namespace ID",
param: "QmkMIE05YA/d0w==",
want: namespace.ID{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x42, 0x69, 0xc, 0x20, 0x4d, 0x39, 0x60, 0xf, 0xdd, 0xd3,
},
wantErr: false,
},
{
name: "not base64 or hex encoded namespace ID returns error",
param: "5748493939429",
want: namespace.ID{},
wantErr: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := parseV0NamespaceID(tc.param)
if tc.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.want, got)
})

}
}

0 comments on commit 258dc78

Please sign in to comment.