Files
zeekayandHanzo Dev 62d5f28c22 A chain address is built in one place
The node moved every chain route from /v1/bc/<alias> to /v1/chain/<alias>
and deleted the old prefix, so every chain call answered 404. The address
was spelled out at 112 sites across 34 files and constants.ChainAliasPrefix
was used at none of them, which is why nothing failed to compile when the
segment moved.

route.Chain(uri, alias) composes it now, and route.Alias reads one back,
replacing three hand-rolled parsers — one of which took the alias by
position in the split path and only worked because the new segment happens
to leave the component count unchanged.

TestChainAddressBuiltOnlyHere walks every .go file in the module and fails
on a chain address in a string literal, so the segment cannot drift back;
prose is free to name a route. TestGuardCatchesEachShape plants each
forbidden shape and requires the guard to find it.

The endpoint box and the eleven-chain table were the same list written
twice; there is one list, rendered once, measured rather than hand-padded.
The generated CLI reference and the faucet manifest compose through the
same function.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-30 15:05:42 -07:00

136 lines
3.3 KiB
Go

// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package rpccmd provides RPC commands for interacting with Lux nodes.
package rpccmd
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/luxfi/cli/pkg/application"
"github.com/luxfi/cli/pkg/route"
"github.com/spf13/cobra"
)
// NewCmd returns the RPC command
func NewCmd(app *application.Lux) *cobra.Command {
pchain := route.Chain("http://localhost:9630", "P")
cmd := &cobra.Command{
Use: "rpc",
Short: "Make RPC calls to Lux node",
Long: fmt.Sprintf(`Make JSON-RPC calls to a Lux node.
Examples:
# Get P-Chain height
lux rpc call --method platform.getHeight --endpoint %[1]s
# Get blockchains with params
lux rpc call --method platform.getBlockchains --params '{}' --endpoint %[1]s
# Create blockchain
lux rpc call --method platform.createBlockchain \
--params '{"vmID":"...", "name":"mychain", "genesis":"..."}' \
--endpoint %[1]s
`, pchain),
RunE: nil,
}
cmd.AddCommand(newCallCmd())
cmd.AddCommand(newTransferCmd(app))
return cmd
}
func newCallCmd() *cobra.Command {
var (
method string
params string
endpoint string
timeout int
)
cmd := &cobra.Command{
Use: "call",
Short: "Make a JSON-RPC call",
Long: "Make a JSON-RPC call to the specified endpoint with the given method and parameters",
RunE: func(_ *cobra.Command, _ []string) error {
// Parse params if provided
var paramsObj interface{}
if params != "" {
if err := json.Unmarshal([]byte(params), &paramsObj); err != nil {
return fmt.Errorf("failed to parse params: %w", err)
}
}
// Create RPC request
request := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"method": method,
}
if paramsObj != nil {
request["params"] = paramsObj
} else {
request["params"] = map[string]interface{}{}
}
// Marshal request
requestBytes, err := json.Marshal(request)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
// Make HTTP request
client := &http.Client{
Timeout: time.Duration(timeout) * time.Second,
}
resp, err := client.Post(
endpoint,
"application/json",
bytes.NewReader(requestBytes),
)
if err != nil {
return fmt.Errorf("failed to make request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
// Read response
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %w", err)
}
// Pretty print JSON response
var result interface{}
if err := json.Unmarshal(body, &result); err != nil {
// If not valid JSON, just print raw
fmt.Println(string(body))
return nil
}
prettyJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
fmt.Println(string(body))
return nil
}
fmt.Println(string(prettyJSON))
return nil
},
}
cmd.Flags().StringVar(&method, "method", "", "RPC method to call (required)")
cmd.Flags().StringVar(&params, "params", "", "JSON params object (optional)")
cmd.Flags().StringVar(&endpoint, "endpoint", route.Chain("http://localhost:9630", "P"), "RPC endpoint URL")
cmd.Flags().IntVar(&timeout, "timeout", 30, "Request timeout in seconds")
_ = cmd.MarkFlagRequired("method")
return cmd
}