Files
zeekay 2b09067132 codec rip: switch wrappers + jsonrpc consumers to luxfi/utils
- sync/statesync (test_trie + trie_segments): codec/wrappers ->
  luxfi/utils/wrappers (canonical Packer + ByteLen/ShortLen/LongLen).
- utils/rpc/handler.go: codec/jsonrpc -> luxfi/utils/json (NewCodec).
- plugin/evm/atomic/vm/api.go + plugin/evm/client/client.go:
  codec/jsonrpc -> luxfi/utils/json for Uint32/Uint64 quoted JSON.

All three subpackages have identical API in luxfi/utils v1.1.5; coreth
no longer imports codec/wrappers or codec/jsonrpc — coreth still
imports codec/linearcodec from plugin/evm/secpfx, which is the SECP fx
that needs the legacy codec.Registry binding to plug into the C-chain
fx system. Documented as structural retain.
2026-06-06 02:56:52 -07:00

175 lines
6.2 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package client
import (
"context"
"errors"
"fmt"
"log/slog"
"github.com/luxfi/formatting"
"github.com/luxfi/address"
"github.com/luxfi/coreth/plugin/evm/atomic"
"github.com/luxfi/coreth/plugin/evm/config"
"github.com/luxfi/ids"
"github.com/luxfi/rpc"
"github.com/luxfi/utils/json"
"github.com/luxfi/vm/api"
)
// Interface compliance
var _ Client = (*client)(nil)
var errInvalidAddr = errors.New("invalid hex address")
// Client interface for interacting with EVM [chain]
type Client interface {
IssueTx(ctx context.Context, txBytes []byte, options ...rpc.Option) (ids.ID, error)
GetAtomicTxStatus(ctx context.Context, txID ids.ID, options ...rpc.Option) (atomic.Status, error)
GetAtomicTx(ctx context.Context, txID ids.ID, options ...rpc.Option) ([]byte, error)
GetAtomicUTXOs(ctx context.Context, addrs []ids.ShortID, sourceChain string, limit uint32, startAddress ids.ShortID, startUTXOID ids.ID, options ...rpc.Option) ([][]byte, ids.ShortID, ids.ID, error)
StartCPUProfiler(ctx context.Context, options ...rpc.Option) error
StopCPUProfiler(ctx context.Context, options ...rpc.Option) error
MemoryProfile(ctx context.Context, options ...rpc.Option) error
LockProfile(ctx context.Context, options ...rpc.Option) error
SetLogLevel(ctx context.Context, level slog.Level, options ...rpc.Option) error
GetVMConfig(ctx context.Context, options ...rpc.Option) (*config.Config, error)
}
// Client implementation for interacting with EVM [chain]
type client struct {
requester rpc.EndpointRequester
adminRequester rpc.EndpointRequester
}
// NewClient returns a Client for interacting with EVM [chain]
func NewClient(uri, chain string) Client {
return &client{
requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/lux", uri, chain)),
adminRequester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain)),
}
}
// NewCChainClient returns a Client for interacting with the C Chain
func NewCChainClient(uri string) Client {
return NewClient(uri, "C")
}
// IssueTx issues a transaction to a node and returns the TxID
func (c *client) IssueTx(ctx context.Context, txBytes []byte, options ...rpc.Option) (ids.ID, error) {
res := &api.JSONTxID{}
txStr, err := formatting.Encode(formatting.Hex, txBytes)
if err != nil {
return res.TxID, fmt.Errorf("problem hex encoding bytes: %w", err)
}
err = c.requester.SendRequest(ctx, "lux.issueTx", &api.FormattedTx{
Tx: txStr,
Encoding: formatting.Hex,
}, res, options...)
return res.TxID, err
}
// GetAtomicTxStatusReply defines the GetAtomicTxStatus replies returned from the API
type GetAtomicTxStatusReply struct {
Status atomic.Status `json:"status"`
BlockHeight *json.Uint64 `json:"blockHeight,omitempty"`
}
// GetAtomicTxStatus returns the status of [txID]
func (c *client) GetAtomicTxStatus(ctx context.Context, txID ids.ID, options ...rpc.Option) (atomic.Status, error) {
res := &GetAtomicTxStatusReply{}
err := c.requester.SendRequest(ctx, "lux.getAtomicTxStatus", &api.JSONTxID{
TxID: txID,
}, res, options...)
return res.Status, err
}
// GetAtomicTx returns the byte representation of [txID]
func (c *client) GetAtomicTx(ctx context.Context, txID ids.ID, options ...rpc.Option) ([]byte, error) {
res := &api.FormattedTx{}
err := c.requester.SendRequest(ctx, "lux.getAtomicTx", &api.GetTxArgs{
TxID: txID,
Encoding: formatting.Hex,
}, res, options...)
if err != nil {
return nil, err
}
return formatting.Decode(formatting.Hex, res.Tx)
}
// GetAtomicUTXOs returns the byte representation of the atomic UTXOs controlled by [addresses]
// from [sourceChain]
func (c *client) GetAtomicUTXOs(ctx context.Context, addrs []ids.ShortID, sourceChain string, limit uint32, startAddress ids.ShortID, startUTXOID ids.ID, options ...rpc.Option) ([][]byte, ids.ShortID, ids.ID, error) {
res := &api.GetUTXOsReply{}
err := c.requester.SendRequest(ctx, "lux.getUTXOs", &api.GetUTXOsArgs{
Addresses: ids.ShortIDsToStrings(addrs),
SourceChain: sourceChain,
Limit: json.Uint32(limit),
StartIndex: api.Index{
Address: startAddress.String(),
UTXO: startUTXOID.String(),
},
Encoding: formatting.Hex,
}, res, options...)
if err != nil {
return nil, ids.ShortID{}, ids.Empty, err
}
utxos := make([][]byte, len(res.UTXOs))
for i, utxo := range res.UTXOs {
utxoBytes, err := formatting.Decode(res.Encoding, utxo)
if err != nil {
return nil, ids.ShortID{}, ids.Empty, err
}
utxos[i] = utxoBytes
}
endAddr, err := address.ParseToID(res.EndIndex.Address)
if err != nil {
return nil, ids.ShortID{}, ids.Empty, err
}
endUTXOID, err := ids.FromString(res.EndIndex.UTXO)
return utxos, endAddr, endUTXOID, err
}
func (c *client) StartCPUProfiler(ctx context.Context, options ...rpc.Option) error {
return c.adminRequester.SendRequest(ctx, "admin.startCPUProfiler", struct{}{}, &api.EmptyReply{}, options...)
}
func (c *client) StopCPUProfiler(ctx context.Context, options ...rpc.Option) error {
return c.adminRequester.SendRequest(ctx, "admin.stopCPUProfiler", struct{}{}, &api.EmptyReply{}, options...)
}
func (c *client) MemoryProfile(ctx context.Context, options ...rpc.Option) error {
return c.adminRequester.SendRequest(ctx, "admin.memoryProfile", struct{}{}, &api.EmptyReply{}, options...)
}
func (c *client) LockProfile(ctx context.Context, options ...rpc.Option) error {
return c.adminRequester.SendRequest(ctx, "admin.lockProfile", struct{}{}, &api.EmptyReply{}, options...)
}
type SetLogLevelArgs struct {
Level string `json:"level"`
}
// SetLogLevel dynamically sets the log level for the C Chain
func (c *client) SetLogLevel(ctx context.Context, level slog.Level, options ...rpc.Option) error {
return c.adminRequester.SendRequest(ctx, "admin.setLogLevel", &SetLogLevelArgs{
Level: level.String(),
}, &api.EmptyReply{}, options...)
}
type ConfigReply struct {
Config *config.Config `json:"config"`
}
// GetVMConfig returns the current config of the VM
func (c *client) GetVMConfig(ctx context.Context, options ...rpc.Option) (*config.Config, error) {
res := &ConfigReply{}
err := c.adminRequester.SendRequest(ctx, "admin.getVMConfig", struct{}{}, res, options...)
return res.Config, err
}