Skip to content

Expand usage of validate struct tags across RPC methods and clean up redundant custom validation #3589

@thiagodeev

Description

@thiagodeev

Context

We use the go-playground/validator library to validate incoming RPC request structs via struct tags. The validator is integrated into the jsonrpc.Server and each RPC version has its own singleton (rpc/v10/validator.go, rpc/v9/validator.go, rpc/v8/validator.go). When a struct is a handler parameter, the server automatically calls validator.Struct() on it before the handler runs (jsonrpc/server.go#L655-L672).

You can see good examples of validate tags already in use:


Task 1: Audit all RPC handler methods for missing validation tag opportunities

Go through every handler method registered in rpc/v10/, rpc/v9/, and rpc/v8/ (you can find the full list in each version's Methods() function) and check the starkent API specification for each one of them (refs for v10, v9, and v8). For each handler, look at the input parameter structs and check:

  • Are there fields that should be required but have no validate tag?
  • Are there conditional requirements (e.g., "field X is required when Type is Y") that are not expressed via required_if, required_unless, excluded_unless, etc.?
  • Are there range/size constraints (like the min=1 on ChunkSize) that are not being enforced via tags?

For each finding, make the appropriate improvements.


Task 2: Identify and remove dead/redundant custom validation code

There is already custom validation logic that duplicates what the validate tags should handle. A clear example is in rpc/v10/simulation.go#L261-L272:

func checkTxHasSenderAddress(tx *BroadcastedTransaction) bool {
    return (tx.Type == TxnDeclare ||
        tx.Type == TxnInvoke) &&
        tx.SenderAddress == nil
}

func checkTxHasResourceBounds(tx *BroadcastedTransaction) bool {
    return (tx.Type == TxnInvoke ||
        tx.Type == TxnDeployAccount ||
        tx.Type == TxnDeclare) &&
        tx.ResourceBounds == nil
}

These are called in prepareTransactions() (rpc/v10/simulation.go#L283-L301) and are checking conditions that are already expressed in the validate tags on the Transaction struct (rpc/v10/transaction_types.go#L402-L424):

  • SenderAddress has validate:"required_if=Type DECLARE,required_if=Type INVOKE" (line 412)
  • ResourceBounds has validate:"required" (line 417)

Search the codebase for other patterns like:

  • Manual nil checks that mirror required tags
  • Manual type-conditional checks that mirror required_if tags
  • Any if field == nil { return error } blocks on fields that already have validate tags
  • Verify existing validate tags are up-to-date. Cross-reference the current validate tags against the Starknet API spec. Some tags may be stale or incorrect — for example, a field that was once optional may now be required (or vice versa), or a required_if condition may reference transaction types that have changed. Compare what the tags enforce vs. what the spec actually demands for each field and transaction type.

For each finding, make the appropriate improvements.


Task 3: Add tests for every validation tag

For every struct that has validate tags (existing or newly added), write unit tests that:

  1. Test the happy path — a fully valid struct passes validation.
  2. Test each validate rule — for every tagged field, submit a struct that violates that specific rule and assert the validator returns an error.
  3. Test conditional rules — for required_if and excluded_unless tags, test both sides of the condition (e.g., for required_if=Type DECLARE, test that the field IS required when Type=DECLARE and is NOT required when Type=INVOKE).
  4. Add a sentinel test that fails when new validate tags are added without corresponding tests.. If someone adds a new validate tag to any struct in the future and doesn't update the test, the test will fail, reminding them to add coverage.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions