Skip to content

[Intermediate]: Add setMaxNodesPerTransaction() method to Client #548

@rwalworth

Description

@rwalworth

🧩 Intermediate Friendly

This issue is a good fit for contributors who are already familiar with the Hiero Swift SDK and feel comfortable navigating the codebase.

Intermediate Issues often involve:

  • Exploring existing implementations
  • Understanding how different components work together
  • Making thoughtful changes that follow established patterns

The goal is to support deeper problem-solving while keeping the task clear, focused, and enjoyable to work on.

🐞 Problem Description

When submitting a transaction, the SDK selects nodes from the network to submit to. Currently, there's no way to limit how many nodes a single transaction can be submitted to during retries.

Other Hiero SDKs (Java, Go, JavaScript, C++) provide a setMaxNodesPerTransaction() method that limits:

  • The number of different nodes a transaction will try
  • Resource usage during high-retry scenarios
  • Network load from a single client

This is useful for:

  • Controlling costs (each node submission may incur fees)
  • Limiting exposure during network issues
  • Testing with specific node subsets

Relevant files:

  • Sources/Hiero/Client/Client.swift - Main client class
  • Sources/Hiero/Client/ConsensusNetwork.swift - Node selection logic
  • Sources/Hiero/Execute.swift - Transaction execution and retry logic

💡 Expected Outcome

Add a configurable maximum nodes per transaction setting:

  1. setMaxNodesPerTransaction(_ maxNodes: Int) - Sets the limit (0 = unlimited)
  2. Optionally: getMaxNodesPerTransaction() -> Int? - Returns current limit

The implementation should:

  • Store the configuration in the Client
  • Be used by node selection logic when building the list of nodes for a transaction
  • Default to 0 (unlimited) to maintain current behavior
  • Work with the existing node health and selection mechanisms

🧠 Implementation Notes

Suggested approach:

  1. Add a private property to Client:

    private let _maxNodesPerTransaction: ManagedAtomic<Int>
  2. Initialize with default (unlimited):

    self._maxNodesPerTransaction = .init(0)  // 0 = unlimited
  3. Add public setter (and optional getter) to Client:

    @discardableResult
    public func setMaxNodesPerTransaction(_ maxNodes: Int) -> Self {
        _maxNodesPerTransaction.store(maxNodes, ordering: .relaxed)
        return self
    }
    
    public func getMaxNodesPerTransaction() -> Int? {
        let value = _maxNodesPerTransaction.load(ordering: .relaxed)
        return value == 0 ? nil : value
    }
  4. Modify node selection in ConsensusNetwork or transaction execution to respect this limit

Key considerations:

  • Look at how ConsensusNetwork.nodes is used when selecting nodes for transactions
  • The limit should apply to the total unique nodes tried, not just concurrent attempts
  • Consider interaction with maxAttempts - if maxNodesPerTransaction is 3 but maxAttempts is 10, the transaction should still only try 3 different nodes
  • A value of 0 should mean "no limit" (use all healthy nodes)

Reference implementations:

  • Java: Client.setMaxNodesPerTransaction(int) - limits nodes in Network
  • Go: Client.SetMaxNodesPerTransaction(int) - stored in network config
  • JavaScript: client.setMaxNodesPerTransaction(number) - limits node list

✅ Acceptance Criteria

To help get this change merged smoothly:

  • setMaxNodesPerTransaction() method added to Client
  • Node selection respects the configured limit
  • Default behavior unchanged (unlimited nodes)
  • Setting 0 means unlimited (no change from current behavior)
  • Follow existing project conventions
  • Avoid breaking public APIs
  • Include tests where appropriate
  • Pass all CI checks

📋 Contribution Guide

To help your contribution go as smoothly as possible, we recommend following these steps:

  • Comment /assign to request the issue
  • Wait for assignment
  • Fork the repository and create a branch
  • Set up the project using the instructions in README.md
  • Make the requested changes
  • Sign each commit using -s -S
  • Push your branch and open a pull request

Read Workflow Guide for step-by-step workflow guidance.
Read README.md for setup instructions.

❗ Pull requests cannot be merged without S and s signed commits.
See the Signing Guide.

📚 Additional Context or Resources

If you have questions, the community is happy to help:

https://discord.com/channels/905194001349627914/1337424839761465364

Useful files to review:

  • Sources/Hiero/Client/ConsensusNetwork.swift - Node list management
  • Sources/Hiero/Execute.swift - Transaction execution flow
  • Sources/Hiero/Transaction.swift - Transaction class that gets executed

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: lowNon-urgent tasks, nice-to-have improvements, or minor issuesscope: apiRelated to the public SDK API surfacescope: grpcRelated to gRPC/protobuf/network layerskill: intermediateRequires familiarity with the codebase structure and SDK conceptsstatus: ready for devThe issue is fully defined and ready for a contributor
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions