Skip to content

Conversation

@SmartDever02
Copy link
Contributor

@SmartDever02 SmartDever02 commented Dec 22, 2025

This PR implements comprehensive batching support for CLI commands that can submit multiple extrinsic calls, significantly reducing transaction fees for users. This closes GitHub issue #567.

Core Changes:

  1. New Batching Interface (subtensor_interface.py)

    • Added sign_and_send_batch_extrinsic() method to support batching multiple GenericCall objects into a single transaction
    • Supports three batch types: 'batch', 'batch_all', and 'force_batch'
    • Defaults to 'batch_all' to ensure atomicity (all succeed or all fail)
    • Fully integrates with existing features: MEV protection, proxy transactions, era management, and nonce handling
    • Returns detailed results including success status, extrinsic receipt, and individual call results
  2. Stake Add Command Refactoring (stake/add.py)

    • Refactored to collect multiple stake operations (across different netuids and/or hotkeys) into a single batch transaction
    • Automatically uses batching when multiple --netuid or --hotkey arguments are provided
    • Optimized balance fetching using asyncio.gather for parallel queries
    • Enhanced display to show:
      • Individual stake changes per netuid/hotkey combination
      • Final coldkey balance change (previous_balance -> current_balance) * Clear visual feedback for each operation in the batch
  3. Stake Remove Command Refactoring (stake/remove.py)

    • Refactored unstake() to batch multiple remove_stake operations
    • Refactored unstake_all() to batch multiple unstake_all operations
    • Supports batching when:
      • Multiple --netuid arguments are provided
      • Multiple --hotkey arguments are provided * --include-hotkeys with multiple hotkeys is used
    • Optimized stake balance fetching using asyncio.gather
    • Enhanced display to show:
      • Individual unstake changes per netuid/hotkey
      • Remaining stake balances after operations * Final coldkey balance change (previous_balance -> current_balance)
    • Captures initial balance at function start for accurate display
  4. CLI Validation Updates (cli.py)

    • Removed restriction preventing unstake_all with multiple --include-hotkeys
    • Updated logic to properly initialize wallet when include_hotkeys is provided
    • Now supports batching unstake_all operations across multiple hotkeys

Technical Details:

  • Batch Type: Uses Utility.batch_all by default, ensuring atomic execution
  • Fee Savings: Multiple operations combined into single transaction fee
  • Backward Compatibility: Single operations still work as before (no batching)
  • Error Handling: batch_all ensures all operations succeed or fail together
  • Display Consistency: Balance changes shown consistently across all stake operations

Benefits:

  • Significant fee reduction when performing multiple stake/unstake operations
  • Improved user experience with clear feedback on all operations
  • Atomic operations prevent partial failures
  • Maintains all existing functionality (MEV protection, proxy, etc.)

Tests for batching:

  • Created test_batching.py for batching extrinsic opeartions

Closes #567

@SmartDever02
Copy link
Contributor Author

what's the reason tests failing in pipeline? as on my local they passed.
image

@SmartDever02
Copy link
Contributor Author

what's the reason tests failing in pipeline? as on my local they passed. image

okay it was because of #778 , pushed a fix

@SmartDever02
Copy link
Contributor Author

SmartDever02 commented Feb 2, 2026

@basfroman were you able to check my pr? FYI - am not mining gittensor anymore
am back to this pr as I noticed batching is not implemented yet while unstaking some subnet alphas

Copy link
Contributor

@basfroman basfroman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for contribution!

What I like:

  • good idea and motivation
  • backward compatibility
  • integration with existing features
  • parallel retrieval of balances

But this logic:

  • has critical bugs
  • have to be up-to-date with staging (as fas as I can see, currently it doesn't)
  • should have more understandable and detailed docstrings for the new functions

)
if not mev_success:
status.stop()
print_error.print(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print_error is a function and don't have print parameter.

)
if not mev_success:
status.stop()
print_error.print(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print_error is a function and don't have print parameter.

Comment on lines +455 to +457
console.print(
f"[yellow][DEBUG][/yellow] Operation {idx} (netuid={op['netuid']}): assigning ext_id={batch_ext_id}"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually show debug info in verbose mode.

coldkey_ss58 = proxy or wallet.coldkeypub.ss58_address

# Capture initial balance before operations
initial_balance_all = await subtensor.get_balance(coldkey_ss58)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable 'initial_balance_all' value is not used

Comment on lines +1372 to +1392
try:
# Extract batch execution results from receipt
# The receipt should contain information about which calls succeeded/failed
for i, call in enumerate(calls):
call_results.append(
{
"index": i,
"call": call,
"success": True, # Will be updated if we can parse receipt
}
)
except Exception:
# If we can't parse results, assume all succeeded if batch succeeded
for i, call in enumerate(calls):
call_results.append(
{
"index": i,
"call": call,
"success": success,
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this try/except block is pointless - the code in the try block will never raise an exception (a simple loop with append). The comment Will be updated if we can parse receipt indicates an incomplete implementation.

Pls either implement parsing of events from the receipt to determine the success of individual calls, or remove the dead code

proxy=proxy,
nonce=next_nonce,
mev_protection=mev_protection,
batch_type="batch_all", # Use batch_all to execute all even if some fail
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a misunderstanding. batch_all means: all calls will be executed, but if at least one fails, all will be rolled back. it doesn't mean execute all even if some fail.

If you need to execute all regardless of errors you need force_batch (which is in the signature, but not used).
Pls, clarify the requirements and correct the comments/logic

Comment on lines +573 to +574
if batch_success and batch_receipt:
if mev_protection:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend you to create something like handle_mev_protection function with proper parameters to handle the result. You broke DRY rule.
Currently, you have 3 exact the same code section in stake_add, unstake, and unstake_all calls.

batch_success,
batch_err_msg,
batch_receipt,
call_results,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this call_results never used

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The e2e tests doesn't verify:

  • the correctness of balances after transactions
  • that the stake is actually added/removed
  • behavior in case of errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants