Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions cmd/cartesi-rollups-cli/root/read/epochs/epochs.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,23 @@ cartesi-rollups-cli read epochs echo-dapp 10
cartesi-rollups-cli read epochs echo-dapp

# Read all epochs with filter:
cartesi-rollups-cli read epochs echo-dapp --status OPEN
cartesi-rollups-cli read epochs echo-dapp --status OPEN --status CLOSED

# Read all epochs with pagination:
cartesi-rollups-cli read epochs echo-dapp --limit 10 --offset 10 --descending
`

var (
status string
statuses []string
limit uint64
offset uint64
descending bool
)

func init() {
Cmd.Flags().StringVar(&status, "status", "",
Cmd.Flags().StringArrayVar(&statuses, "status", nil,
"Filter epochs by status (OPEN, CLOSED, INPUTS_PROCESSED, CLAIM_COMPUTED, CLAIM_SUBMITTED, "+
"CLAIM_STAGED, CLAIM_ACCEPTED, CLAIM_REJECTED, CLAIM_FORECLOSED)")
"CLAIM_STAGED, CLAIM_ACCEPTED, CLAIM_REJECTED, CLAIM_FORECLOSED); may be specified multiple times")
Cmd.Flags().Uint64Var(&limit, "limit", 50, //nolint: mnd
"Maximum number of epochs to return")
Cmd.Flags().Uint64Var(&offset, "offset", 0,
Expand Down Expand Up @@ -106,7 +106,8 @@ func run(cmd *cobra.Command, args []string) {

// Add status filter if provided
if cmd.Flags().Changed("status") {
params.Status = &status
epochStatuses := api.StringOrList(statuses)
params.Status = &epochStatuses
}
params.Limit = limit
params.Offset = offset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func run(cmd *cobra.Command, args []string) {

var result json.RawMessage
if len(args) >= 5 {
var params api.GetMatchAdvancedParams
var params api.GetMatchAdvanceParams
params.Application = args[0]
params.EpochIndex, err = config.AsHexString(args[1])
cobra.CheckErr(err)
Expand Down
21 changes: 15 additions & 6 deletions cmd/cartesi-rollups-cli/root/read/outputs/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ cartesi-rollups-cli read outputs echo-dapp 10
# Read all outputs:
cartesi-rollups-cli read outputs echo-dapp

# Read all outputs with filter:
cartesi-rollups-cli read outputs echo-dapp --epoch-index 10 --input-index 10 --output-type 0x237a816f --voucher-address 0x95eac57f9d67c5e0f255d5a19eb5d3fd00cafa73
# Read all outputs with filters:
cartesi-rollups-cli read outputs echo-dapp --epoch-index 10 --input-index 10 --output-type 0x237a816f --output-type 0x10321e8b --executed --voucher-address 0x95eac57f9d67c5e0f255d5a19eb5d3fd00cafa73

# Read all outputs with pagination:
cartesi-rollups-cli read outputs echo-dapp --limit 10 --offset 10 --descending
Expand All @@ -49,7 +49,8 @@ cartesi-rollups-cli read outputs echo-dapp --limit 10 --offset 10 --descending
var (
epochIndex string
inputIndex string
outputType string
outputTypes []string
executed bool
voucherAddress string
limit uint64
offset uint64
Expand All @@ -61,8 +62,10 @@ func init() {
"Filter outputs by epoch index (decimal or hex encoded)")
Cmd.Flags().StringVar(&inputIndex, "input-index", "",
"Filter outputs by input index (decimal or hex encoded)")
Cmd.Flags().StringVar(&outputType, "output-type", "",
"Filter outputs by output type (first 4 bytes of raw data hex encoded)")
Cmd.Flags().StringArrayVar(&outputTypes, "output-type", nil,
"Filter outputs by output type (first 4 bytes of raw data hex encoded); may be specified multiple times")
Cmd.Flags().BoolVar(&executed, "executed", false,
"Filter outputs by execution status")
Cmd.Flags().StringVar(&voucherAddress, "voucher-address", "",
"Filter outputs by voucher address (hex encoded)")
Cmd.Flags().Uint64Var(&limit, "limit", 50, //nolint: mnd
Expand Down Expand Up @@ -128,7 +131,13 @@ func run(cmd *cobra.Command, args []string) {

// Add output type filter if provided
if cmd.Flags().Changed("output-type") {
params.OutputType = &outputType
selectors := api.StringOrList(outputTypes)
params.OutputType = &selectors
}

// Add execution status filter if provided
if cmd.Flags().Changed("executed") {
params.Executed = &executed
}

// Add voucher address filter if provided
Expand Down
20 changes: 12 additions & 8 deletions cmd/cartesi-rollups-cli/root/read/service/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ func (s *JsonrpcReadService) ListEpochs(ctx context.Context, params api.ListEpoc
if _, err := config.ToApplicationNameOrAddressFromString(params.Application); err != nil {
return nil, fmt.Errorf("invalid application: %w", err)
}
// Add status filter if provided
// Validate status filter if provided
if params.Status != nil {
var statusVal model.EpochStatus
if err := statusVal.Scan(*params.Status); err != nil {
return nil, fmt.Errorf("invalid status: %w", err)
for i, status := range *params.Status {
var statusVal model.EpochStatus
if err := statusVal.Scan(status); err != nil {
return nil, fmt.Errorf("invalid status #%d: %w", i+1, err)
}
}
}

Expand Down Expand Up @@ -130,8 +132,10 @@ func (s *JsonrpcReadService) ListOutputs(ctx context.Context, params api.ListOut
}
// Add output type filter if provided
if params.OutputType != nil {
if _, err := api.ParseOutputType(*params.OutputType); err != nil {
return nil, fmt.Errorf("invalid output type: %w", err)
for i, selector := range *params.OutputType {
if _, err := api.ParseOutputType(selector); err != nil {
return nil, fmt.Errorf("invalid output type #%d: %w", i+1, err)
}
}
}
// Add voucher address filter if provided
Expand Down Expand Up @@ -338,7 +342,7 @@ func (s *JsonrpcReadService) ListMatches(ctx context.Context, params api.ListMat
return resp, err
}

func (s *JsonrpcReadService) GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvancedParams) (json.RawMessage, error) {
func (s *JsonrpcReadService) GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvanceParams) (json.RawMessage, error) {
if _, err := config.ToApplicationNameOrAddressFromString(params.Application); err != nil {
return nil, fmt.Errorf("invalid application: %w", err)
}
Expand All @@ -356,7 +360,7 @@ func (s *JsonrpcReadService) GetMatchAdvanced(ctx context.Context, params api.Ge
}

var resp json.RawMessage
err := s.Client.Call(ctx, "cartesi_getMatchAdvanced", params, &resp)
err := s.Client.Call(ctx, "cartesi_getMatchAdvance", params, &resp)
return resp, err
}

Expand Down
24 changes: 16 additions & 8 deletions cmd/cartesi-rollups-cli/root/read/service/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,14 @@ func (s *RepositoryReadService) ListEpochs(ctx context.Context, params api.ListE
pagination := repository.Pagination{}
// Add status filter if provided
if params.Status != nil {
var statusVal model.EpochStatus
if err := statusVal.Scan(*params.Status); err != nil {
return nil, fmt.Errorf("invalid status: %w", err)
filter.Status = make([]model.EpochStatus, len(*params.Status))
for i, status := range *params.Status {
var statusVal model.EpochStatus
if err := statusVal.Scan(status); err != nil {
return nil, fmt.Errorf("invalid status #%d: %w", i, err)
}
filter.Status[i] = statusVal
}
filter.Status = []model.EpochStatus{statusVal}
}
pagination.Limit = params.Limit
pagination.Offset = params.Offset
Expand Down Expand Up @@ -289,9 +292,13 @@ func (s *RepositoryReadService) ListOutputs(ctx context.Context, params api.List
}
// Add output type filter if provided
if params.OutputType != nil {
outputTypeVal, err := api.ParseOutputType(*params.OutputType)
if err != nil {
return nil, fmt.Errorf("invalid output type: %w", err)
outputTypeVal := make([][]byte, len(*params.OutputType))
for i, selector := range *params.OutputType {
parsed, err := api.ParseOutputType(selector)
if err != nil {
return nil, fmt.Errorf("invalid output type #%d: %w", i+1, err)
}
outputTypeVal[i] = parsed
}
filter.OutputType = &outputTypeVal
}
Expand All @@ -303,6 +310,7 @@ func (s *RepositoryReadService) ListOutputs(ctx context.Context, params api.List
}
filter.VoucherAddress = &voucherAddressVal
}
filter.Executed = params.Executed
pagination.Limit = params.Limit
pagination.Offset = params.Offset

Expand Down Expand Up @@ -782,7 +790,7 @@ func (s *RepositoryReadService) ListMatches(ctx context.Context, params api.List
return json.RawMessage(result), err
}

func (s *RepositoryReadService) GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvancedParams) (json.RawMessage, error) {
func (s *RepositoryReadService) GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvanceParams) (json.RawMessage, error) {
repo := s.Repository
application, err := config.ToApplicationNameOrAddressFromString(params.Application)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/cartesi-rollups-cli/root/read/service/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type ReadService interface {
ListCommitments(ctx context.Context, params api.ListCommitmentsParams) (json.RawMessage, error)
GetMatch(ctx context.Context, params api.GetMatchParams) (json.RawMessage, error)
ListMatches(ctx context.Context, params api.ListMatchesParams) (json.RawMessage, error)
GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvancedParams) (json.RawMessage, error)
GetMatchAdvanced(ctx context.Context, params api.GetMatchAdvanceParams) (json.RawMessage, error)
ListMatchAdvances(ctx context.Context, params api.ListMatchAdvancesParams) (json.RawMessage, error)
Close()
}
Expand Down
119 changes: 104 additions & 15 deletions internal/jsonrpc/api/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,34 @@

package api

import (
"bytes"
"encoding/json"
"fmt"
"reflect"
)

type StringOrList []string

func (s *StringOrList) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
if len(data) > 0 && data[0] == '"' {
var value string
if err := json.Unmarshal(data, &value); err != nil {
return err
}
*s = []string{value}
return nil
}

var values []string
if err := json.Unmarshal(data, &values); err != nil {
return fmt.Errorf("expected a string or an array of strings: %w", err)
}
*s = values
return nil
}

// ListApplicationsParams aligns with the OpenRPC specification
type ListApplicationsParams struct {
Limit uint64 `json:"limit"`
Expand All @@ -17,11 +45,13 @@ type GetApplicationParams struct {

// ListEpochsParams aligns with the OpenRPC specification
type ListEpochsParams struct {
Application string `json:"application"`
Status *string `json:"status,omitempty"`
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
Application string `json:"application"`
Status *StringOrList `json:"status,omitempty"`
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
From *string `json:"from,omitempty"` // inclusive lower bound on the epoch index (hex)
To *string `json:"to,omitempty"` // inclusive upper bound on the epoch index (hex)
}

// GetEpochParams aligns with the OpenRPC specification
Expand All @@ -30,6 +60,12 @@ type GetEpochParams struct {
EpochIndex string `json:"epoch_index"`
}

// GetEpochByVirtualIndexParams aligns with the OpenRPC specification
type GetEpochByVirtualIndexParams struct {
Application string `json:"application"`
VirtualIndex string `json:"virtual_index"`
}

// GetLastAcceptedEpochIndexParams with the OpenRPC specification
type GetLastAcceptedEpochIndexParams struct {
Application string `json:"application"`
Expand All @@ -44,6 +80,8 @@ type ListInputsParams struct {
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
From *string `json:"from,omitempty"` // inclusive lower bound on the input index (hex)
To *string `json:"to,omitempty"` // inclusive upper bound on the input index (hex)
}

// GetInputParams aligns with the OpenRPC specification
Expand All @@ -59,14 +97,17 @@ type GetProcessedInputCountParams struct {

// ListOutputsParams aligns with the OpenRPC specification
type ListOutputsParams struct {
Application string `json:"application"`
EpochIndex *string `json:"epoch_index,omitempty"`
InputIndex *string `json:"input_index,omitempty"`
OutputType *string `json:"output_type,omitempty"`
VoucherAddress *string `json:"voucher_address,omitempty"`
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
Application string `json:"application"`
EpochIndex *string `json:"epoch_index,omitempty"`
InputIndex *string `json:"input_index,omitempty"`
OutputType *StringOrList `json:"output_type,omitempty"`
VoucherAddress *string `json:"voucher_address,omitempty"`
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
From *string `json:"from,omitempty"` // inclusive lower bound on the output index (hex)
To *string `json:"to,omitempty"` // inclusive upper bound on the output index (hex)
Executed *bool `json:"executed,omitempty"`
}

// GetOutputParams aligns with the OpenRPC specification
Expand All @@ -83,6 +124,8 @@ type ListReportsParams struct {
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Descending bool `json:"descending,omitempty"`
From *string `json:"from,omitempty"` // inclusive lower bound on the report index (hex)
To *string `json:"to,omitempty"` // inclusive upper bound on the report index (hex)
}

// GetReportParams aligns with the OpenRPC specification
Expand Down Expand Up @@ -156,8 +199,8 @@ type ListMatchAdvancesParams struct {
Descending bool `json:"descending,omitempty"`
}

// GetMatchAdvancedParams aligns with the OpenRPC specification
type GetMatchAdvancedParams struct {
// GetMatchAdvanceParams aligns with the OpenRPC specification
type GetMatchAdvanceParams struct {
Application string `json:"application"`
EpochIndex string `json:"epoch_index"`
TournamentAddress string `json:"tournament_address"`
Expand All @@ -179,3 +222,49 @@ type GetWithdrawalParams struct {
Application string `json:"application"`
AccountIndex string `json:"account_index"`
}

// UnmarshalParams supports both by-name (object) and by-position (array) parameter structures.
// If params is an object, it simply does json.Unmarshal; if it's an array, it will attempt
// to unmarshal each positional parameter into the target struct field in declaration order.
func UnmarshalParams(data json.RawMessage, target any) error {
data = bytes.TrimSpace(data)
if len(data) > 0 && data[0] == '[' {
// Unmarshal positional parameters into a slice of json.RawMessage.
var rawParams []json.RawMessage
if err := json.Unmarshal(data, &rawParams); err != nil {
return err
}
// Use reflection to set values in the target struct in the order they appear.
val := reflect.ValueOf(target)
if val.Kind() != reflect.Pointer || val.IsNil() {
return fmt.Errorf("error unmarshalling positional parameters target must be a non-nil pointer to a struct")
}
val = val.Elem()
if val.Kind() != reflect.Struct {
return fmt.Errorf("error unmarshalling positional parameters target must point to a struct")
}
typ := val.Type()
if len(rawParams) > typ.NumField() {
return fmt.Errorf("error unmarshalling positional parameters, expected %d params, got %d",
typ.NumField(), len(rawParams))
}
// For each field in the struct, if a positional parameter exists, unmarshal that parameter.
for i := 0; i < typ.NumField() && i < len(rawParams); i++ {
sf := typ.Field(i)
if sf.Tag.Get("json") == "-" {
continue
}
field := val.Field(i)
if !field.CanSet() {
return fmt.Errorf("error unmarshalling positional parameter field %q is not settable", typ.Field(i).Name)
}
// Unmarshal the corresponding raw parameter into the field.
if err := json.Unmarshal(rawParams[i], field.Addr().Interface()); err != nil {
return fmt.Errorf("error unmarshalling positional parameter %d for field %s: %w", i, typ.Field(i).Name, err)
}
}
return nil
}
// Otherwise, assume by-name structure.
return json.Unmarshal(data, target)
}
Loading