diff --git a/api/gateway/das.go b/api/gateway/das.go deleted file mode 100644 index 88dc97927c..0000000000 --- a/api/gateway/das.go +++ /dev/null @@ -1,28 +0,0 @@ -package gateway - -import ( - "encoding/json" - "net/http" -) - -const ( - dasStateEndpoint = "/daser/state" -) - -func (h *Handler) handleDASStateRequest(w http.ResponseWriter, r *http.Request) { - logDeprecation(dasStateEndpoint, "das.SamplingStats") - stats, err := h.das.SamplingStats(r.Context()) - if err != nil { - writeError(w, http.StatusInternalServerError, dasStateEndpoint, err) - return - } - resp, err := json.Marshal(stats) - if err != nil { - writeError(w, http.StatusInternalServerError, dasStateEndpoint, err) - return - } - _, err = w.Write(resp) - if err != nil { - log.Errorw("serving request", "endpoint", dasStateEndpoint, "err", err) - } -} diff --git a/api/gateway/endpoints.go b/api/gateway/endpoints.go index 9600138909..104d01b053 100644 --- a/api/gateway/endpoints.go +++ b/api/gateway/endpoints.go @@ -5,28 +5,7 @@ import ( "net/http" ) -func (h *Handler) RegisterEndpoints(rpc *Server, deprecatedEndpointsEnabled bool) { - if deprecatedEndpointsEnabled { - log.Warn("Deprecated endpoints will be removed from the gateway in the next release. Use the RPC instead.") - // state endpoints - rpc.RegisterHandlerFunc(balanceEndpoint, h.handleBalanceRequest, http.MethodGet) - rpc.RegisterHandlerFunc(submitPFBEndpoint, h.handleSubmitPFB, http.MethodPost) - - // staking queries - rpc.RegisterHandlerFunc(fmt.Sprintf("%s/{%s}", queryDelegationEndpoint, addrKey), h.handleQueryDelegation, - http.MethodGet) - rpc.RegisterHandlerFunc(fmt.Sprintf("%s/{%s}", queryUnbondingEndpoint, addrKey), h.handleQueryUnbonding, - http.MethodGet) - rpc.RegisterHandlerFunc(queryRedelegationsEndpoint, h.handleQueryRedelegations, - http.MethodPost) - - // DASer endpoints - // only register if DASer service is available - if h.das != nil { - rpc.RegisterHandlerFunc(dasStateEndpoint, h.handleDASStateRequest, http.MethodGet) - } - } - +func (h *Handler) RegisterEndpoints(rpc *Server) { // state endpoints rpc.RegisterHandlerFunc(fmt.Sprintf("%s/{%s}", balanceEndpoint, addrKey), h.handleBalanceRequest, http.MethodGet) diff --git a/api/gateway/state.go b/api/gateway/state.go index 69900b0bfc..13cf729cc6 100644 --- a/api/gateway/state.go +++ b/api/gateway/state.go @@ -9,17 +9,12 @@ import ( "github.com/cosmos/cosmos-sdk/types" "github.com/gorilla/mux" - "github.com/celestiaorg/celestia-node/blob" "github.com/celestiaorg/celestia-node/state" ) const ( - balanceEndpoint = "/balance" - submitTxEndpoint = "/submit_tx" - submitPFBEndpoint = "/submit_pfb" - queryDelegationEndpoint = "/query_delegation" - queryUnbondingEndpoint = "/query_unbonding" - queryRedelegationsEndpoint = "/query_redelegations" + balanceEndpoint = "/balance" + submitTxEndpoint = "/submit_tx" ) const addrKey = "address" @@ -34,21 +29,6 @@ type submitTxRequest struct { Tx string `json:"tx"` } -// submitPFBRequest represents a request to submit a PayForBlob -// transaction. -type submitPFBRequest struct { - NamespaceID string `json:"namespace_id"` - Data string `json:"data"` - Fee int64 `json:"fee"` - GasLimit uint64 `json:"gas_limit"` -} - -// queryRedelegationsRequest represents a request to query redelegations -type queryRedelegationsRequest struct { - From string `json:"from"` - To string `json:"to"` -} - func (h *Handler) handleBalanceRequest(w http.ResponseWriter, r *http.Request) { var ( bal *state.Balance @@ -57,24 +37,25 @@ func (h *Handler) handleBalanceRequest(w http.ResponseWriter, r *http.Request) { // read and parse request vars := mux.Vars(r) addrStr, exists := vars[addrKey] - if exists { - // convert address to Address type - var addr state.AccAddress - addr, err = types.AccAddressFromBech32(addrStr) + if !exists { + writeError(w, http.StatusBadRequest, balanceEndpoint, errors.New("balance endpoint requires address")) + return + } + + // convert address to Address type + var addr state.AccAddress + addr, err = types.AccAddressFromBech32(addrStr) + if err != nil { + // first check if it is a validator address and can be converted + valAddr, err := types.ValAddressFromBech32(addrStr) if err != nil { - // first check if it is a validator address and can be converted - valAddr, err := types.ValAddressFromBech32(addrStr) - if err != nil { - writeError(w, http.StatusBadRequest, balanceEndpoint, ErrInvalidAddressFormat) - return - } - addr = valAddr.Bytes() + writeError(w, http.StatusBadRequest, balanceEndpoint, ErrInvalidAddressFormat) + return } - bal, err = h.state.BalanceForAddress(r.Context(), state.Address{Address: addr}) - } else { - logDeprecation(balanceEndpoint, "state.Balance") - bal, err = h.state.Balance(r.Context()) + addr = valAddr.Bytes() } + + bal, err = h.state.BalanceForAddress(r.Context(), state.Address{Address: addr}) if err != nil { writeError(w, http.StatusInternalServerError, balanceEndpoint, err) return @@ -119,157 +100,3 @@ func (h *Handler) handleSubmitTx(w http.ResponseWriter, r *http.Request) { log.Errorw("writing response", "endpoint", submitTxEndpoint, "err", err) } } - -func (h *Handler) handleSubmitPFB(w http.ResponseWriter, r *http.Request) { - logDeprecation(submitPFBEndpoint, "blob.Submit or state.SubmitPayForBlob") - // decode request - var req submitPFBRequest - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - writeError(w, http.StatusBadRequest, submitPFBEndpoint, err) - return - } - namespace, err := hex.DecodeString(req.NamespaceID) - if err != nil { - writeError(w, http.StatusBadRequest, submitPFBEndpoint, err) - return - } - data, err := hex.DecodeString(req.Data) - if err != nil { - writeError(w, http.StatusBadRequest, submitPFBEndpoint, err) - return - } - fee := types.NewInt(req.Fee) - - constructedBlob, err := blob.NewBlobV0(namespace, data) - if err != nil { - writeError(w, http.StatusBadRequest, submitPFBEndpoint, err) - return - } - - // perform request - txResp, err := h.state.SubmitPayForBlob(r.Context(), fee, req.GasLimit, []*blob.Blob{constructedBlob}) - if err != nil { - if txResp == nil { - // no tx data to return - writeError(w, http.StatusBadRequest, submitPFBEndpoint, err) - return - } - // if error returned, change status from 200 to 206 - w.WriteHeader(http.StatusPartialContent) - } - - bs, err := json.Marshal(&txResp) - if err != nil { - writeError(w, http.StatusInternalServerError, submitPFBEndpoint, err) - return - } - - _, err = w.Write(bs) - if err != nil { - log.Errorw("writing response", "endpoint", submitPFBEndpoint, "err", err) - } -} - -func (h *Handler) handleQueryDelegation(w http.ResponseWriter, r *http.Request) { - logDeprecation(queryDelegationEndpoint, "state.QueryDelegation") - // read and parse request - vars := mux.Vars(r) - addrStr, exists := vars[addrKey] - if !exists { - writeError(w, http.StatusBadRequest, queryDelegationEndpoint, ErrMissingAddress) - return - } - - // convert address to Address type - addr, err := types.ValAddressFromBech32(addrStr) - if err != nil { - writeError(w, http.StatusBadRequest, queryDelegationEndpoint, err) - return - } - delegation, err := h.state.QueryDelegation(r.Context(), addr) - if err != nil { - writeError(w, http.StatusInternalServerError, queryDelegationEndpoint, err) - return - } - resp, err := json.Marshal(delegation) - if err != nil { - writeError(w, http.StatusInternalServerError, queryDelegationEndpoint, err) - return - } - _, err = w.Write(resp) - if err != nil { - log.Errorw("writing response", "endpoint", queryDelegationEndpoint, "err", err) - } -} - -func (h *Handler) handleQueryUnbonding(w http.ResponseWriter, r *http.Request) { - logDeprecation(queryUnbondingEndpoint, "state.QueryUnbonding") - // read and parse request - vars := mux.Vars(r) - addrStr, exists := vars[addrKey] - if !exists { - writeError(w, http.StatusBadRequest, queryUnbondingEndpoint, ErrMissingAddress) - return - } - - // convert address to Address type - addr, err := types.ValAddressFromBech32(addrStr) - if err != nil { - writeError(w, http.StatusBadRequest, queryUnbondingEndpoint, err) - return - } - unbonding, err := h.state.QueryUnbonding(r.Context(), addr) - if err != nil { - writeError(w, http.StatusInternalServerError, queryUnbondingEndpoint, err) - return - } - resp, err := json.Marshal(unbonding) - if err != nil { - writeError(w, http.StatusInternalServerError, queryUnbondingEndpoint, err) - return - } - _, err = w.Write(resp) - if err != nil { - log.Errorw("writing response", "endpoint", queryUnbondingEndpoint, "err", err) - } -} - -func (h *Handler) handleQueryRedelegations(w http.ResponseWriter, r *http.Request) { - logDeprecation(queryRedelegationsEndpoint, "state.QueryRedelegations") - var req queryRedelegationsRequest - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - writeError(w, http.StatusBadRequest, queryRedelegationsEndpoint, err) - return - } - srcValAddr, err := types.ValAddressFromBech32(req.From) - if err != nil { - writeError(w, http.StatusBadRequest, queryRedelegationsEndpoint, err) - return - } - dstValAddr, err := types.ValAddressFromBech32(req.To) - if err != nil { - writeError(w, http.StatusBadRequest, queryRedelegationsEndpoint, err) - return - } - unbonding, err := h.state.QueryRedelegations(r.Context(), srcValAddr, dstValAddr) - if err != nil { - writeError(w, http.StatusInternalServerError, queryRedelegationsEndpoint, err) - return - } - resp, err := json.Marshal(unbonding) - if err != nil { - writeError(w, http.StatusInternalServerError, queryRedelegationsEndpoint, err) - return - } - _, err = w.Write(resp) - if err != nil { - log.Errorw("writing response", "endpoint", queryRedelegationsEndpoint, "err", err) - } -} - -func logDeprecation(endpoint string, alternative string) { - log.Warn("The " + endpoint + " endpoint is deprecated and will be removed in the next release. Please " + - "use " + alternative + " from the RPC instead.") -} diff --git a/api/gateway/state_test.go b/api/gateway/state_test.go deleted file mode 100644 index aa9196cc8d..0000000000 --- a/api/gateway/state_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package gateway - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "errors" - "net/http" - "net/http/httptest" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - - stateMock "github.com/celestiaorg/celestia-node/nodebuilder/state/mocks" - "github.com/celestiaorg/celestia-node/share" - "github.com/celestiaorg/celestia-node/state" -) - -func TestHandleSubmitPFB(t *testing.T) { - ctrl := gomock.NewController(t) - mock := stateMock.NewMockModule(ctrl) - handler := NewHandler(mock, nil, nil, nil) - - t.Run("partial response", func(t *testing.T) { - txResponse := state.TxResponse{ - Height: 1, - TxHash: "hash", - Codespace: "codespace", - Code: 1, - } - // simulate core-app err, since it is not exported - timedErr := errors.New("timed out waiting for tx to be included in a block") - mock.EXPECT().SubmitPayForBlob(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). - Return(&txResponse, timedErr) - - ns, err := share.NewBlobNamespaceV0([]byte("abc")) - require.NoError(t, err) - hexNs := hex.EncodeToString(ns[:]) - - bs, err := json.Marshal(submitPFBRequest{ - NamespaceID: hexNs, - Data: "DEADBEEF", - }) - require.NoError(t, err) - httpreq := httptest.NewRequest("GET", "/", bytes.NewReader(bs)) - respRec := httptest.NewRecorder() - handler.handleSubmitPFB(respRec, httpreq) - - var resp state.TxResponse - err = json.NewDecoder(respRec.Body).Decode(&resp) - require.NoError(t, err) - - require.Equal(t, http.StatusPartialContent, respRec.Code) - require.Equal(t, resp, txResponse) - }) -} diff --git a/cmd/auth.go b/cmd/auth.go index eb2000675e..3006526b15 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -25,59 +25,61 @@ func AuthCmd(fsets ...*flag.FlagSet) *cobra.Command { Short: "Signs and outputs a hex-encoded JWT token with the given permissions.", Long: "Signs and outputs a hex-encoded JWT token with the given permissions. NOTE: only use this command when " + "the node has already been initialized and started.", - RunE: newToken, - } + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("must specify permissions") + } + permissions, err := convertToPerms(args[0]) + if err != nil { + return err + } - for _, set := range fsets { - cmd.Flags().AddFlagSet(set) - } - return cmd -} + ks, err := newKeystore(StorePath(cmd.Context())) + if err != nil { + return err -func newToken(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return fmt.Errorf("must specify permissions") - } + } - permissions, err := convertToPerms(args[0]) - if err != nil { - return err - } + key, err := ks.Get(nodemod.SecretName) + if err != nil { + if !errors.Is(err, keystore.ErrNotFound) { + return err + } + key, err = generateNewKey(ks) + if err != nil { + return err + } + } - expanded, err := homedir.Expand(filepath.Clean(StorePath(cmd.Context()))) - if err != nil { - return err - } - ks, err := keystore.NewFSKeystore(filepath.Join(expanded, "keys"), nil) - if err != nil { - return err + token, err := buildJWTToken(key.Body, permissions) + if err != nil { + return err + } + fmt.Printf("%s", token) + return nil + }, } - var key keystore.PrivKey - key, err = ks.Get(nodemod.SecretName) - if err != nil { - if !errors.Is(err, keystore.ErrNotFound) { - return err - } - // otherwise, generate and save new priv key - key, err = generateNewKey(ks) - if err != nil { - return err - } + for _, set := range fsets { + cmd.Flags().AddFlagSet(set) } + return cmd +} - signer, err := jwt.NewHS256(key.Body) +func newKeystore(path string) (keystore.Keystore, error) { + expanded, err := homedir.Expand(filepath.Clean(path)) if err != nil { - return err + return nil, err } + return keystore.NewFSKeystore(filepath.Join(expanded, "keys"), nil) +} - token, err := authtoken.NewSignedJWT(signer, permissions) +func buildJWTToken(body []byte, permissions []auth.Permission) (string, error) { + signer, err := jwt.NewHS256(body) if err != nil { - return err + return "", err } - - fmt.Printf("%s", token) - return nil + return authtoken.NewSignedJWT(signer, permissions) } func generateNewKey(ks keystore.Keystore) (keystore.PrivKey, error) { diff --git a/cmd/celestia/bridge.go b/cmd/celestia/bridge.go index fb5066e5d4..c0e2ab0d1a 100644 --- a/cmd/celestia/bridge.go +++ b/cmd/celestia/bridge.go @@ -42,6 +42,6 @@ var bridgeCmd = &cobra.Command{ Args: cobra.NoArgs, Short: "Manage your Bridge node", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - return persistentPreRunEnv(cmd, node.Bridge, args) + return cmdnode.PersistentPreRunEnv(cmd, node.Bridge, args) }, } diff --git a/cmd/celestia/cmd_test.go b/cmd/celestia/cmd_test.go index 503548b708..9c26489e14 100644 --- a/cmd/celestia/cmd_test.go +++ b/cmd/celestia/cmd_test.go @@ -128,3 +128,23 @@ func TestBridge(t *testing.T) { }) */ } + +func parseSignatureForHelpstring(methodSig reflect.StructField) string { + simplifiedSignature := "(" + in, out := methodSig.Type.NumIn(), methodSig.Type.NumOut() + for i := 1; i < in; i++ { + simplifiedSignature += methodSig.Type.In(i).String() + if i != in-1 { + simplifiedSignature += ", " + } + } + simplifiedSignature += ") -> (" + for i := 0; i < out-1; i++ { + simplifiedSignature += methodSig.Type.Out(i).String() + if i != out-2 { + simplifiedSignature += ", " + } + } + simplifiedSignature += ")" + return simplifiedSignature +} diff --git a/cmd/celestia/full.go b/cmd/celestia/full.go index 912de0bca8..8baff1080e 100644 --- a/cmd/celestia/full.go +++ b/cmd/celestia/full.go @@ -46,6 +46,6 @@ var fullCmd = &cobra.Command{ Args: cobra.NoArgs, Short: "Manage your Full node", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - return persistentPreRunEnv(cmd, node.Full, args) + return cmdnode.PersistentPreRunEnv(cmd, node.Full, args) }, } diff --git a/cmd/celestia/light.go b/cmd/celestia/light.go index 9c63945445..553660c5d3 100644 --- a/cmd/celestia/light.go +++ b/cmd/celestia/light.go @@ -46,6 +46,6 @@ var lightCmd = &cobra.Command{ Args: cobra.NoArgs, Short: "Manage your Light node", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - return persistentPreRunEnv(cmd, node.Light, args) + return cmdnode.PersistentPreRunEnv(cmd, node.Light, args) }, } diff --git a/cmd/celestia/logs.go b/cmd/celestia/logs.go deleted file mode 100644 index ac302ff6dd..0000000000 --- a/cmd/celestia/logs.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" - - "github.com/celestiaorg/celestia-node/cmd" -) - -var logCmd = &cobra.Command{ - Use: cmd.LogLevelFlag, - Args: cobra.ExactArgs(1), - Short: "Allows to set log level for all modules to " + - "`DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL and their lower-case forms`", - - RunE: func(c *cobra.Command, args []string) error { - client, err := rpcClient(c.Context()) - if err != nil { - return err - } - return client.Node.LogLevelSet(c.Context(), "*", args[0]) - }, -} - -var logModuleCmd = &cobra.Command{ - Use: cmd.LogLevelModuleFlag, - Args: cobra.MinimumNArgs(1), - Short: "Allows to set log level for a particular module in format :", - RunE: func(c *cobra.Command, args []string) error { - client, err := rpcClient(c.Context()) - if err != nil { - return err - } - for _, ll := range args { - params := strings.Split(ll, ":") - if len(params) != 2 { - return fmt.Errorf("cmd: %s arg must be in form :,"+ - "e.g. pubsub:debug", cmd.LogLevelModuleFlag) - } - if err = client.Node.LogLevelSet(c.Context(), params[0], params[1]); err != nil { - return err - } - } - return nil - }, -} diff --git a/cmd/celestia/rpc.go b/cmd/celestia/rpc.go index c263496b26..11e96c2e46 100644 --- a/cmd/celestia/rpc.go +++ b/cmd/celestia/rpc.go @@ -1,402 +1,32 @@ package main import ( - "bytes" - "context" - "encoding/base64" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "io" - "log" - "net/http" - "os" - "reflect" - "strconv" - "strings" - - "github.com/spf13/cobra" - - "github.com/celestiaorg/celestia-node/api/rpc/client" - "github.com/celestiaorg/celestia-node/share" - "github.com/celestiaorg/celestia-node/state" + "github.com/celestiaorg/celestia-node/cmd" + blob "github.com/celestiaorg/celestia-node/nodebuilder/blob/cmd" + das "github.com/celestiaorg/celestia-node/nodebuilder/das/cmd" + header "github.com/celestiaorg/celestia-node/nodebuilder/header/cmd" + node "github.com/celestiaorg/celestia-node/nodebuilder/node/cmd" + p2p "github.com/celestiaorg/celestia-node/nodebuilder/p2p/cmd" + share "github.com/celestiaorg/celestia-node/nodebuilder/share/cmd" + state "github.com/celestiaorg/celestia-node/nodebuilder/state/cmd" ) -const authEnvKey = "CELESTIA_NODE_AUTH_TOKEN" //nolint:gosec - -var requestURL string -var authTokenFlag string -var printRequest bool - -type jsonRPCRequest struct { - ID int64 `json:"id"` - JSONRPC string `json:"jsonrpc"` - Method string `json:"method"` - Params []interface{} `json:"params"` -} - -type outputWithRequest struct { - Request jsonRPCRequest - Response json.RawMessage -} - func init() { - rpcCmd.PersistentFlags().StringVar( - &requestURL, - "url", - "http://localhost:26658", - "Request URL", - ) - rpcCmd.PersistentFlags().StringVar( - &authTokenFlag, - "auth", - "", - "Authorization token (if not provided, the "+authEnvKey+" environment variable will be used)", + blob.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + das.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + header.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + p2p.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + share.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + state.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + node.Cmd.PersistentFlags().AddFlagSet(cmd.RPCFlags()) + + rootCmd.AddCommand( + blob.Cmd, + das.Cmd, + header.Cmd, + p2p.Cmd, + share.Cmd, + state.Cmd, + node.Cmd, ) - rpcCmd.PersistentFlags().BoolVar( - &printRequest, - "print-request", - false, - "Print JSON-RPC request along with the response", - ) - rpcCmd.AddCommand(logCmd, logModuleCmd) - rpcCmd.AddCommand(blobCmd) - rootCmd.AddCommand(rpcCmd) -} - -var rpcCmd = &cobra.Command{ - Use: "rpc [namespace] [method] [params...]", - Short: "Send JSON-RPC request", - Args: cobra.MinimumNArgs(2), - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - rpcClient, err := newRPCClient(cmd.Context()) - if err != nil { - return err - } - - ctx := context.WithValue(cmd.Context(), rpcClientKey{}, rpcClient) - cmd.SetContext(ctx) - return nil - }, - PersistentPostRunE: func(cmd *cobra.Command, args []string) error { - client, err := rpcClient(cmd.Context()) - if err != nil { - return err - } - - client.Close() - return nil - }, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - modules := client.Modules - if len(args) == 0 { - // get keys from modules (map[string]interface{}) - var keys []string - for k := range modules { - keys = append(keys, k) - } - return keys, cobra.ShellCompDirectiveNoFileComp - } else if len(args) == 1 { - // get methods from module - module := modules[args[0]] - methods := reflect.VisibleFields(reflect.TypeOf(module).Elem()) - var methodNames []string - for _, m := range methods { - methodNames = append(methodNames, m.Name+"\t"+parseSignatureForHelpstring(m)) - } - return methodNames, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveNoFileComp - }, - Run: func(cmd *cobra.Command, args []string) { - namespace := args[0] - method := args[1] - params := parseParams(method, args[2:]) - - sendJSONRPCRequest(namespace, method, params) - }, -} - -func parseParams(method string, params []string) []interface{} { - parsedParams := make([]interface{}, len(params)) - validateParamsFn := func(has, want int) error { - if has != want { - return fmt.Errorf("rpc: invalid amount of params. has=%d, want=%d", has, want) - } - return nil - } - switch method { - case "GetSharesByNamespace": - if err := validateParamsFn(len(params), 2); err != nil { - panic(err) - } - // 1. Share Root - root, err := parseJSON(params[0]) - if err != nil { - panic(fmt.Errorf("couldn't parse share root as json: %v", err)) - } - parsedParams[0] = root - // 2. Namespace - namespace, err := parseV0Namespace(params[1]) - if err != nil { - panic(fmt.Sprintf("Error parsing namespace: %v", err)) - } - parsedParams[1] = namespace - return parsedParams - case "QueryDelegation", "QueryUnbonding", "BalanceForAddress": - var err error - if err = validateParamsFn(len(params), 2); err != nil { - panic(err) - } - parsedParams[0], err = parseAddressFromString(params[0]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - return parsedParams - case "QueryRedelegations": - var err error - parsedParams[0], err = parseAddressFromString(params[0]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - parsedParams[1], err = parseAddressFromString(params[1]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - return parsedParams - case "Transfer", "Delegate", "Undelegate": - // 1. Address - var err error - if err = validateParamsFn(len(params), 4); err != nil { - panic(err) - } - parsedParams[0], err = parseAddressFromString(params[0]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - // 2. Amount + Fee - parsedParams[1] = params[1] - parsedParams[2] = params[2] - // 3. GasLimit (uint64) - num, err := strconv.ParseUint(params[3], 10, 64) - if err != nil { - panic("Error parsing gas limit: uint64 could not be parsed.") - } - parsedParams[3] = num - return parsedParams - case "CancelUnbondingDelegation": - // 1. Validator Address - var err error - if err = validateParamsFn(len(params), 5); err != nil { - panic(err) - } - parsedParams[0], err = parseAddressFromString(params[0]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - // 2. Amount + Height + Fee - parsedParams[1] = params[1] - parsedParams[2] = params[2] - parsedParams[3] = params[3] - // 4. GasLimit (uint64) - num, err := strconv.ParseUint(params[4], 10, 64) - if err != nil { - panic("Error parsing gas limit: uint64 could not be parsed.") - } - parsedParams[4] = num - return parsedParams - case "BeginRedelegate": - // 1. Source Validator Address - var err error - if err = validateParamsFn(len(params), 5); err != nil { - panic(err) - } - parsedParams[0], err = parseAddressFromString(params[0]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - // 2. Destination Validator Address - parsedParams[1], err = parseAddressFromString(params[1]) - if err != nil { - panic(fmt.Errorf("error parsing address: %w", err)) - } - // 2. Amount + Fee - parsedParams[2] = params[2] - parsedParams[3] = params[3] - // 4. GasLimit (uint64) - num, err := strconv.ParseUint(params[4], 10, 64) - if err != nil { - panic("Error parsing gas limit: uint64 could not be parsed.") - } - parsedParams[4] = num - return parsedParams - default: - } - - for i, param := range params { - if param[0] == '{' || param[0] == '[' { - rawJSON, err := parseJSON(param) - if err != nil { - parsedParams[i] = param - } else { - parsedParams[i] = rawJSON - } - } else { - // try to parse arguments as numbers before adding them as strings - num, err := strconv.ParseInt(param, 10, 64) - if err == nil { - parsedParams[i] = num - continue - } - parsedParams[i] = param - } - } - return parsedParams -} - -func sendJSONRPCRequest(namespace, method string, params []interface{}) { - url := requestURL - request := jsonRPCRequest{ - ID: 1, - JSONRPC: "2.0", - Method: fmt.Sprintf("%s.%s", namespace, method), - Params: params, - } - - requestBody, err := json.Marshal(request) - if err != nil { - log.Fatalf("Error marshaling JSON-RPC request: %v", err) - } - - req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody)) - if err != nil { - log.Fatalf("Error creating JSON-RPC request: %v", err) - } - - req.Header.Set("Content-Type", "application/json") - - authToken := authTokenFlag - if authToken == "" { - authToken = os.Getenv(authEnvKey) - } - if authToken != "" { - req.Header.Set("Authorization", "Bearer "+authToken) - } - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - log.Fatalf("Error sending JSON-RPC request: %v", err) - } - defer resp.Body.Close() - - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - log.Fatalf("Error reading response body: %v", err) //nolint:gocritic - } - - rawResponseJSON, err := parseJSON(string(responseBody)) - if err != nil { - log.Fatalf("Error parsing JSON-RPC response: %v", 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) { - var address state.Address - err := address.UnmarshalJSON([]byte(addrStr)) - if err != nil { - return address, err - } - return address, nil -} - -func parseSignatureForHelpstring(methodSig reflect.StructField) string { - simplifiedSignature := "(" - in, out := methodSig.Type.NumIn(), methodSig.Type.NumOut() - for i := 1; i < in; i++ { - simplifiedSignature += methodSig.Type.In(i).String() - if i != in-1 { - simplifiedSignature += ", " - } - } - simplifiedSignature += ") -> (" - for i := 0; i < out-1; i++ { - simplifiedSignature += methodSig.Type.Out(i).String() - if i != out-2 { - simplifiedSignature += ", " - } - } - simplifiedSignature += ")" - return simplifiedSignature -} - -// parseV0Namespace parses a namespace 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 parseV0Namespace(param string) (share.Namespace, error) { - userBytes, err := decodeToBytes(param) - if err != nil { - return nil, err - } - - // if the namespace ID is <= 10 bytes, left pad it with 0s - return share.NewBlobNamespaceV0(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) - } - return decoded, nil - } - // 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 decoded, nil -} - -func parseJSON(param string) (json.RawMessage, error) { - var raw json.RawMessage - err := json.Unmarshal([]byte(param), &raw) - return raw, err -} - -func newRPCClient(ctx context.Context) (*client.Client, error) { - if authTokenFlag == "" { - authTokenFlag = os.Getenv(authEnvKey) - } - return client.NewClient(ctx, requestURL, authTokenFlag) -} - -type rpcClientKey struct{} - -func rpcClient(ctx context.Context) (*client.Client, error) { - client, ok := ctx.Value(rpcClientKey{}).(*client.Client) - if !ok { - return nil, errors.New("rpc client was not set") - } - return client, nil } diff --git a/cmd/celestia/util.go b/cmd/celestia/util.go deleted file mode 100644 index a38860d1f7..0000000000 --- a/cmd/celestia/util.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "github.com/spf13/cobra" - - cmdnode "github.com/celestiaorg/celestia-node/cmd" - "github.com/celestiaorg/celestia-node/nodebuilder/core" - "github.com/celestiaorg/celestia-node/nodebuilder/gateway" - "github.com/celestiaorg/celestia-node/nodebuilder/header" - "github.com/celestiaorg/celestia-node/nodebuilder/node" - "github.com/celestiaorg/celestia-node/nodebuilder/p2p" - "github.com/celestiaorg/celestia-node/nodebuilder/rpc" - "github.com/celestiaorg/celestia-node/nodebuilder/state" -) - -func persistentPreRunEnv(cmd *cobra.Command, nodeType node.Type, _ []string) error { - var ( - ctx = cmd.Context() - err error - ) - - ctx = cmdnode.WithNodeType(ctx, nodeType) - - parsedNetwork, err := p2p.ParseNetwork(cmd) - if err != nil { - return err - } - ctx = cmdnode.WithNetwork(ctx, parsedNetwork) - - // loads existing config into the environment - ctx, err = cmdnode.ParseNodeFlags(ctx, cmd, cmdnode.Network(ctx)) - if err != nil { - return err - } - - cfg := cmdnode.NodeConfig(ctx) - - err = p2p.ParseFlags(cmd, &cfg.P2P) - if err != nil { - return err - } - - err = core.ParseFlags(cmd, &cfg.Core) - if err != nil { - return err - } - - if nodeType != node.Bridge { - err = header.ParseFlags(cmd, &cfg.Header) - if err != nil { - return err - } - } - - ctx, err = cmdnode.ParseMiscFlags(ctx, cmd) - if err != nil { - return err - } - - rpc.ParseFlags(cmd, &cfg.RPC) - gateway.ParseFlags(cmd, &cfg.Gateway) - state.ParseFlags(cmd, &cfg.State) - - // set config - ctx = cmdnode.WithNodeConfig(ctx, &cfg) - cmd.SetContext(ctx) - return nil -} diff --git a/cmd/flags_node.go b/cmd/flags_node.go index 8c73a06169..fe4981b6c6 100644 --- a/cmd/flags_node.go +++ b/cmd/flags_node.go @@ -15,7 +15,7 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/p2p" ) -var ( +const ( nodeStoreFlag = "node.store" nodeConfigFlag = "node.config" ) diff --git a/cmd/rpc.go b/cmd/rpc.go new file mode 100644 index 0000000000..62e9fe7923 --- /dev/null +++ b/cmd/rpc.go @@ -0,0 +1,98 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + + rpc "github.com/celestiaorg/celestia-node/api/rpc/client" + "github.com/celestiaorg/celestia-node/api/rpc/perms" + nodemod "github.com/celestiaorg/celestia-node/nodebuilder/node" +) + +const ( + // defaultRPCAddress is a default address to dial to + defaultRPCAddress = "http://localhost:26658" +) + +var ( + requestURL string + authTokenFlag string +) + +func RPCFlags() *flag.FlagSet { + fset := &flag.FlagSet{} + + fset.StringVar( + &requestURL, + "url", + defaultRPCAddress, + "Request URL", + ) + + fset.StringVar( + &authTokenFlag, + "token", + "", + "Authorization token", + ) + + storeFlag := NodeFlags().Lookup(nodeStoreFlag) + fset.AddFlag(storeFlag) + return fset +} + +func InitClient(cmd *cobra.Command, _ []string) error { + if authTokenFlag == "" { + storePath := "" + if !cmd.Flag(nodeStoreFlag).Changed { + return fmt.Errorf("cant get the access to the auth token: token/node-store flag was not specified") + } + storePath = cmd.Flag(nodeStoreFlag).Value.String() + token, err := getToken(storePath) + if err != nil { + return fmt.Errorf("cant get the access to the auth token: %v", err) + } + authTokenFlag = token + } + + client, err := rpc.NewClient(cmd.Context(), requestURL, authTokenFlag) + if err != nil { + return err + } + + ctx := context.WithValue(cmd.Context(), rpcClientKey{}, client) + cmd.SetContext(ctx) + return nil +} + +func getToken(path string) (string, error) { + if path == "" { + return "", errors.New("root directory was not specified") + } + + ks, err := newKeystore(path) + if err != nil { + return "", err + } + + key, err := ks.Get(nodemod.SecretName) + if err != nil { + fmt.Printf("error getting the JWT secret: %v", err) + return "", err + } + return buildJWTToken(key.Body, perms.AllPerms) +} + +type rpcClientKey struct{} + +func ParseClientFromCtx(ctx context.Context) (*rpc.Client, error) { + client, ok := ctx.Value(rpcClientKey{}).(*rpc.Client) + if !ok { + return nil, errors.New("rpc client was not set") + } + return client, nil +} diff --git a/cmd/util.go b/cmd/util.go new file mode 100644 index 0000000000..625685fe0b --- /dev/null +++ b/cmd/util.go @@ -0,0 +1,127 @@ +package cmd + +import ( + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" + + "github.com/celestiaorg/celestia-node/nodebuilder/core" + "github.com/celestiaorg/celestia-node/nodebuilder/gateway" + "github.com/celestiaorg/celestia-node/nodebuilder/header" + "github.com/celestiaorg/celestia-node/nodebuilder/node" + "github.com/celestiaorg/celestia-node/nodebuilder/p2p" + rpc_cfg "github.com/celestiaorg/celestia-node/nodebuilder/rpc" + "github.com/celestiaorg/celestia-node/nodebuilder/state" + "github.com/celestiaorg/celestia-node/share" +) + +func PrintOutput(data interface{}, err error, formatData func(interface{}) interface{}) error { + switch { + case err != nil: + data = err + case formatData != nil: + data = formatData(data) + } + + resp := struct { + Result interface{} `json:"result"` + }{ + Result: data, + } + + bytes, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return err + } + fmt.Fprintln(os.Stdout, string(bytes)) + return nil +} + +// ParseV0Namespace parses a namespace 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 ParseV0Namespace(param string) (share.Namespace, error) { + userBytes, err := DecodeToBytes(param) + if err != nil { + return nil, err + } + + // if the namespace ID is <= 10 bytes, left pad it with 0s + return share.NewBlobNamespaceV0(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) + } + return decoded, nil + } + // 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 decoded, nil +} + +func PersistentPreRunEnv(cmd *cobra.Command, nodeType node.Type, _ []string) error { + var ( + ctx = cmd.Context() + err error + ) + + ctx = WithNodeType(ctx, nodeType) + + parsedNetwork, err := p2p.ParseNetwork(cmd) + if err != nil { + return err + } + ctx = WithNetwork(ctx, parsedNetwork) + + // loads existing config into the environment + ctx, err = ParseNodeFlags(ctx, cmd, Network(ctx)) + if err != nil { + return err + } + + cfg := NodeConfig(ctx) + + err = p2p.ParseFlags(cmd, &cfg.P2P) + if err != nil { + return err + } + + err = core.ParseFlags(cmd, &cfg.Core) + if err != nil { + return err + } + + if nodeType != node.Bridge { + err = header.ParseFlags(cmd, &cfg.Header) + if err != nil { + return err + } + } + + ctx, err = ParseMiscFlags(ctx, cmd) + if err != nil { + return err + } + + rpc_cfg.ParseFlags(cmd, &cfg.RPC) + gateway.ParseFlags(cmd, &cfg.Gateway) + state.ParseFlags(cmd, &cfg.State) + + // set config + ctx = WithNodeConfig(ctx, &cfg) + cmd.SetContext(ctx) + return nil +} diff --git a/cmd/celestia/rpc_test.go b/cmd/util_test.go similarity index 97% rename from cmd/celestia/rpc_test.go rename to cmd/util_test.go index 53087646a7..b6e245f3e2 100644 --- a/cmd/celestia/rpc_test.go +++ b/cmd/util_test.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "testing" @@ -69,7 +69,7 @@ func Test_parseNamespaceID(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - got, err := parseV0Namespace(tc.param) + got, err := ParseV0Namespace(tc.param) if tc.wantErr { assert.Error(t, err) return diff --git a/go.mod b/go.mod index bcd7f2aab4..13f218440c 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/BurntSushi/toml v1.3.2 github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b github.com/benbjohnson/clock v1.3.5 - github.com/celestiaorg/celestia-app v1.0.0-rc17 + github.com/celestiaorg/celestia-app v1.0.0-rc18 github.com/celestiaorg/go-ds-badger4 v0.0.0-20230712104058-7ede1c814ac5 github.com/celestiaorg/go-fraud v0.2.0 github.com/celestiaorg/go-header v0.3.1 @@ -56,12 +56,12 @@ require ( github.com/tendermint/tendermint v0.34.28 go.opentelemetry.io/contrib/instrumentation/runtime v0.44.0 go.opentelemetry.io/otel v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.41.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 go.opentelemetry.io/otel/metric v1.19.0 go.opentelemetry.io/otel/sdk v1.19.0 - go.opentelemetry.io/otel/sdk/metric v0.41.0 + go.opentelemetry.io/otel/sdk/metric v1.19.0 go.opentelemetry.io/otel/trace v1.19.0 go.opentelemetry.io/proto/otlp v1.0.0 go.uber.org/fx v1.20.0 @@ -77,7 +77,7 @@ require ( require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/bits-and-blooms/bitset v1.5.0 // indirect - github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.1 // indirect + github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.2 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.10.0 // indirect github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect @@ -116,7 +116,7 @@ require ( github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect - github.com/confio/ics23/go v0.9.0 // indirect + github.com/confio/ics23/go v0.9.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -145,7 +145,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect - github.com/ethereum/go-ethereum v1.13.1 // indirect + github.com/ethereum/go-ethereum v1.13.2 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -316,7 +316,7 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect @@ -343,10 +343,10 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.18.0-sdk-v0.46.14 + github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.18.1-sdk-v0.46.14 github.com/filecoin-project/dagstore => github.com/celestiaorg/dagstore v0.0.0-20230824094345-537c012aa403 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // broken goleveldb needs to be replaced for the cosmos-sdk and celestia-app github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.27.0-tm-v0.34.28 + github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.29.0-tm-v0.34.29 ) diff --git a/go.sum b/go.sum index 236dd50f4f..7c1334a343 100644 --- a/go.sum +++ b/go.sum @@ -358,12 +358,12 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-app v1.0.0-rc17 h1:ak9OIViNJCfDFklopPgxnjRqUx5oKPcctpGpmwmqJy4= -github.com/celestiaorg/celestia-app v1.0.0-rc17/go.mod h1:gDKOpD8xCWHw/PUdcTc0WFYf52Mq0etOFZ1oTkBlFkQ= -github.com/celestiaorg/celestia-core v1.27.0-tm-v0.34.28 h1:BE7JFZ1SYpwM9OfL9cPcjlO5xjIbDPgdFkJNouyl6jA= -github.com/celestiaorg/celestia-core v1.27.0-tm-v0.34.28/go.mod h1:1GT0RfdNqOXvyR3Hq4ROcNBknQNz9E6K5l3Cla9eFFk= -github.com/celestiaorg/cosmos-sdk v1.18.0-sdk-v0.46.14 h1:dDfoQJOlVNj4HufJ1lBLTo2k3/L/255MIiKmEQziDmw= -github.com/celestiaorg/cosmos-sdk v1.18.0-sdk-v0.46.14/go.mod h1:kkdiHo/zG6ar80730+bG1owdMAQXrGp4utFu7mbfADo= +github.com/celestiaorg/celestia-app v1.0.0-rc18 h1:d2+KYPr4ri10aOtnXih3hOUd6ap94c/Hv46JFzpWzy0= +github.com/celestiaorg/celestia-app v1.0.0-rc18/go.mod h1:Q375ijriqMv8PjKmMujNs2WzMAsgxjpbeUoQt+AZre0= +github.com/celestiaorg/celestia-core v1.29.0-tm-v0.34.29 h1:Fd7ymPUzExPGNl2gZw4i5S74arMw+iDHLE78M/cCxl4= +github.com/celestiaorg/celestia-core v1.29.0-tm-v0.34.29/go.mod h1:xrICN0PBhp3AdTaZ8q4wS5Jvi32V02HNjaC2EsWiEKk= +github.com/celestiaorg/cosmos-sdk v1.18.1-sdk-v0.46.14 h1:c4cMVLU2bGTesZW1ZVgeoCB++gOOJTF3OvBsqBvo6n0= +github.com/celestiaorg/cosmos-sdk v1.18.1-sdk-v0.46.14/go.mod h1:D5y5Exw0bJkcDv9fvYDiZfZrDV1b6+xsFyiungxrCsU= github.com/celestiaorg/dagstore v0.0.0-20230824094345-537c012aa403 h1:Lj73O3S+KJx5/hgZ+IeOLEIoLsAveJN/7/ZtQQtPSVw= github.com/celestiaorg/dagstore v0.0.0-20230824094345-537c012aa403/go.mod h1:cCGM1UoMvyTk8k62mkc+ReVu8iHBCtSBAAL4wYU7KEI= github.com/celestiaorg/go-ds-badger4 v0.0.0-20230712104058-7ede1c814ac5 h1:MJgXvhJP1Au8rXTvMMlBXodu9jplEK1DxiLtMnEphOs= @@ -378,8 +378,8 @@ github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4 h1:CJdIpo8n github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4/go.mod h1:fzuHnhzj1pUygGz+1ZkB3uQbEUL4htqCGJ4Qs2LwMZA= github.com/celestiaorg/nmt v0.20.0 h1:9i7ultZ8Wv5ytt8ZRaxKQ5KOOMo4A2K2T/aPGjIlSas= github.com/celestiaorg/nmt v0.20.0/go.mod h1:Oz15Ub6YPez9uJV0heoU4WpFctxazuIhKyUtaYNio7E= -github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.1 h1:xOBMoRYSh/hnsEW7OLI3bjSJXKlqILfZehjPEK/+3oI= -github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.1/go.mod h1:NziNBP12grIi+DH3TqIKUUPM2T6Hl9BTyxiK3+p8yeA= +github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.2 h1:Q8nr5SAtDW5gocrBwqwDJcSS/JedqU58WwQA2SP+nXw= +github.com/celestiaorg/quantum-gravity-bridge/v2 v2.1.2/go.mod h1:s/LzLUw0WeYPJ6qdk4q46jKLOq7rc9Z5Mdrxtfpcigw= github.com/celestiaorg/rsmt2d v0.11.0 h1:lcto/637WyTEZR3dLRoNvyuExfnUbxvdvKi3qz/2V4k= github.com/celestiaorg/rsmt2d v0.11.0/go.mod h1:6Y580I3gVr0+OVFfW6m2JTwnCCmvW3WfbwSLfuT+HCA= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -446,8 +446,8 @@ github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZ github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= -github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= -github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +github.com/confio/ics23/go v0.9.1 h1:3MV46eeWwO3xCauKyAtuAdJYMyPnnchW4iLr2bTw6/U= +github.com/confio/ics23/go v0.9.1/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= @@ -606,8 +606,8 @@ github.com/etclabscore/go-openrpc-reflect v0.0.37/go.mod h1:0404Ky3igAasAOpyj1eE github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/ethereum/go-ethereum v1.13.1 h1:UF2FaUKPIy5jeZk3X06ait3y2Q4wI+vJ1l7+UARp+60= -github.com/ethereum/go-ethereum v1.13.1/go.mod h1:xHQKzwkHSl0gnSjZK1mWa06XEdm9685AHqhRknOzqGQ= +github.com/ethereum/go-ethereum v1.13.2 h1:g9mCpfPWqCA1OL4e6C98PeVttb0HadfBRuKTGvMnOvw= +github.com/ethereum/go-ethereum v1.13.2/go.mod h1:gkQ5Ygi64ZBh9M/4iXY1R8WqoNCx1Ey0CkYn2BD4/fw= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -2384,14 +2384,14 @@ go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+n go.opentelemetry.io/otel v1.13.0/go.mod h1:FH3RtdZCzRkJYFTCsAKDy9l/XYjMdNv6QrkFFB8DvVg= go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 h1:k0k7hFNDd8K4iOMJXj7s8sHaC4mhTlAeppRmZXLgZ6k= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.41.0 h1:iV3BOgW4fry1Riw9dwypigqlIYWXvSRVT2RJmblzo40= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.41.0/go.mod h1:7PGzqlKrxIRmbj5tlNW0nTkYZ5fHXDgk6Fy8/KjR0CI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 h1:6pu8ttx76BxHf+xz/H77AUZkPF3cwWzXqAUsXhVKI18= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0/go.mod h1:IOmXxPrxoxFMXdNy7lfDmE8MzE61YPcurbUm0SMjerI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 h1:2PunuO5SbkN5MhCbuHCd3tC6qrcaj+uDAkX/qBU5BAs= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1/go.mod h1:q8+Tha+5LThjeSU8BW93uUC5w5/+DnYHMKBMpRCsui0= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= @@ -2401,8 +2401,8 @@ go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk/metric v0.41.0 h1:c3sAt9/pQ5fSIUfl0gPtClV3HhE18DCVzByD33R/zsk= -go.opentelemetry.io/otel/sdk/metric v0.41.0/go.mod h1:PmOmSt+iOklKtIg5O4Vz9H/ttcRFSNTgii+E1KGyn1w= +go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= +go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= diff --git a/cmd/celestia/blob.go b/nodebuilder/blob/cmd/blob.go similarity index 65% rename from cmd/celestia/blob.go rename to nodebuilder/blob/cmd/blob.go index 6d397525f5..f3510edfe1 100644 --- a/cmd/celestia/blob.go +++ b/nodebuilder/blob/cmd/blob.go @@ -1,16 +1,15 @@ -package main +package cmd import ( "encoding/base64" - "encoding/json" "fmt" - "os" "reflect" "strconv" "github.com/spf13/cobra" "github.com/celestiaorg/celestia-node/blob" + cmdnode "github.com/celestiaorg/celestia-node/cmd" "github.com/celestiaorg/celestia-node/share" ) @@ -22,7 +21,7 @@ var ( ) func init() { - blobCmd.AddCommand(getCmd, getAllCmd, submitCmd, getProofCmd) + Cmd.AddCommand(getCmd, getAllCmd, submitCmd, getProofCmd) getCmd.PersistentFlags().BoolVar( &base64Flag, @@ -30,6 +29,7 @@ func init() { false, "printed blob's data a base64 string", ) + getAllCmd.PersistentFlags().BoolVar( &base64Flag, "base64", @@ -41,39 +41,45 @@ func init() { &fee, "fee", -1, - "specifies fee for blob submission", + "specifies fee (in utia) for blob submission.\n"+ + "Fee will be automatically calculated if negative value is passed [optional]", ) submitCmd.PersistentFlags().Uint64Var( &gasLimit, "gas.limit", 0, - "specifies max gas for the blob submission", + "sets the amount of gas that is consumed during blob submission [optional]", ) + + // unset the default value to avoid users confusion + submitCmd.PersistentFlags().Lookup("fee").DefValue = "0" } -var blobCmd = &cobra.Command{ - Use: "blob [command]", - Short: "Allows to interact with the Blob Service via JSON-RPC", - Args: cobra.NoArgs, +var Cmd = &cobra.Command{ + Use: "blob [command]", + Short: "Allows to interact with the Blob Service via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, } var getCmd = &cobra.Command{ - Use: "get [height, namespace, commitment]", + Use: "get [height] [namespace] [commitment]", Args: cobra.ExactArgs(3), Short: "Returns the blob for the given namespace by commitment at a particular height.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := rpcClient(cmd.Context()) + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) if err != nil { return err } + defer client.Close() height, err := strconv.ParseUint(args[0], 10, 64) if err != nil { return fmt.Errorf("error parsing a height:%v", err) } - namespace, err := parseV0Namespace(args[1]) + namespace, err := cmdnode.ParseV0Namespace(args[1]) if err != nil { return fmt.Errorf("error parsing a namespace:%v", err) } @@ -85,49 +91,59 @@ var getCmd = &cobra.Command{ blob, err := client.Blob.Get(cmd.Context(), height, namespace, commitment) - printOutput(blob, err) - return nil + formatter := formatData + if base64Flag || err != nil { + formatter = nil + } + return cmdnode.PrintOutput(blob, err, formatter) }, } var getAllCmd = &cobra.Command{ - Use: "get-all [height, namespace]", + Use: "get-all [height] [namespace]", Args: cobra.ExactArgs(2), Short: "Returns all blobs for the given namespace at a particular height.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := rpcClient(cmd.Context()) + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) if err != nil { return err } + defer client.Close() height, err := strconv.ParseUint(args[0], 10, 64) if err != nil { return fmt.Errorf("error parsing a height:%v", err) } - namespace, err := parseV0Namespace(args[1]) + namespace, err := cmdnode.ParseV0Namespace(args[1]) if err != nil { return fmt.Errorf("error parsing a namespace:%v", err) } blobs, err := client.Blob.GetAll(cmd.Context(), height, []share.Namespace{namespace}) - - printOutput(blobs, err) - return nil + formatter := formatData + if base64Flag || err != nil { + formatter = nil + } + return cmdnode.PrintOutput(blobs, err, formatter) }, } var submitCmd = &cobra.Command{ - Use: "submit [namespace, blobData]", - Args: cobra.ExactArgs(2), - Short: "Submit the blob at the given namespace. Note: only one blob is allowed to submit through the RPC.", + Use: "submit [namespace] [blobData]", + Args: cobra.ExactArgs(2), + Short: "Submit the blob at the given namespace.\n" + + "Note:\n" + + "* only one blob is allowed to submit through the RPC.\n" + + "* fee and gas.limit params will be calculated automatically if they are not provided as arguments", RunE: func(cmd *cobra.Command, args []string) error { - client, err := rpcClient(cmd.Context()) + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) if err != nil { return err } + defer client.Close() - namespace, err := parseV0Namespace(args[0]) + namespace, err := cmdnode.ParseV0Namespace(args[0]) if err != nil { return fmt.Errorf("error parsing a namespace:%v", err) } @@ -150,28 +166,27 @@ var submitCmd = &cobra.Command{ Height: height, Commitment: parsedBlob.Commitment, } - - printOutput(response, err) - return nil + return cmdnode.PrintOutput(response, err, nil) }, } var getProofCmd = &cobra.Command{ - Use: "get-proof [height, namespace, commitment]", + Use: "get-proof [height] [namespace] [commitment]", Args: cobra.ExactArgs(3), Short: "Retrieves the blob in the given namespaces at the given height by commitment and returns its Proof.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := rpcClient(cmd.Context()) + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) if err != nil { return err } + defer client.Close() height, err := strconv.ParseUint(args[0], 10, 64) if err != nil { return fmt.Errorf("error parsing a height:%v", err) } - namespace, err := parseV0Namespace(args[1]) + namespace, err := cmdnode.ParseV0Namespace(args[1]) if err != nil { return fmt.Errorf("error parsing a namespace:%v", err) } @@ -182,35 +197,10 @@ var getProofCmd = &cobra.Command{ } proof, err := client.Blob.GetProof(cmd.Context(), height, namespace, commitment) - - printOutput(proof, err) - return nil + return cmdnode.PrintOutput(proof, err, nil) }, } -func printOutput(data interface{}, err error) { - if err != nil { - data = err - } - - if !base64Flag && err == nil { - data = formatData(data) - } - - resp := struct { - Result interface{} `json:"result"` - }{ - Result: data, - } - - bytes, err := json.MarshalIndent(resp, "", " ") - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - fmt.Fprintln(os.Stdout, string(bytes)) -} - func formatData(data interface{}) interface{} { type tempBlob struct { Namespace []byte `json:"namespace"` @@ -220,11 +210,7 @@ func formatData(data interface{}) interface{} { } if reflect.TypeOf(data).Kind() == reflect.Slice { - blobs, ok := data.([]*blob.Blob) - if !ok { - return data - } - + blobs := data.([]*blob.Blob) result := make([]tempBlob, len(blobs)) for i, b := range blobs { result[i] = tempBlob{ @@ -237,10 +223,7 @@ func formatData(data interface{}) interface{} { return result } - b, ok := data.(*blob.Blob) - if !ok { - return data - } + b := data.(*blob.Blob) return tempBlob{ Namespace: b.Namespace(), Data: string(b.Data), diff --git a/nodebuilder/das/cmd/das.go b/nodebuilder/das/cmd/das.go new file mode 100644 index 0000000000..7512861ac3 --- /dev/null +++ b/nodebuilder/das/cmd/das.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" +) + +func init() { + Cmd.AddCommand(samplingStatsCmd) +} + +var Cmd = &cobra.Command{ + Use: "das [command]", + Short: "Allows to interact with the Daser via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var samplingStatsCmd = &cobra.Command{ + Use: "sampling-stats", + Short: "Returns the current statistics over the DA sampling process", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + stats, err := client.DAS.SamplingStats(cmd.Context()) + return cmdnode.PrintOutput(stats, err, nil) + }, +} diff --git a/nodebuilder/gateway/config.go b/nodebuilder/gateway/config.go index f85f207ceb..903a27489a 100644 --- a/nodebuilder/gateway/config.go +++ b/nodebuilder/gateway/config.go @@ -8,10 +8,9 @@ import ( ) type Config struct { - Address string - Port string - Enabled bool - deprecatedEndpoints bool + Address string + Port string + Enabled bool } func DefaultConfig() Config { diff --git a/nodebuilder/gateway/constructors.go b/nodebuilder/gateway/constructors.go index c771c12023..c28153b0a5 100644 --- a/nodebuilder/gateway/constructors.go +++ b/nodebuilder/gateway/constructors.go @@ -10,7 +10,6 @@ import ( // Handler constructs a new RPC Handler from the given services. func Handler( - cfg *Config, state state.Module, share share.Module, header header.Module, @@ -18,7 +17,7 @@ func Handler( serv *gateway.Server, ) { handler := gateway.NewHandler(state, share, header, daser) - handler.RegisterEndpoints(serv, cfg.deprecatedEndpoints) + handler.RegisterEndpoints(serv) handler.RegisterMiddleware(serv) } diff --git a/nodebuilder/gateway/flags.go b/nodebuilder/gateway/flags.go index 4d72a278e5..cd13e47162 100644 --- a/nodebuilder/gateway/flags.go +++ b/nodebuilder/gateway/flags.go @@ -6,10 +6,9 @@ import ( ) var ( - enabledFlag = "gateway" - addrFlag = "gateway.addr" - portFlag = "gateway.port" - deprecatedEndpoints = "gateway.deprecated-endpoints" + enabledFlag = "gateway" + addrFlag = "gateway.addr" + portFlag = "gateway.port" ) // Flags gives a set of hardcoded node/gateway package flags. @@ -21,11 +20,6 @@ func Flags() *flag.FlagSet { false, "Enables the REST gateway", ) - flags.Bool( - deprecatedEndpoints, - false, - "Enables deprecated endpoints on the gateway. These will be removed in the next release.", - ) flags.String( addrFlag, "", @@ -46,10 +40,6 @@ func ParseFlags(cmd *cobra.Command, cfg *Config) { if cmd.Flags().Changed(enabledFlag) && err == nil { cfg.Enabled = enabled } - deprecatedEndpointsEnabled, err := cmd.Flags().GetBool(deprecatedEndpoints) - if cmd.Flags().Changed(deprecatedEndpoints) && err == nil { - cfg.deprecatedEndpoints = deprecatedEndpointsEnabled - } addr, port := cmd.Flag(addrFlag), cmd.Flag(portFlag) if !cfg.Enabled && (addr.Changed || port.Changed) { log.Warn("custom address or port provided without enabling gateway, setting config values") diff --git a/nodebuilder/gateway/module.go b/nodebuilder/gateway/module.go index b727f4c04d..4cdf325dc0 100644 --- a/nodebuilder/gateway/module.go +++ b/nodebuilder/gateway/module.go @@ -48,13 +48,12 @@ func ConstructModule(tp node.Type, cfg *Config) fx.Option { "gateway", baseComponents, fx.Invoke(func( - cfg *Config, state stateServ.Module, share shareServ.Module, header headerServ.Module, serv *gateway.Server, ) { - Handler(cfg, state, share, header, nil, serv) + Handler(state, share, header, nil, serv) }), ) default: diff --git a/nodebuilder/header/cmd/header.go b/nodebuilder/header/cmd/header.go new file mode 100644 index 0000000000..b3bba1eb32 --- /dev/null +++ b/nodebuilder/header/cmd/header.go @@ -0,0 +1,117 @@ +package cmd + +import ( + "encoding/hex" + "fmt" + "strconv" + + "github.com/spf13/cobra" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" +) + +func init() { + Cmd.AddCommand( + localHeadCmd, + networkHeadCmd, + getByHashCmd, + getByHeightCmd, + syncStateCmd, + ) +} + +var Cmd = &cobra.Command{ + Use: "header [command]", + Short: "Allows interaction with the Header Module via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var localHeadCmd = &cobra.Command{ + Use: "local-head", + Short: "Returns the ExtendedHeader from the chain head.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + header, err := client.Header.LocalHead(cmd.Context()) + return cmdnode.PrintOutput(header, err, nil) + }, +} + +var networkHeadCmd = &cobra.Command{ + Use: "network-head", + Short: "Provides the Syncer's view of the current network head.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + header, err := client.Header.NetworkHead(cmd.Context()) + return cmdnode.PrintOutput(header, err, nil) + }, +} + +var getByHashCmd = &cobra.Command{ + Use: "get-by-hash", + Short: "Returns the header of the given hash from the node's header store.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + hash, err := hex.DecodeString(args[0]) + if err != nil { + return fmt.Errorf("error decoding a hash: expected a hex encoded string:%v", err) + } + header, err := client.Header.GetByHash(cmd.Context(), hash) + return cmdnode.PrintOutput(header, err, nil) + }, +} + +var getByHeightCmd = &cobra.Command{ + Use: "get-by-height", + Short: "Returns the ExtendedHeader at the given height if it is currently available.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + height, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a height:%v", err) + } + + header, err := client.Header.GetByHeight(cmd.Context(), height) + return cmdnode.PrintOutput(header, err, nil) + }, +} + +var syncStateCmd = &cobra.Command{ + Use: "sync-state", + Short: "Returns the current state of the header Syncer.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + header, err := client.Header.SyncState(cmd.Context()) + return cmdnode.PrintOutput(header, err, nil) + }, +} diff --git a/nodebuilder/node/cmd/node.go b/nodebuilder/node/cmd/node.go new file mode 100644 index 0000000000..a65727fb03 --- /dev/null +++ b/nodebuilder/node/cmd/node.go @@ -0,0 +1,105 @@ +package cmd + +import ( + "errors" + "strings" + + "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/spf13/cobra" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" +) + +func init() { + Cmd.AddCommand(nodeInfoCmd, logCmd, verifyCmd, authCmd) +} + +var Cmd = &cobra.Command{ + Use: "node [command]", + Short: "Allows administrating running node.", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var nodeInfoCmd = &cobra.Command{ + Use: "info", + Args: cobra.NoArgs, + Short: "Returns administrative information about the node.", + RunE: func(c *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(c.Context()) + if err != nil { + return err + } + defer client.Close() + + info, err := client.Node.Info(c.Context()) + return cmdnode.PrintOutput(info, err, nil) + }, +} + +var logCmd = &cobra.Command{ + Use: "log-level", + Args: cobra.MinimumNArgs(1), + Short: "Sets log level for module.", + Long: "Allows to set log level for module to in format :" + + "`DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL and their lower-case forms`.\n" + + "To set all modules to a particular level `*:` should be passed", + RunE: func(c *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(c.Context()) + if err != nil { + return err + } + defer client.Close() + + for _, ll := range args { + params := strings.Split(ll, ":") + if len(params) != 2 { + return errors.New("cmd: log-level arg must be in form :," + + "e.g. pubsub:debug") + } + + if err := client.Node.LogLevelSet(c.Context(), params[0], params[1]); err != nil { + return err + } + } + return nil + }, +} + +var verifyCmd = &cobra.Command{ + Use: "permissions", + Args: cobra.ExactArgs(1), + Short: "Returns the permissions assigned to the given token.", + + RunE: func(c *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(c.Context()) + if err != nil { + return err + } + defer client.Close() + + perms, err := client.Node.AuthVerify(c.Context(), args[0]) + return cmdnode.PrintOutput(perms, err, nil) + }, +} + +var authCmd = &cobra.Command{ + Use: "set-permissions", + Args: cobra.MinimumNArgs(1), + Short: "Signs and returns a new token with the given permissions.", + RunE: func(c *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(c.Context()) + if err != nil { + return err + } + defer client.Close() + + perms := make([]auth.Permission, len(args)) + for i, p := range args { + perms[i] = (auth.Permission)(p) + } + + result, err := client.Node.AuthNew(c.Context(), perms) + return cmdnode.PrintOutput(result, err, nil) + }, +} diff --git a/nodebuilder/p2p/cmd/p2p.go b/nodebuilder/p2p/cmd/p2p.go new file mode 100644 index 0000000000..5951595fa4 --- /dev/null +++ b/nodebuilder/p2p/cmd/p2p.go @@ -0,0 +1,576 @@ +package cmd + +import ( + "github.com/libp2p/go-libp2p/core/metrics" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/protocol" + ma2 "github.com/multiformats/go-multiaddr" + "github.com/spf13/cobra" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" +) + +type peerInfo struct { + ID string `json:"id"` + PeerAddr []string `json:"peer_addr"` +} + +func init() { + Cmd.AddCommand(infoCmd, + peersCmd, + peerInfoCmd, + connectCmd, + closePeerCmd, + connectednessCmd, + natStatusCmd, + blockPeerCmd, + unblockPeerCmd, + blockedPeersCmd, + protectCmd, + unprotectCmd, + protectedCmd, + bandwidthStatsCmd, + peerBandwidthCmd, + bandwidthForProtocolCmd, + pubsubPeersCmd, + ) +} + +var Cmd = &cobra.Command{ + Use: "p2p [command]", + Short: "Allows interaction with the P2P Module via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var infoCmd = &cobra.Command{ + Use: "info", + Short: "Gets the node's peer info (peer id and multiaddresses)", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + info, err := client.P2P.Info(cmd.Context()) + + formatter := func(data interface{}) interface{} { + peerAdd := data.(peer.AddrInfo) + ma := make([]string, len(info.Addrs)) + for i := range peerAdd.Addrs { + ma[i] = peerAdd.Addrs[i].String() + } + + return peerInfo{ + ID: peerAdd.ID.String(), + PeerAddr: ma, + } + } + return cmdnode.PrintOutput(info, err, formatter) + }, +} + +var peersCmd = &cobra.Command{ + Use: "peers", + Short: "Lists the peers we are connected to", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + result, err := client.P2P.Peers(cmd.Context()) + peers := make([]string, len(result)) + for i, peer := range result { + peers[i] = peer.String() + } + + formatter := func(data interface{}) interface{} { + conPeers := data.([]string) + return struct { + Peers []string `json:"peers"` + }{ + Peers: conPeers, + } + } + return cmdnode.PrintOutput(peers, err, formatter) + }, +} + +var peerInfoCmd = &cobra.Command{ + Use: "peer-info [param]", + Short: "Gets PeerInfo for a given peer", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + info, err := client.P2P.PeerInfo(cmd.Context(), pid) + formatter := func(data interface{}) interface{} { + peerAdd := data.(peer.AddrInfo) + ma := make([]string, len(info.Addrs)) + for i := range peerAdd.Addrs { + ma[i] = peerAdd.Addrs[i].String() + } + + return peerInfo{ + ID: peerAdd.ID.String(), + PeerAddr: ma, + } + } + return cmdnode.PrintOutput(info, err, formatter) + }, +} + +var connectCmd = &cobra.Command{ + Use: "connect [peer.ID, address]", + Short: "Establishes a connection with the given peer", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + ma, err := ma2.NewMultiaddr(args[1]) + if err != nil { + return err + } + + peerInfo := peer.AddrInfo{ + ID: pid, + Addrs: []ma2.Multiaddr{ma}, + } + + err = client.P2P.Connect(cmd.Context(), peerInfo) + if err != nil { + return cmdnode.PrintOutput(nil, err, nil) + } + return connectednessCmd.RunE(cmd, args) + }, +} + +var closePeerCmd = &cobra.Command{ + Use: "close-peer [peer.ID]", + Short: "Closes the connection with the given peer", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + err = client.P2P.ClosePeer(cmd.Context(), pid) + if err != nil { + return cmdnode.PrintOutput(nil, err, nil) + } + return connectednessCmd.RunE(cmd, args) + }, +} + +var connectednessCmd = &cobra.Command{ + Use: "connectedness [peer.ID]", + Short: "Checks the connection state between current and given peers", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + con, err := client.P2P.Connectedness(cmd.Context(), pid) + + formatter := func(data interface{}) interface{} { + conn := data.(network.Connectedness) + return struct { + ConnectionState string `json:"connection_state"` + }{ + ConnectionState: conn.String(), + } + } + return cmdnode.PrintOutput(con, err, formatter) + }, +} + +var natStatusCmd = &cobra.Command{ + Use: "nat-status", + Short: "Gets the currrent NAT status", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + r, err := client.P2P.NATStatus(cmd.Context()) + + formatter := func(data interface{}) interface{} { + rr := data.(network.Reachability) + return struct { + Reachability string `json:"reachability"` + }{ + Reachability: rr.String(), + } + } + return cmdnode.PrintOutput(r, err, formatter) + }, +} + +var blockPeerCmd = &cobra.Command{ + Use: "block-peer [peer.ID]", + Short: "Blocks the given peer", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + err = client.P2P.BlockPeer(cmd.Context(), pid) + + formatter := func(data interface{}) interface{} { + err, ok := data.(error) + blocked := false + if !ok { + blocked = true + } + return struct { + Blocked bool `json:"blocked"` + Peer string `json:"peer"` + Reason error `json:"reason,omitempty"` + }{ + Blocked: blocked, + Peer: args[0], + Reason: err, + } + } + return cmdnode.PrintOutput(err, nil, formatter) + }, +} + +var unblockPeerCmd = &cobra.Command{ + Use: "unblock-peer [peer.ID]", + Short: "Unblocks the given peer", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + err = client.P2P.UnblockPeer(cmd.Context(), pid) + + formatter := func(data interface{}) interface{} { + err, ok := data.(error) + unblocked := false + if !ok { + unblocked = true + } + + return struct { + Unblocked bool `json:"unblocked"` + Peer string `json:"peer"` + Reason error `json:"reason,omitempty"` + }{ + Unblocked: unblocked, + Peer: args[0], + Reason: err, + } + } + return cmdnode.PrintOutput(err, nil, formatter) + }, +} + +var blockedPeersCmd = &cobra.Command{ + Use: "blocked-peers", + Short: "Lists the node's blocked peers", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + list, err := client.P2P.ListBlockedPeers(cmd.Context()) + + pids := make([]string, len(list)) + for i, peer := range list { + pids[i] = peer.String() + } + + formatter := func(data interface{}) interface{} { + peers := data.([]string) + return struct { + Peers []string `json:"peers"` + }{ + Peers: peers, + } + } + return cmdnode.PrintOutput(pids, err, formatter) + }, +} + +var protectCmd = &cobra.Command{ + Use: "protect [peer.ID, tag]", + Short: "Protects the given peer from being pruned by the given tag", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + err = client.P2P.Protect(cmd.Context(), pid, args[1]) + + formatter := func(data interface{}) interface{} { + err, ok := data.(error) + protected := false + if !ok { + protected = true + } + return struct { + Protected bool `json:"protected"` + Peer string `json:"peer"` + Reason error `json:"reason,omitempty"` + }{ + Protected: protected, + Peer: args[0], + Reason: err, + } + } + return cmdnode.PrintOutput(err, nil, formatter) + }, +} + +var unprotectCmd = &cobra.Command{ + Use: "unprotect [peer.ID, tag]", + Short: "Removes protection from the given peer.", + Long: "Removes a protection that may have been placed on a peer, under the specified tag." + + "The return value indicates whether the peer continues to be protected after this call, by way of a different tag", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + _, err = client.P2P.Unprotect(cmd.Context(), pid, args[1]) + + formatter := func(data interface{}) interface{} { + err, ok := data.(error) + unprotected := false + if !ok { + unprotected = true + } + return struct { + Unprotected bool `json:"unprotected"` + Peer string `json:"peer"` + Reason error `json:"reason,omitempty"` + }{ + Unprotected: unprotected, + Peer: args[0], + Reason: err, + } + } + return cmdnode.PrintOutput(err, nil, formatter) + }, +} + +var protectedCmd = &cobra.Command{ + Use: "protected [peer.ID, tag]", + Short: "Ensures that a given peer is protected under a specific tag", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + result, err := client.P2P.IsProtected(cmd.Context(), pid, args[1]) + return cmdnode.PrintOutput(result, err, nil) + }, +} + +type bandwidthStats struct { + TotalIn int64 `json:"total_in"` + TotalOut int64 `json:"total_out"` + RateIn float64 `json:"rate_in"` + RateOut float64 `json:"rate_out"` +} + +var bandwidthStatsCmd = &cobra.Command{ + Use: "bandwidth-stats", + Short: "Provides metrics for current peer.", + Long: "Get stats struct with bandwidth metrics for all data sent/" + + "received by the local peer, regardless of protocol or remote peer IDs", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + result, err := client.P2P.BandwidthStats(cmd.Context()) + + formatter := func(data interface{}) interface{} { + stats := data.(metrics.Stats) + return bandwidthStats{ + TotalIn: stats.TotalIn, + TotalOut: stats.TotalOut, + RateIn: stats.RateIn, + RateOut: stats.RateOut, + } + } + return cmdnode.PrintOutput(result, err, formatter) + }, +} + +var peerBandwidthCmd = &cobra.Command{ + Use: "peer-bandwidth [peer.ID]", + Short: "Gets stats struct with bandwidth metrics associated with the given peer.ID", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + pid, err := peer.Decode(args[0]) + if err != nil { + return err + } + + result, err := client.P2P.BandwidthForPeer(cmd.Context(), pid) + + formatter := func(data interface{}) interface{} { + stats := data.(metrics.Stats) + return bandwidthStats{ + TotalIn: stats.TotalIn, + TotalOut: stats.TotalOut, + RateIn: stats.RateIn, + RateOut: stats.RateOut, + } + } + return cmdnode.PrintOutput(result, err, formatter) + }, +} + +var bandwidthForProtocolCmd = &cobra.Command{ + Use: "protocol-bandwidth [protocol.ID]", + Short: "Gets stats struct with bandwidth metrics associated with the given protocol.ID", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + result, err := client.P2P.BandwidthForProtocol(cmd.Context(), protocol.ID(args[0])) + + formatter := func(data interface{}) interface{} { + stats := data.(metrics.Stats) + return bandwidthStats{ + TotalIn: stats.TotalIn, + TotalOut: stats.TotalOut, + RateIn: stats.RateIn, + RateOut: stats.RateOut, + } + } + return cmdnode.PrintOutput(result, err, formatter) + }, +} + +var pubsubPeersCmd = &cobra.Command{ + Use: "pubsub-peers [topic]", + Short: "Lists the peers we are connected to in the given topic", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + result, err := client.P2P.PubSubPeers(cmd.Context(), args[0]) + peers := make([]string, len(result)) + + for i, peer := range result { + peers[i] = peer.String() + } + + formatter := func(data interface{}) interface{} { + conPeers := data.([]string) + return struct { + Peers []string `json:"peers"` + }{ + Peers: conPeers, + } + } + return cmdnode.PrintOutput(peers, err, formatter) + }, +} diff --git a/nodebuilder/share/cmd/share.go b/nodebuilder/share/cmd/share.go new file mode 100644 index 0000000000..fbf3e51db4 --- /dev/null +++ b/nodebuilder/share/cmd/share.go @@ -0,0 +1,209 @@ +package cmd + +import ( + "encoding/hex" + "encoding/json" + "strconv" + + "github.com/spf13/cobra" + + "github.com/celestiaorg/celestia-app/pkg/da" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" + "github.com/celestiaorg/celestia-node/share" +) + +func init() { + Cmd.AddCommand( + sharesAvailableCmd, + probabilityOfAvailabilityCmd, + getSharesByNamespaceCmd, + getShare, + getEDS, + ) +} + +var Cmd = &cobra.Command{ + Use: "share [command]", + Short: "Allows interaction with the Share Module via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var sharesAvailableCmd = &cobra.Command{ + Use: "available", + Short: "Subjectively validates if Shares committed to the given Root are available on the Network.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + raw, err := parseJSON(args[0]) + if err != nil { + return err + } + + root := da.MinDataAvailabilityHeader() + err = json.Unmarshal(raw, &root) + if err != nil { + return err + } + + err = client.Share.SharesAvailable(cmd.Context(), &root) + formatter := func(data interface{}) interface{} { + err, ok := data.(error) + available := false + if !ok { + available = true + } + return struct { + Available bool `json:"available"` + Hash []byte `json:"dah_hash"` + Reason error `json:"reason,omitempty"` + }{ + Available: available, + Hash: []byte(args[0]), + Reason: err, + } + } + return cmdnode.PrintOutput(err, nil, formatter) + }, +} + +var probabilityOfAvailabilityCmd = &cobra.Command{ + Use: "availability", + Short: "Calculates the probability of the data square being available based on the number of samples collected.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + prob := client.Share.ProbabilityOfAvailability(cmd.Context()) + return cmdnode.PrintOutput(prob, nil, nil) + }, +} + +var getSharesByNamespaceCmd = &cobra.Command{ + Use: "get-by-namespace [dah, namespace]", + Short: "Gets all shares from an EDS within the given namespace.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + raw, err := parseJSON(args[0]) + if err != nil { + return err + } + + root := da.MinDataAvailabilityHeader() + err = json.Unmarshal(raw, &root) + if err != nil { + return err + } + + ns, err := cmdnode.ParseV0Namespace(args[1]) + if err != nil { + return err + } + + shares, err := client.Share.GetSharesByNamespace(cmd.Context(), &root, ns) + return cmdnode.PrintOutput(shares, err, nil) + }, +} + +var getShare = &cobra.Command{ + Use: "get-share [dah, row, col]", + Short: "Gets a Share by coordinates in EDS.", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + raw, err := parseJSON(args[0]) + if err != nil { + return err + } + + root := da.MinDataAvailabilityHeader() + err = json.Unmarshal(raw, &root) + if err != nil { + return err + } + + row, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return err + } + + col, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return err + } + + s, err := client.Share.GetShare(cmd.Context(), &root, int(row), int(col)) + + formatter := func(data interface{}) interface{} { + sh, ok := data.(share.Share) + if !ok { + return data + } + + ns := hex.EncodeToString(share.GetNamespace(sh)) + + return struct { + Namespace string `json:"namespace"` + Data []byte `json:"data"` + }{ + Namespace: ns, + Data: share.GetData(sh), + } + } + return cmdnode.PrintOutput(s, err, formatter) + }, +} + +var getEDS = &cobra.Command{ + Use: "get-eds [dah]", + Short: "Gets the full EDS identified by the given root", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + raw, err := parseJSON(args[0]) + if err != nil { + return err + } + + root := da.MinDataAvailabilityHeader() + err = json.Unmarshal(raw, &root) + if err != nil { + return err + } + + shares, err := client.Share.GetEDS(cmd.Context(), &root) + return cmdnode.PrintOutput(shares, err, nil) + }, +} + +func parseJSON(param string) (json.RawMessage, error) { + var raw json.RawMessage + err := json.Unmarshal([]byte(param), &raw) + return raw, err +} diff --git a/nodebuilder/state/cmd/state.go b/nodebuilder/state/cmd/state.go new file mode 100644 index 0000000000..d35c4a1b4f --- /dev/null +++ b/nodebuilder/state/cmd/state.go @@ -0,0 +1,412 @@ +package cmd + +import ( + "encoding/hex" + "fmt" + "strconv" + + "cosmossdk.io/math" + "github.com/spf13/cobra" + + cmdnode "github.com/celestiaorg/celestia-node/cmd" + "github.com/celestiaorg/celestia-node/state" +) + +func init() { + Cmd.AddCommand( + accountAddressCmd, + balanceCmd, + balanceForAddressCmd, + transferCmd, + submitTxCmd, + cancelUnbondingDelegationCmd, + beginRedelegateCmd, + undelegateCmd, + delegateCmd, + queryDelegationCmd, + queryUnbondingCmd, + queryRedelegationCmd, + ) +} + +var Cmd = &cobra.Command{ + Use: "state [command]", + Short: "Allows interaction with the State Module via JSON-RPC", + Args: cobra.NoArgs, + PersistentPreRunE: cmdnode.InitClient, +} + +var accountAddressCmd = &cobra.Command{ + Use: "account-address", + Short: "Retrieves the address of the node's account/signer.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + address, err := client.State.AccountAddress(cmd.Context()) + return cmdnode.PrintOutput(address, err, nil) + }, +} + +var balanceCmd = &cobra.Command{ + Use: "balance", + Short: "Retrieves the Celestia coin balance for the node's account/signer and verifies it against " + + "the corresponding block's AppHash.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + balance, err := client.State.Balance(cmd.Context()) + return cmdnode.PrintOutput(balance, err, nil) + }, +} + +var balanceForAddressCmd = &cobra.Command{ + Use: "balance-for-address [address]", + Short: "Retrieves the Celestia coin balance for the given address and verifies the returned balance against " + + "the corresponding block's AppHash.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + balance, err := client.State.BalanceForAddress(cmd.Context(), addr) + return cmdnode.PrintOutput(balance, err, nil) + }, +} + +var transferCmd = &cobra.Command{ + Use: "transfer [address] [amount] [fee] [gasLimit]", + Short: "Sends the given amount of coins from default wallet of the node to the given account address.", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + amount, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing an amount:%v", err) + } + fee, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + gasLimit, err := strconv.ParseUint(args[3], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a gas limit:%v", err) + } + + txResponse, err := client.State.Transfer( + cmd.Context(), + addr.Address.(state.AccAddress), + math.NewInt(amount), + math.NewInt(fee), gasLimit, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var submitTxCmd = &cobra.Command{ + Use: "submit-tx [tx]", + Short: "Submits the given transaction/message to the Celestia network and blocks until the tx is included in a block.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + decoded, err := hex.DecodeString(args[0]) + if err != nil { + return fmt.Errorf("failed to decode tx: %v", err) + } + txResponse, err := client.State.SubmitTx( + cmd.Context(), + decoded, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var cancelUnbondingDelegationCmd = &cobra.Command{ + Use: "cancel-unbonding-delegation [address] [amount] [height] [fee] [gasLimit]", + Short: "Cancels a user's pending undelegation from a validator.", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + amount, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing an amount:%v", err) + } + + height, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + + fee, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + + gasLimit, err := strconv.ParseUint(args[4], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a gas limit:%v", err) + } + + txResponse, err := client.State.CancelUnbondingDelegation( + cmd.Context(), + addr.Address.(state.ValAddress), + math.NewInt(amount), + math.NewInt(height), + math.NewInt(fee), + gasLimit, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var beginRedelegateCmd = &cobra.Command{ + Use: "begin-redelegate [srcAddress] [dstAddress] [amount] [fee] [gasLimit]", + Short: "Sends a user's delegated tokens to a new validator for redelegation", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + srcAddr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + dstAddr, err := parseAddressFromString(args[1]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + amount, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error parsing an amount:%v", err) + } + + fee, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + gasLimit, err := strconv.ParseUint(args[4], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a gas limit:%v", err) + } + + txResponse, err := client.State.BeginRedelegate( + cmd.Context(), + srcAddr.Address.(state.ValAddress), + dstAddr.Address.(state.ValAddress), + math.NewInt(amount), + math.NewInt(fee), + gasLimit, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var undelegateCmd = &cobra.Command{ + Use: "undelegate [valAddress] [amount] [fee] [gasLimit]", + Short: "Undelegates a user's delegated tokens, unbonding them from the current validator.", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + amount, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing an amount:%v", err) + } + fee, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + gasLimit, err := strconv.ParseUint(args[3], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a gas limit:%v", err) + } + + txResponse, err := client.State.Undelegate( + cmd.Context(), + addr.Address.(state.ValAddress), + math.NewInt(amount), + math.NewInt(fee), + gasLimit, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var delegateCmd = &cobra.Command{ + Use: "delegate [valAddress] [amount] [fee] [gasLimit]", + Short: "Sends a user's liquid tokens to a validator for delegation.", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + amount, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing an amount:%v", err) + } + + fee, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a fee:%v", err) + } + + gasLimit, err := strconv.ParseUint(args[3], 10, 64) + if err != nil { + return fmt.Errorf("error parsing a gas limit:%v", err) + } + + txResponse, err := client.State.Delegate( + cmd.Context(), + addr.Address.(state.ValAddress), + math.NewInt(amount), + math.NewInt(fee), + gasLimit, + ) + return cmdnode.PrintOutput(txResponse, err, nil) + }, +} + +var queryDelegationCmd = &cobra.Command{ + Use: "get-delegation [valAddress]", + Short: "Retrieves the delegation information between a delegator and a validator.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + balance, err := client.State.QueryDelegation(cmd.Context(), addr.Address.(state.ValAddress)) + return cmdnode.PrintOutput(balance, err, nil) + }, +} + +var queryUnbondingCmd = &cobra.Command{ + Use: "get-unbonding [valAddress]", + Short: "Retrieves the unbonding status between a delegator and a validator.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + addr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing an address:%v", err) + } + + response, err := client.State.QueryUnbonding(cmd.Context(), addr.Address.(state.ValAddress)) + return cmdnode.PrintOutput(response, err, nil) + }, +} + +var queryRedelegationCmd = &cobra.Command{ + Use: "get-redelegations [srcAddress] [dstAddress]", + Short: "Retrieves the status of the redelegations between a delegator and a validator.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := cmdnode.ParseClientFromCtx(cmd.Context()) + if err != nil { + return err + } + defer client.Close() + + srcAddr, err := parseAddressFromString(args[0]) + if err != nil { + return fmt.Errorf("error parsing a src address:%v", err) + } + + dstAddr, err := parseAddressFromString(args[1]) + if err != nil { + return fmt.Errorf("error parsing a dst address:%v", err) + } + + response, err := client.State.QueryRedelegations( + cmd.Context(), + srcAddr.Address.(state.ValAddress), + dstAddr.Address.(state.ValAddress), + ) + return cmdnode.PrintOutput(response, err, nil) + }, +} + +func parseAddressFromString(addrStr string) (state.Address, error) { + var address state.Address + err := address.UnmarshalJSON([]byte(addrStr)) + if err != nil { + return address, err + } + return address, nil +}