8000 feat: add support for Batch amendment by mvadari · Pull Request #757 · XRPLF/xrpl-py · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: add support for Batch amendment #757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 86 commits into from
Jun 6, 2025
Merged

feat: add support for Batch amendment #757

merged 86 commits into from
Jun 6, 2025

Conversation

mvadari
Copy link
Collaborator
@mvadari mvadari commented Oct 10, 2024

High Level Overview of Change

This PR:

  • Adds models for the Batch transactions
  • Updates definitions.json to handle the new field types
  • Adds support to the binary codec to properly sign multi-account Batch transactions
  • Adds helper functions for signing and combining multi-account Batch transactions
  • Adds support to autofill for filling in the BatchTxn and TxIDs fields
  • Fixes a side issue where multisigned transactions weren't properly autofilled
  • Fixes another side issue where ticket sequences weren't handled properly

Context of Change

XRPLF/rippled#5060

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Did you update CHANGELOG.md?

  • Yes
  • No, this change does not impact library users

Test Plan

Added tests for the new features.

Copy link
Contributor
coderabbitai bot commented Oct 10, 2024

Walkthrough

This update introduces comprehensive support for batch transactions (XLS-56d) in the XRPL Python library. It adds new transaction models, batch signing and combination utilities, batch encoding for signing, and test coverage. Numerous transaction flag interfaces are unified, and new type annotations are applied throughout transaction autofill and signing workflows.

Changes

Files / Groups Change Summary
.vscode/settings.json Added batch-related terms ("autofilling", "multiaccount", "multisigned", "multisigning") to spell checker words.
.ci-config/rippled.cfg Updated amendments: removed some, added Batch and others under new version headings.
CHANGELOG.md Documented batch transaction support, validation improvements, and other enhancements.
tools/generate_tx_models.py Added usage message for missing command-line arguments.
xrpl/core/binarycodec/main.py, xrpl/core/binarycodec/__init__.py Added encode_for_signing_batch for batch transaction signing; exported it.
xrpl/models/transactions/batch.py Introduced Batch transaction model, flags, and batch signer classes.
xrpl/models/transactions/types/transaction_type.py Added BATCH member to TransactionType enum.
xrpl/models/transactions/transaction.py Added TransactionFlag enum and interface; adjusted get_hash for batch flag.
xrpl/models/transactions/__init__.py Exported Batch-related and transaction flag classes.
xrpl/models/transactions/* (various transaction types) Unified flag interface base classes to use TransactionFlagInterface.
xrpl/models/transactions/delegate_set.py, tests/unit/models/transactions/test_delegate_set.py Updated non-delegable transaction logic and error messages for Batch.
xrpl/asyncio/transaction/main.py, xrpl/transaction/main.py Added batch transaction autofill/signing support; improved type annotations.
xrpl/transaction/batch_signers.py, xrpl/transaction/__init__.py Added batch multi-account signing and signer combination utilities; exported them.
xrpl/core/binarycodec/definitions/definitions.py Formatting and whitespace clean-up.
tests/unit/models/transactions/test_batch.py Added unit test for Batch model and flag propagation.
tests/unit/transaction/test_batch_signers.py Added unit tests for batch multi-account signing and signer combination.
tests/unit/core/binarycodec/test_main.py Added test for batch transaction signing encoding.
tests/integration/transactions/test_batch.py Added integration tests for batch transaction submission and multi-signing.
tests/integration/sugar/test_transaction.py Added async test for batch autofill; updated imports.
tests/unit/models/transactions/test_transaction.py Added test for multisigned transaction with x-addresses; refactored test names.
tests/integration/it_utils.py Removed explicit fee check argument in wallet funding helpers.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant BatchTx
    participant Wallet
    participant Client
    participant BatchSigners

    User->>BatchTx: Create Batch with raw_transactions
    User->>Client: autofill(BatchTx)
    Client->>BatchTx: Assign sequence, set flags, validate inner txns
    User->>Wallet: sign_multiaccount_batch(BatchTx, Wallet)
    Wallet->>BatchSigners: Sign Batch, add to BatchSigners
    User->>Client: submit(BatchTx with BatchSigners)
    Client-->>User: Submission result
Loading

Possibly related PRs

Suggested reviewers

  • ckeshava

Poem

🐇 In fields of code where batchers leap,
New flags and signers now run deep.
Transactions hop in groups, not one—
With multi-sign, the work gets done!
Tests abound, and models grow,
As rabbits cheer, “Batch, away we go!”
✨🐰

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (13)
xrpl/models/transactions/ledger_state_fix.py (1)

19-25: LGTM: Attributes are well-defined. Consider adding more documentation.

The class attributes are appropriately defined with correct types and default values. The use of REQUIRED for ledger_fix_type and the optional owner attribute provide necessary flexibility.

Consider adding a comment or expanding the class docstring to explain the possible values and significance of the ledger_fix_type attribute. This would enhance the usability of the class for developers.

tools/generate_tx_models.py (1)

188-189: Good addition of argument handling. Consider a minor improvement.

The addition of argument checking and a usage message is a valuable improvement to the script's usability and error prevention. It aligns well with best practices for command-line tools.

Consider updating the usage message to be more explicit about the required argument:

print("Usage: poetry run python generate_tx_models.py <path_to_rippled_source>")

This minor change makes it even clearer what the expected argument represents.

tests/unit/models/transactions/test_transaction.py (1)

162-171: LGTM: New test for multisigned transactions with X-addresses.

This new test method effectively verifies the functionality of multisigning transactions using X-addresses, which aligns with the PR objectives.

Suggestion for improvement:
Consider adding assertions to verify the content of the multisigned transaction, not just that it's signed. For example, you could check that the Account and Authorize fields in the final transaction contain the correct X-addresses.

xrpl/core/binarycodec/definitions/definitions.json (7)

383-392: LGTM: New LedgerFixType field added

The addition of the "LedgerFixType" field of type UInt16 is appropriate for supporting the new LedgerStateFix transaction type. This allows for a wide range of potential ledger fix types (up to 65,535).

Consider adding documentation or comments explaining the purpose of this field and any predefined LedgerFixType values, if applicable.


2003-2012: LGTM: New InnerResult field added

The addition of the "InnerResult" field of type Blob is appropriate for storing results of individual transactions within a Batch transaction. The Blob type provides flexibility for various result data.

Consider adding documentation or comments explaining the purpose and expected content of this field, especially in the context of Batch transactions.


2173-2182: LGTM: New OuterAccount field added

The addition of the "OuterAccount" field of type AccountID is appropriate for identifying the account initiating a Batch transaction.

Consider adding documentation or comments explaining the specific role and usage of the OuterAccount field in the context of Batch transactions.


2223-2232: LGTM: New TxIDs field added

The addition of the "TxIDs" field of type Vector256 is appropriate for storing transaction IDs within a Batch transaction. This allows for efficient storage and retrieval of multiple transaction hashes.

Consider adding documentation or comments explaining the purpose and usage of the TxIDs field, particularly its relationship to Batch transactions and any limitations on the number of transaction IDs that can be stored.


2931-2931: LGTM: New transaction types and results added

The additions of new transaction types (LedgerStateFix and Batch) and transaction results (temINVALID_BATCH and tecBATCH_FAILURE) are consistent with the PR objectives. The numbering follows the existing pattern and doesn't conflict with other types/results.

Consider adding documentation or comments explaining:

  1. The purpose and use cases for the LedgerStateFix transaction type.
  2. The conditions under which temINVALID_BATCH and tecBATCH_FAILURE results would occur.
  3. Any specific requirements or limitations for Batch transactions.

Also applies to: 2954-2954, 3048-3049, 3100-3101


2603-2642: LGTM: New STObject and STArray fields added for Batch transactions

The addition of new STObject fields (RawTransaction, BatchExecution, BatchTxn, BatchSigner) and STArray fields (BatchExecutions, RawTransactions, BatchSigners) is consistent with the PR objectives for adding Batch transaction support. The naming is clear and follows existing conventions.

Consider adding documentation or comments explaining:

  1. The purpose and contents of each new field.
  2. The relationships between these fields (e.g., how BatchExecutions relates to BatchExecution).
  3. Any constraints or requirements for these fields in the context of Batch transactions.

Also applies to: 2833-2861


Line range hint 1-3101: Overall changes look good, but documentation is needed

The additions and modifications to the definitions.json file are consistent with the PR objectives of adding support for Batch transactions and LedgerStateFix functionality. The new fields, transaction types, and results are appropriately structured and follow existing patterns.

However, there's a general lack of documentation for these new elements. To improve maintainability and ease of use, consider the following suggestions:

  1. Add a comment section at the beginning of the file explaining the overall changes introduced in this update.
  2. For each new field, transaction type, and result, add inline comments explaining their purpose, usage, and any constraints or requirements.
  3. If there are any relationships or dependencies between the new elements (e.g., how BatchExecutions relates to BatchExecution), document these connections.
  4. Consider creating or updating separate documentation that provides a more detailed explanation of the Batch transaction feature and the LedgerStateFix functionality.
xrpl/models/transactions/batch.py (2)

20-26: Consider adding docstrings for class attributes

Adding docstrings to the BatchSigner class attributes can improve code readability and maintainability by providing clear descriptions of each field.


34-36: Consider adding docstrings for class attributes

Adding docstrings to the Batch class attributes can enhance clarity by explaining the purpose and usage of each field.

tests/integration/sugar/test_transaction.py (1)

266-267: Use constants for account addresses to improve maintainability

Hardcoding account addresses directly in the test code reduces maintainability and can lead to potential issues if the addresses need to be updated. Consider defining these addresses as constants at the top of the test module or using existing test account variables (e.g., ACCOUNT or DESTINATION). This will make the code cleaner and more consistent.

Also applies to: 270-271, 274-275, 286-287

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c288a5a and 2443f4c.

📒 Files selected for processing (11)
  • .vscode/settings.json (1 hunks)
  • tests/integration/sugar/test_transaction.py (2 hunks)
  • tests/unit/models/transactions/test_transaction.py (5 hunks)
  • tools/generate_tx_models.py (5 hunks)
  • xrpl/asyncio/transaction/main.py (8 hunks)
  • xrpl/core/binarycodec/definitions/definitions.json (11 hunks)
  • xrpl/models/transactions/init.py (4 hunks)
  • xrpl/models/transactions/batch.py (1 hunks)
  • xrpl/models/transactions/ledger_state_fix.py (1 hunks)
  • xrpl/models/transactions/transaction.py (3 hunks)
  • xrpl/models/transactions/types/transaction_type.py (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .vscode/settings.json
🧰 Additional context used
🪛 Gitleaks
tests/integration/sugar/test_transaction.py

270-270: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


274-274: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (30)
xrpl/models/transactions/ledger_state_fix.py (3)

1-11: LGTM: File structure and imports are well-organized.

The file structure is clean, with a clear module-level docstring and appropriate imports. The use of from __future__ import annotations is a good practice for forward compatibility with type annotations.


14-17: LGTM: Class definition and decorators are well-implemented.

The LedgerStateFix class is properly defined as a frozen dataclass, inheriting from Transaction. The use of @require_kwargs_on_init and KW_ONLY_DATACLASS ensures consistency with other XRPL models and enforces clear instantiation practices.


1-25: LGTM: Overall implementation is solid and consistent with XRPL patterns.

The LedgerStateFix transaction type is well-implemented, following XRPL conventions and Python best practices. The file is focused, concise, and maintains consistency with other transaction types in the XRPL framework.

xrpl/models/transactions/types/transaction_type.py (2)

17-17: LGTM: Addition of BATCH transaction type

The addition of BATCH = "Batch" to the TransactionType enum is consistent with the PR objective of introducing support for Batch transactions. The naming convention and placement within the enum are appropriate.


28-28: Approved: Addition of LEDGER_STATE_FIX transaction type, but clarification needed

The addition of LEDGER_STATE_FIX = "LedgerStateFix" to the TransactionType enum is consistent with the naming conventions and placement within the enum. However, this transaction type was not explicitly mentioned in the PR objectives.

Could you please provide some context on the purpose of this new transaction type and how it relates to the overall objectives of this PR? This information would be helpful for understanding the full scope of the changes.

xrpl/models/transactions/__init__.py (2)

114-114: Updated all list with new transaction types

The __all__ list has been correctly updated to include Batch and LedgerStateFix, making these new classes part of the module's public API. This change is consistent with the existing pattern in the file and ensures that the new transaction types are accessible when importing from this module.

Also applies to: 125-125


27-27: New transaction types added: Batch and LedgerStateFix

The addition of Batch and LedgerStateFix imports aligns with the PR objectives of adding support for Batch transactions. The LedgerStateFix addition, while not explicitly mentioned in the PR objectives, appears to be a related enhancement to the framework's functionality.

Let's verify the consistency of these additions with other files in the codebase:

Also applies to: 38-38

✅ Verification successful

Verification Successful: The additions of Batch and LedgerStateFix imports in xrpl/models/transactions/__init__.py are consistent with the project's structure and intended API enhancements.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and usage of Batch and LedgerStateFix classes

# Test 1: Check if the Batch and LedgerStateFix files exist
echo "Checking for Batch and LedgerStateFix files:"
fd -e py "batch|ledger_state_fix" xrpl/models/transactions

# Test 2: Look for usage of Batch and LedgerStateFix in other files
echo "Checking for usage of Batch and LedgerStateFix:"
rg -t py "from xrpl\.models\.transactions import .*(?:Batch|LedgerStateFix)" --glob '!xrpl/models/transactions/__init__.py'

Length of output: 469

tools/generate_tx_models.py (3)

134-134: Great addition of the @DataClass decorator!

The addition of the @dataclass(frozen=True, **KW_ONLY_DATACLASS) decorator is a valuable improvement. It simplifies class creation, enhances immutability, and likely enforces keyword-only arguments. These changes contribute to improved type safety, code robustness, and clarity, aligning well with the PR objectives.


40-40: LGTM. Verify the new file path.

The update to the file path for TxFormats.cpp is consistent with the previous change, further confirming the restructuring of the source code to separate the XRPL protocol into its own library. This change aligns with the PR objectives.

Please run the following script to verify the existence of the new file path:

#!/bin/bash
# Verify the existence of the new TxFormats.cpp file
fd -t f "TxFormats.cpp" | grep "src/libxrpl/protocol/TxFormats.cpp"

29-29: LGTM. Verify the new file path.

The update to the file path for SField.cpp reflects a restructuring of the source code, which is in line with the PR objectives. This change suggests a more modular approach by separating the XRPL protocol into its own library.

Please run the following script to verify the existence of the new file path:

tests/unit/models/transactions/test_transaction.py (4)

4-4: LGTM: New import for address conversion.

The addition of classic_address_to_xaddress import is appropriate for the new test method that will be using X-addresses.


6-6: LGTM: Updated import for DepositPreauth transaction type.

The inclusion of DepositPreauth in the import statement is appropriate for the new test method that will be using this transaction type.


174-174: LGTM: Renamed test methods to follow Python naming conventions.

The renaming of these test methods from camelCase to snake_case improves consistency with Python naming conventions (PEP 8). This change enhances code readability and maintainability.

Also applies to: 190-190, 206-206, 222-222


Line range hint 1-238: Summary: Valuable additions and improvements to transaction tests.

The changes in this file effectively support the PR objectives:

  1. Added support for X-addresses in multisigned transactions.
  2. Expanded test coverage for Batch transactions.
  3. Improved code quality through consistent naming conventions.

These changes enhance the robustness of the XRPL Python library without breaking existing functionality. The new test for multisigned transactions with X-addresses is particularly valuable for ensuring the correct handling of these complex scenarios.

xrpl/core/binarycodec/definitions/definitions.json (1)

263-272: LGTM: New BatchIndex field added

The addition of the "BatchIndex" field of type UInt8 is appropriate for supporting Batch transactions. This allows for indexing up to 255 items in a batch, which should be sufficient for most use cases.

xrpl/models/transactions/batch.py (2)

15-27: Well-defined BatchSigner class

The BatchSigner class is correctly implemented with required and optional fields, following the codebase conventions.


29-41: Correct implementation of the Batch transaction class

The Batch class extends Transaction and appropriately defines required and optional fields, including setting the transaction_type to BATCH.

tests/integration/sugar/test_transaction.py (1)

264-291: New test for batch autofill is comprehensive and correct

The test_batch_autofill method effectively tests the autofilling of a batch transaction with multiple DepositPreauth transactions. The assertions verify that the transaction IDs are correctly generated and that the batch transaction properties are as expected. This improves the test coverage for batch transactions.

🧰 Tools
🪛 Gitleaks

270-270: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


274-274: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

xrpl/models/transactions/transaction.py (3)

430-434: Review the Updated Condition in get_hash Method for Correctness

The get_hash method now includes and self.batch_txn is None in its conditional check. This change implies that a transaction with a batch_txn is considered hashable even if txn_signature and signers are None. Please confirm that this aligns with the intended behavior for batch transactions and does not introduce security concerns by allowing unsigned transactions to be hashed.

Run the following script to find all usages of get_hash and ensure that the updated logic is compatible with how the method is utilized elsewhere in the codebase.

#!/bin/bash
# Description: Find all usages of `get_hash` method in the codebase.

rg --type py '\.get_hash\(' -A 2 -B 2

267-268: Ensure Backward Compatibility with Added batch_txn Field

The addition of the optional batch_txn field to the Transaction class could affect serialization and deserialization processes. Please verify that transactions without this field are still correctly handled, maintaining backward compatibility with existing transactions.

Run the following script to identify how Transaction serialization and deserialization are handled across the codebase and ensure they account for the new batch_txn field appropriately.

#!/bin/bash
# Description: Find all instances of Transaction serialization/deserialization methods.

rg --type py 'Transaction\.(from_dict|to_dict|from_xrpl|to_xrpl|from_blob|blob)\(' -A 2 -B 2

156-168: Question About the Necessity of # type: ignore Comments

The fields outer_account and batch_index in the BatchTxn class are marked with # type: ignore. Could you verify if these comments are necessary? If they suppress type-checking errors due to the use of REQUIRED, there might be a more elegant solution to handle the type annotations without ignoring type checks.

Run the following script to find all instances where REQUIRED fields are annotated with # type: ignore to assess if this pattern is used consistently and determine if it's essential.

✅ Verification successful

# type: ignore Comments for REQUIRED Fields are Necessary

The # type: ignore comments used with REQUIRED fields are essential to suppress type-checking errors caused by the REQUIRED sentinel value not matching the declared field types.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all instances of REQUIRED fields with `# type: ignore`.

rg --type py '=\s*REQUIRED\s*#\s*type:\s*ignore'

Length of output: 1978


Script:

#!/bin/bash
# Description: Find all instances of REQUIRED fields annotated with `# type: ignore`.

rg --type py '=\s*REQUIRED\s*#\s*type:\s*ignore'

Length of output: 17279

xrpl/asyncio/transaction/main.py (9)

200-202: Prevent direct signing of batch inner transactions

The added check correctly raises an exception when attempting to sign a batch inner transaction directly, ensuring that only appropriate transactions are signed.


221-223: Enhance type safety with TypeVar T

Introducing the type variable T bounded to Transaction improves type annotations and ensures that functions return the same subtype of Transaction that is passed in.


225-226: Update autofill function signature

The autofill function now utilizes the type variable T, allowing it to return the same specific transaction type as the input. This enhances type safety and consistency.


256-261: Handle batch transactions in autofill

The added code correctly checks if the transaction is of type BATCH and processes it using the _autofill_batch function. This ensures that batch transactions are properly autofilled.


392-392: Convert X-Addresses to classic addresses

The code ensures that if the specified field contains an X-Address, it is converted to a classic address. This maintains consistency in address formats throughout the transaction.


501-533: Implement _autofill_batch function for batch transactions

The new _autofill_batch function properly handles the autofilling of batch transactions. It assigns sequence numbers, manages batch indices, and computes transaction IDs for each inner transaction, ensuring correct processing of batch transactions.


516-523: Ensure correct sequence number assignment for multiple accounts

The sequence number assignment logic handles multiple transactions from potentially different accounts. Verify that the sequence number incrementation accurately reflects the state of each account, preventing sequence number collisions or gaps.

To verify that sequence numbers are correctly assigned per account, consider the following script:

#!/bin/bash
# Description: Check for sequence number consistency across accounts in batch transactions.

# List accounts and their assigned sequences in batch transactions
rg --type python 'account_sequences\[\s*raw_txn\.account\s*\]' -A 5

This script helps ensure that the account_sequences dictionary correctly tracks and increments sequence numbers for each account.


527-529: Confirm transaction reconstruction with updated batch_txn

After adding the batch_txn field to raw_txn_dict, a new Transaction object is created using Transaction.from_dict(). Verify that this method accurately reconstructs the transaction with all necessary fields intact.

You can run the following script to check the integrity of the reconstructed transactions:

#!/bin/bash
# Description: Ensure all required fields are present after reconstructing transactions with `batch_txn`.

# Search for usages of `Transaction.from_dict` and check fields
rg --type python 'Transaction\.from_dict\(' -A 10

This script helps confirm that from_dict() properly includes all essential fields when creating the new Transaction instances.


510-512: Verify handling of raw transactions with existing batch_txn

The code skips raw transactions that already have a batch_txn attribute. Please verify that these transactions have been adequately processed prior to this point and that skipping them here won't lead to missing necessary autofill steps.

To confirm that all raw transactions with existing batch_txn fields have been properly processed, you can search for their initialization in the codebase:

This script looks for places where batch_txn is assigned, helping ensure that such transactions are correctly handled before reaching this point in the code.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
xrpl/asyncio/transaction/main.py (3)

253-258: LGTM: Added support for batch transactions in autofill.

The addition of batch transaction handling in the autofill function is a significant feature. It correctly differentiates between regular and batch transactions, calling the appropriate autofill method.

Consider adding comprehensive unit tests for this new batch transaction handling to ensure all edge cases are covered.


498-530: LGTM: Well-implemented batch transaction autofill logic.

The _autofill_batch function effectively handles the complexities of batch transactions, including sequence management for multiple accounts and transaction ID generation. The logic appears sound and well-structured.

Consider adding error handling for potential issues, such as network errors during sequence retrieval. Also, it would be beneficial to add comprehensive unit tests for this function to cover various scenarios, including edge cases with multiple accounts and different transaction types within a batch.


Line range hint 1-530: Overall: Well-implemented batch transaction support with improved type safety.

The changes in this file successfully introduce support for batch transactions while also improving type safety throughout. Key points:

  1. The new batch transaction handling is well-integrated into existing functions like autofill and sign.
  2. Type safety improvements, especially in the autofill function, enhance the robustness of the code.
  3. The new _autofill_batch function effectively manages the complexities of batch transactions.

These changes significantly enhance the capabilities of the XRPL Python library without introducing breaking changes to existing functionality.

To ensure the reliability and correctness of these new features:

  1. Add comprehensive unit tests for batch transaction handling, covering various scenarios and edge cases.
  2. Consider adding more detailed error handling, especially in the _autofill_batch function.
  3. Update the documentation to clearly explain the new batch transaction support and any considerations for developers using this feature.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2443f4c and 3fa2294.

📒 Files selected for processing (1)
  • xrpl/asyncio/transaction/main.py (10 hunks)
🧰 Additional context used
🔇 Additional comments (4)
xrpl/asyncio/transaction/main.py (4)

2-6: LGTM: Import statements and type definitions updated appropriately.

The new imports and type definitions are well-aligned with the introduction of batch transaction support and improved type safety. These changes lay a good foundation for the subsequent modifications in the file.

Also applies to: 18-19


Line range hint 180-200: LGTM: Consistent check for batch inner transactions.

The addition of the check for batch inner transactions in _prepare_transaction is consistent with the changes in the sign function. This double-check approach enhances the security and correctness of transaction handling.


218-223: LGTM: Improved type safety in autofill function.

The introduction of the generic type T and its use in the autofill function signature enhances type safety. This change allows for more precise type checking and better IDE support when working with different transaction types.


Line range hint 90-99: Approve change, but verify impact on existing functionality.

The addition of _prepare_transaction call and the check for batch inner transactions improves the security of the signing process. However, we should ensure this change doesn't break any existing use cases.

Please run the following script to check for any existing direct uses of the sign function with batch inner transactions:

✅ Verification successful

Action Required: Correct the file type identifier in the search script.

Please run the following script to check for any existing direct uses of the sign function with batch inner transactions:


Action Required: Refine the search pattern to ensure all relevant sign function calls with Batch are captured.

Please run the following script to check for any existing direct uses of the sign function with batch inner transactions:


Change Verified: No direct calls to sign with Batch found.

The addition of _prepare_transaction and the check for batch inner transactions do not appear to break any existing functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for direct calls to sign() function with potential batch inner transactions
rg -t python 'sign\s*\([^)]*Batch' --glob '!xrpl/asyncio/transaction/main.py'

Length of output: 110


Script:

# 
#!/bin/bash
# Search for direct calls to sign() function with potential batch inner transactions
rg -t py 'sign\s*\([^)]*Batch' --glob '!xrpl/asyncio/transaction/main.py'

Length of output: 75


Script:

# 
#!/bin/bash
# Search for direct calls to sign() function with any usage of Batch in arguments
rg -t py 'sign\s*\(.*Batch.*\)' --glob '!xrpl/asyncio/transaction/main.py'

Length of output: 76

@mvadari mvadari marked this pull request as draft October 10, 2024 02:19
@mvadari
Copy link
Collaborator Author
mvadari commented Oct 10, 2024

cc @dangell7 @tequdev

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
CHANGELOG.md (2)

10-13: Unify bullet punctuation and improve terminology
The “Added” bullets are inconsistent: the 3rd entry ends with a period, while the others do not. Also, expand “param” to “parameter” for clarity.

Apply this diff:

@@ -10-13
- ### Added
- - Improved validation for models to also check param types
- - Support for `Account Permission` and `Account Permission Delegation` (XLS-74d, XLS-75d)
- - Support for the `Batch` amendment (XLS-56d).
+ ### Added
+ - Improved validation for models to also check parameter types
+ - Support for `Account Permission` and `Account Permission Delegation` (XLS-74d, XLS-75d)
+ - Support for the `Batch` amendment (XLS-56d)

16-22: Unify bullet punctuation in “Fixed” section
The first bullet under “Fixed” lacks a trailing period, while subsequent entries include one. Add a period to maintain consistency.

Apply this diff:

@@ -16
- - Add `MPTCurrency` support in `Issue` (rippled internal type)
+ - Add `MPTCurrency` support in `Issue` (rippled internal type).
🧰 Tools
🪛 LanguageTool

[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ... extracting sequence number. - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bac28c0 and 2496176.

📒 Files selected for processing (1)
  • CHANGELOG.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ... extracting sequence number. - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Integration test (3.8)

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
xrpl/transaction/batch_signers.py (1)

122-134: Consider adding a clarifying comment for the filtering logic.

The function correctly aggregates signers and filters out the submitter's signature. However, the logic at line 128 that uses transactions[0].account as the submitter might benefit from a comment explaining this assumption.

 def _get_batch_with_all_signers(transactions: List[Batch]) -> Batch:
+    # Collect all batch signers except the submitter's own signature.
+    # The submitter is identified as the account field of the first transaction.
     batch_signers = [
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2496176 and cd03c6f.

📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • xrpl/core/binarycodec/main.py (3 hunks)
  • xrpl/transaction/batch_signers.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • xrpl/core/binarycodec/main.py
🧰 Additional context used
🪛 Pylint (3.3.7)
xrpl/transaction/batch_signers.py

[error] 106-106: Instance of 'BaseModel' has no 'to_xrpl' member

(E1101)

🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Integration test (3.8)
🔇 Additional comments (4)
xrpl/transaction/batch_signers.py (3)

1-13: LGTM!

Well-structured module with clear purpose and appropriate imports.


15-62: Well-implemented batch signing function.

The function correctly validates that the signing wallet is involved in the batch, properly normalizes flags using _flags_to_int(), and handles both single-sign and multisign modes appropriately.


109-119: Validation logic looks good.

The equivalence check correctly ensures all batch transactions have identical flags and raw transactions, which is essential for safe combining of batch signers.

CHANGELOG.md (1)

10-22: Changelog updates are well-organized.

The changes properly document the new Batch amendment support and related fixes. The reorganization with "Added" section before "Fixed" follows changelog best practices.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

xrpl/transaction/batch_signers.py Show resolved Hide resolved
Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
xrpl/models/transactions/batch.py (1)

77-101: Consider defensive programming for flag handling

The __post_init__ method assumes that when flags is a dict, it can be modified by setting ["TF_INNER_BATCH_TXN"]. However, this could potentially overwrite existing flag values if there are naming conflicts.

Consider validating that the flag isn't already set in dict form before adding it:

                elif isinstance(tx_dict["flags"], dict):
-                    tx_dict["flags"]["TF_INNER_BATCH_TXN"] = True
+                    if "TF_INNER_BATCH_TXN" not in tx_dict["flags"]:
+                        tx_dict["flags"]["TF_INNER_BATCH_TXN"] = True
tests/unit/models/transactions/test_batch.py (1)

30-41: Consider expanding test coverage

While the minimum transaction count test is good, consider adding tests for:

  • Edge cases with different flag formats (dict, list, None)
  • Batch with pre-signed transactions (should fail)
  • Nested batch transactions (should fail)

Would you like me to generate additional test cases to improve coverage of the edge cases mentioned above?

xrpl/asyncio/transaction/main.py (1)

319-319: Simplify nested conditional logic

The static analysis tool correctly identifies that the nested if statements can be simplified for better readability.

-    if client.network_id is not None and client.network_id > _RESTRICTED_NETWORKS:
+    if (client.network_id is not None 
+        and client.network_id > _RESTRICTED_NETWORKS):

However, the current logic is actually correct as-is since we need to check both conditions. The static analysis suggestion might not be appropriate here given the specific business logic requirements.

🧰 Tools
🪛 Ruff (0.11.9)

319-322: Use a single if statement instead of nested if statements

(SIM102)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd03c6f and fa78532.

📒 Files selected for processing (7)
  • .ci-config/rippled.cfg (1 hunks)
  • CHANGELOG.md (1 hunks)
  • tests/unit/core/binarycodec/test_main.py (2 hunks)
  • tests/unit/models/transactions/test_batch.py (1 hunks)
  • xrpl/asyncio/transaction/main.py (13 hunks)
  • xrpl/models/transactions/batch.py (1 hunks)
  • xrpl/transaction/main.py (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/unit/core/binarycodec/test_main.py
  • .ci-config/rippled.cfg
  • xrpl/transaction/main.py
🧰 Additional context used
🪛 Ruff (0.11.9)
xrpl/asyncio/transaction/main.py

319-322: Use a single if statement instead of nested if statements

(SIM102)


555-555: Function definition does not bind loop variable raw_txn_dict

(B023)


556-556: Function definition does not bind loop variable raw_txn_dict

(B023)


557-557: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)
xrpl/asyncio/transaction/main.py

[error] 529-529: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 530-530: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 530-530: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 533-533: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~21-~21: The preposition ‘to’ seems more likely in this position.
Context: ...est.from_dict- Improve error handling foramm_info` - Handle autofilling better ...

(AI_HYDRA_LEO_REPLACE_FOR_TO)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Integration test (3.9)
🔇 Additional comments (6)
xrpl/models/transactions/batch.py (1)

130-137: LGTM: Clean handling of nested transaction structure

The from_dict method correctly handles the nested raw_transaction structure that comes from the XRPL format while maintaining backward compatibility with direct transaction objects.

tests/unit/models/transactions/test_batch.py (1)

10-28: LGTM: Good coverage of basic batch functionality

The test correctly verifies that the TF_INNER_BATCH_TXN flag is automatically added to inner transactions and that the batch validates successfully.

xrpl/asyncio/transaction/main.py (2)

413-413: LGTM: Correct fix for address conversion

The fix correctly extracts only the classic address from the tuple returned by xaddress_to_classic_address, preventing potential issues with tag and test flag values.


525-585: Good implementation of batch autofill logic

The _autofill_batch function properly handles the complex requirements for batch transactions:

  • Prevents nested batches
  • Manages sequence numbers per account
  • Validates required field values
  • Prevents pre-signed transactions
🧰 Tools
🪛 Ruff (0.11.9)

555-555: Function definition does not bind loop variable raw_txn_dict

(B023)


556-556: Function definition does not bind loop variable raw_txn_dict

(B023)


557-557: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)

[error] 529-529: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 530-530: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 530-530: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 533-533: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

CHANGELOG.md (2)

13-13: LGTM: Accurate documentation of new feature

The changelog entry correctly documents the addition of Batch amendment support (XLS-56d) which aligns with the comprehensive implementation across the codebase.


15-24: Good organization of changelog entries

The reorganization of the Fixed section with clear bullet points improves readability and properly documents the various improvements made alongside the batch transaction feature.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~21-~21: The preposition ‘to’ seems more likely in this position.
Context: ...est.from_dict- Improve error handling foramm_info` - Handle autofilling better ...

(AI_HYDRA_LEO_REPLACE_FOR_TO)

Comment on lines +554 to +561
def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
if field_name not in raw_txn_dict:
raw_txn_dict[field_name] = expected_value
elif raw_txn_dict[field_name] != expected_value:
raise XRPLException(
f"Must have a `{field_name}` of {repr(expected_value)} in an "
"inner Batch transaction."
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix function closure issue with loop variable

The static analysis correctly identifies that the nested _validate_field function doesn't properly capture the loop variable raw_txn_dict. This could lead to unexpected behavior.

Move the function definition outside the loop or pass the dictionary as a parameter:

+    def _validate_field(txn_dict: Dict[str, Any], field_name: str, expected_value: Union[str, None]) -> None:
+        if field_name not in txn_dict:
+            txn_dict[field_name] = expected_value
+        elif txn_dict[field_name] != expected_value:
+            raise XRPLException(
+                f"Must have a `{field_name}` of {repr(expected_value)} in an "
+                "inner Batch transaction."
+            )
+
     for raw_txn in transaction.raw_transactions:
         raw_txn_dict = raw_txn.to_dict()
         # ... existing validation logic ...
-        def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
-            if field_name not in raw_txn_dict:
-                raw_txn_dict[field_name] = expected_value
-            elif raw_txn_dict[field_name] != expected_value:
-                raise XRPLException(
-                    f"Must have a `{field_name}` of {repr(expected_value)} in an "
-                    "inner Batch transaction."
-                )
         
-        _validate_field("fee", "0")
-        _validate_field("signing_pub_key", "")
-        _validate_field("txn_signature", None)
+        _validate_field(raw_txn_dict, "fee", "0")
+        _validate_field(raw_txn_dict, "signing_pub_key", "")
+        _validate_field(raw_txn_dict, "txn_signature", None)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
if field_name not in raw_txn_dict:
raw_txn_dict[field_name] = expected_value
elif raw_txn_dict[field_name] != expected_value:
raise XRPLException(
f"Must have a `{field_name}` of {repr(expected_value)} in an "
"inner Batch transaction."
)
def _validate_field(txn_dict: Dict[str, Any], field_name: str, expected_value: Union[str, None]) -> None:
if field_name not in txn_dict:
txn_dict[field_name] = expected_value
elif txn_dict[field_name] != expected_value:
raise XRPLException(
f"Must have a `{field_name}` of {repr(expected_value)} in an "
"inner Batch transaction."
)
for raw_txn in transaction.raw_transactions:
raw_txn_dict = raw_txn.to_dict()
# ... existing validation logic ...
_validate_field(raw_txn_dict, "fee", "0")
_validate_field(raw_txn_dict, "signing_pub_key", "")
_validate_field(raw_txn_dict, "txn_signature", None)
🧰 Tools
🪛 Ruff (0.11.9)

555-555: Function definition does not bind loop variable raw_txn_dict

(B023)


556-556: Function definition does not bind loop variable raw_txn_dict

(B023)


557-557: Function definition does not bind loop variable raw_txn_dict

(B023)

🤖 Prompt for AI Agents
In xrpl/asyncio/transaction/main.py around lines 554 to 561, the nested function
_validate_field improperly closes over the loop variable raw_txn_dict, which can
cause incorrect behavior. To fix this, refactor _validate_field to accept
raw_txn_dict as an explicit parameter instead of relying on closure, or move the
function definition outside the loop so it does not capture the loop variable.
This ensures the function uses the correct dictionary instance each time it is
called.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
xrpl/asyncio/transaction/main.py (1)

558-565: ⚠️ Potential issue

Fix function closure issue with loop variable

The nested _validate_field function captures raw_txn_dict from the loop, which could lead to incorrect behavior. Move the function outside the loop or pass the dictionary as a parameter:

-        # validate fields that are supposed to be empty/zeroed
-        def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
-            if field_name not in raw_txn_dict:
-                raw_txn_dict[field_name] = expected_value
-            elif raw_txn_dict[field_name] != expected_value:
-                raise XRPLException(
-                    f"Must have a `{field_name}` of {repr(expected_value)} in an "
-                    "inner Batch transaction."
-                )
-
-        _validate_field("fee", "0")
-        _validate_field("signing_pub_key", "")
-        _validate_field("txn_signature", None)
+        # validate fields that are supposed to be empty/zeroed
+        def _validate_field(
+            txn_dict: Dict[str, Any], 
+            field_name: str, 
+            expected_value: Union[str, None]
+        ) -> None:
+            if field_name not in txn_dict:
+                txn_dict[field_name] = expected_value
+            elif txn_dict[field_name] != expected_value:
+                raise XRPLException(
+                    f"Must have a `{field_name}` of {repr(expected_value)} in an "
+                    "inner Batch transaction."
+                )
+
+        _validate_field(raw_txn_dict, "fee", "0")
+        _validate_field(raw_txn_dict, "signing_pub_key", "")
+        _validate_field(raw_txn_dict, "txn_signature", None)
🧰 Tools
🪛 Ruff (0.11.9)

559-559: Function definition does not bind loop variable raw_txn_dict

(B023)


560-560: Function definition does not bind loop variable raw_txn_dict

(B023)


561-561: Function definition does not bind loop variable raw_txn_dict

(B023)

🧹 Nitpick comments (5)
xrpl/asyncio/transaction/main.py (2)

319-322: Simplify nested if statements

The logic is correct, but can be simplified by combining the conditions:

-    if client.network_id is not None and client.network_id > _RESTRICTED_NETWORKS:
-        if client.build_version and _is_not_later_rippled_version(
-            _REQUIRED_NETWORKID_VERSION, client.build_version
-        ):
-            return True
+    if (client.network_id is not None 
+        and client.network_id > _RESTRICTED_NETWORKS
+        and client.build_version 
+        and _is_not_later_rippled_version(_REQUIRED_NETWORKID_VERSION, client.build_version)):
+        return True
🧰 Tools
🪛 Ruff (0.11.9)

319-322: Use a single if statement instead of nested if statements

(SIM102)


506-514: Optimize batch fee calculation with generator expression

The fee calculation correctly follows the specification. Consider using a generator expression for better memory efficiency:

-        base_fee = base_fee * 2 + sum(
-            [
-                int(await _calculate_fee_per_transaction_type(raw_txn, client))
-                for raw_txn in batch.raw_transactions
-            ]
-        )
+        base_fee = base_fee * 2 + sum(
+            int(await _calculate_fee_per_transaction_type(raw_txn, client))
+            for raw_txn in batch.raw_transactions
+        )
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 508-513: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)

xrpl/models/transactions/batch.py (3)

99-101: Include actual type in error message

The error message could be more helpful by including the actual type that was encountered.

                 else:
                     raise XRPLModelException(
-                        "Invalid `flags` ty
2684
pe for raw transaction in Batch."
+                        f"Invalid `flags` type for raw transaction in Batch: {type(tx_dict['flags'])}."
                     )

112-117: Use enumerate for more Pythonic iteration

Consider using enumerate instead of range(len()) for cleaner iteration.

-        for i in range(len(self.raw_transactions)):
-            tx = self.raw_transactions[i]
+        for i, tx in enumerate(self.raw_transactions):

83-102: Consider extracting flag handling logic

The logic for ensuring the TF_INNER_BATCH_TXN flag is complex and handles multiple cases. Consider extracting this into a helper method for better maintainability and reusability.

def _ensure_inner_batch_flag(tx_dict: Dict[str, Any]) -> Dict[str, Any]:
    """Ensure the transaction has the TF_INNER_BATCH_TXN flag set."""
    if "flags" not in tx_dict:
        tx_dict["flags"] = TransactionFlag.TF_INNER_BATCH_TXN
    elif isinstance(tx_dict["flags"], int):
        tx_dict["flags"] |= TransactionFlag.TF_INNER_BATCH_TXN
    elif isinstance(tx_dict["flags"], dict):
        tx_dict["flags"]["TF_INNER_BATCH_TXN"] = True
    elif isinstance(tx_dict["flags"], list):
        tx_dict["flags"].append(TransactionFlag.TF_INNER_BATCH_TXN)
    elif tx_dict["flags"] is None:
        tx_dict["flags"] = TransactionFlag.TF_INNER_BATCH_TXN
    else:
        raise XRPLModelException(
            f"Invalid `flags` type for raw transaction in Batch: {type(tx_dict['flags'])}."
        )
    return tx_dict
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa78532 and e1dc2b0.

📒 Files selected for processing (2)
  • xrpl/asyncio/transaction/main.py (14 hunks)
  • xrpl/models/transactions/batch.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
xrpl/asyncio/transaction/main.py (1)
Learnt from: ckeshava
PR: XRPLF/xrpl-py#757
File: xrpl/asyncio/transaction/main.py:505-509
Timestamp: 2025-06-05T20:52:31.065Z
Learning: The correct fee calculation for XRPL Batch transactions follows the C++ rippled implementation structure: (2 × base_fee) + sum of individual inner transaction fees + (signer_count × base_fee). Each inner transaction's fee should be calculated individually using the same fee calculation logic as standalone transactions, not assumed to be equal to base_fee.
🪛 Ruff (0.11.9)
xrpl/asyncio/transaction/main.py

319-322: Use a single if statement instead of nested if statements

(SIM102)


559-559: Function definition does not bind loop variable raw_txn_dict

(B023)


560-560: Function definition does not bind loop variable raw_txn_dict

(B023)


561-561: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)
xrpl/asyncio/transaction/main.py

[refactor] 508-513: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)


[error] 533-533: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 534-534: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 534-534: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 537-537: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

🔇 Additional comments (7)
xrpl/asyncio/transaction/main.py (5)

42-42: Good use of TypeVar for better type safety

The generic type variable T properly constrains to Transaction and provides type safety for functions that preserve the specific transaction type.


80-124: Improved sign() function with better type safety and structure

The refactoring properly:

  • Uses generics to preserve transaction type
  • Delegates transaction preparation to _prepare_transaction
  • Fixes the multisign structure to use dictionaries
  • Correctly assigns SigningPubKey for non-multisigned transactions

223-242: Proper validation to prevent signing of inner batch transactions

The function correctly prevents direct signing of inner batch transactions, which is essential for batch transaction security. The simplified signature without the wallet parameter is cleaner.


260-304: Well-structured autofill() with batch transaction support

The function properly:

  • Uses generics to preserve transaction type
  • Correctly handles ticket sequences by setting sequence to 0
  • Delegates batch transaction autofilling to a specialized helper function

413-413: Fixed extraction of classic address from tuple

Good fix - correctly extracts only the classic address from the tuple returned by xaddress_to_classic_address.

xrpl/models/transactions/batch.py (2)

24-37: Well-designed flag enumeration

The BatchFlag enum correctly uses distinct bit positions for each flag, enabling proper bitwise operations. The naming convention follows the established pattern.


122-159: Clean implementation of serialization/deserialization

The from_dict and to_dict methods correctly handle the wrapping/unwrapping of the raw_transaction field, maintaining consistency with the expected wire format.

The dictionary representation of a Batch.
"""
tx_dict = super().to_dict()
tx_dict["raw_transactions"] = [
Copy link
Collaborator

Choose a reason for hiding this comment

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

Help me understand this question: Why are you manually unpacking/packing the RawTransactions field? There are other "inner-object" (in rippled parlance)/ NestedModel fields which do not have this special code in their from_dict and to_dict method definitions. (AuthAccount, BatchSigner are two examples).

Aren't inner-objects handled by the JSON library automatically? Do we need to spell out arbitrary depth nesting of the JSON object structure?

(The below structure is my mental model of the RawTransactions STArray inner object)

RawTransactions: [
    {
      RawTransaction: {
        TransactionType: "OfferCreate",
        ...
      }
    },
    {
      RawTransaction: {
        TransactionType: "Payment",
        ...
      }
    },
  ]

Copy link
Collaborator Author
@mvadari mvadari Jun 6, 2025

Choose a reason for hiding this comment

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

Note that RawTransactions is a list of Transactions, and Transaction does not inherit from NestedModel. We could theoretically have a model called RawTransaction that just has a Transaction field, but that's much less user-friendly IMO, so instead we have to do the nesting in the Batch class. If you take a look at the NestedModel class, you'll see the code handling it is pretty similar.

Copy link
Collaborator

Choose a reason for hiding this comment

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

You could have implemented this idea by making use of NestedModel.

class RawTransaction(NestedModel):
    raw_transaction: Transaction = REQUIRED # type: ignore

class Batch(Transaction):
    """Represents a Batch transaction."""

    raw_transactions: List[RawTransaction] = REQUIRED  # type: ignore
    # instead of the current design
    # raw_transactions: List[Transaction] = REQUIRED  # type: ignore
    
    # rest of the code

I don't see how this lessens the user-experience. As a bonus, you wouldn't have had to unpack/pack the raw-transactions yourself.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I could have, but now every Batch looks like this:

Batch(account="r...", 
    raw_transactions=[
        RawTransaction(Payment(account="r...", ...)),
        RawTransaction(AccountSet(account="r...", ...)),
    ]
)

This is much weirder/trickier to use, instead of just having a list of transactions, which is how I would want to use it. Users don't have to do any additional work with the existing solution anyways, it "magically" works because of the additional NestedModel-esque code.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
xrpl/asyncio/transaction/main.py (1)

565-572: ⚠️ Potential issue

Fix function closure issue with loop variable.

The static analysis correctly identifies that the nested _validate_field function doesn't properly capture the loop variable raw_txn_dict. This has been flagged in previous reviews as well.

Move the function definition outside the loop or pass the dictionary as a parameter:

+    def _validate_field(txn_dict: Dict[str, Any], field_name: str, expected_value: Union[str, None]) -> None:
+        if field_name not in txn_dict:
+            txn_dict[field_name] = expected_value
+        elif txn_dict[field_name] != expected_value:
+            raise XRPLException(
+                f"Must have a `{field_name}` of {repr(expected_value)} in an "
+                "inner Batch transaction."
+            )
+
     for raw_txn in transaction.raw_transactions:
         raw_txn_dict = raw_txn.to_dict()
         # ... existing validation logic ...
-        def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
-            if field_name not in raw_txn_dict:
-                raw_txn_dict[field_name] = expected_value
-            elif raw_txn_dict[field_name] != expected_value:
-                raise XRPLException(
-                    f"Must have a `{field_name}` of {repr(expected_value)} in an "
-                    "inner Batch transaction."
-                )
         
-        _validate_field("fee", "0")
-        _validate_field("signing_pub_key", "")
-        _validate_field("txn_signature", None)
+        _validate_field(raw_txn_dict, "fee", "0")
+        _validate_field(raw_txn_dict, "signing_pub_key", "")
+        _validate_field(raw_txn_dict, "txn_signature", None)
🧰 Tools
🪛 Ruff (0.11.9)

566-566: Function definition does not bind loop variable raw_txn_dict

(B023)


567-567: Function definition does not bind loop variable raw_txn_dict

(B023)


568-568: Function definition does not bind loop variable raw_txn_dict

(B023)

🧹 Nitpick comments (1)
xrpl/asyncio/transaction/main.py (1)

319-319: Consider simplifying nested if statements.

The static analysis correctly suggests combining the nested if statements for better readability.

-    if client.network_id is not None and client.network_id > _RESTRICTED_NETWORKS:
-        if client.build_version and _is_not_later_rippled_version(
-            _REQUIRED_NETWORKID_VERSION, client.build_version
-        ):
-            return True
+    if (client.network_id is not None 
+        and client.network_id > _RESTRICTED_NETWORKS 
+        and client.build_version 
+        and _is_not_later_rippled_version(_REQUIRED_NETWORKID_VERSION, client.build_version)):
+        return True
🧰 Tools
🪛 Ruff (0.11.9)

319-322: Use a single if statement instead of nested if statements

(SIM102)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1dc2b0 and 341d91a.

📒 Files selected for processing (4)
  • CHANGELOG.md (1 hunks)
  • tests/integration/transactions/test_batch.py (1 hunks)
  • xrpl/asyncio/transaction/main.py (15 hunks)
  • xrpl/models/transactions/batch.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/integration/transactions/test_batch.py
  • xrpl/models/transactions/batch.py
🧰 Additional context used
🧠 Learnings (1)
xrpl/asyncio/transaction/main.py (1)
Learnt from: ckeshava
PR: XRPLF/xrpl-py#757
File: xrpl/asyncio/transaction/main.py:505-509
Timestamp: 2025-06-05T20:52:31.065Z
Learning: The correct fee calculation for XRPL Batch transactions follows the C++ rippled implementation structure: (2 × base_fee) + sum of individual inner transaction fees + (signer_count × base_fee). Each inner transaction's fee should be calculated individually using the same fee calculation logic as standalone transactions, not assumed to be equal to base_fee.
🪛 Ruff (0.11.9)
xrpl/asyncio/transaction/main.py

319-322: Use a single if statement instead of nested if statements

(SIM102)


566-566: Function definition does not bind loop variable raw_txn_dict

(B023)


567-567: Function definition does not bind loop variable raw_txn_dict

(B023)


568-568: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)
xrpl/asyncio/transaction/main.py

[refactor] 512-517: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)


[error] 540-540: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 544-544: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Integration test (3.8)
🔇 Additional comments (7)
xrpl/asyncio/transaction/main.py (6)

4-6: Generic typing implementation looks good.

The addition of TypeVar T bound to Transaction is well-implemented and will help preserve transaction subtype information through the transformation functions.

Also applies to: 42-42


240-242: Good validation for preventing direct signing of batch inner transactions.

The check for TF_INNER_BATCH_TXN flag correctly prevents direct signing of batch inner transactions, which aligns with the batch transaction specification.


413-413: Correct fix for X-address conversion.

The update to extract only the classic address from the tuple returned by xaddress_to_classic_address is correct and fixes a potential bug.


510-518: Verify batch fee calculation matches specification.

Based on the retrieved learning, the fee calculation has been updated to follow the C++ rippled implementation structure. The current implementation calculates individual fees for each inner transaction and applies the correct base fee multiplier.

Note: This addresses the previously discussed fee calculation concerns by properly calculating fees for each inner transaction rather than assuming they equal the base fee.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 512-517: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)


536-596: Comprehensive batch autofill implementation.

The _autofill_batch function provides thorough handling of inner transaction autofilling with proper validation for:

  • Nested batch transaction prevention
  • Sequence number management per account
  • Signature validation
  • Required field enforcement

The implementation correctly enforces batch transaction constraints as specified in XLS-56d.

🧰 Tools
🪛 Ruff (0.11.9)

566-566: Function definition does not bind loop variable raw_txn_dict

(B023)


567-567: Function definition does not bind loop variable raw_txn_dict

(B023)


568-568: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)

[error] 540-540: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 544-544: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)


96-123:

❓ Verification inconclusive

Verify the multisign dictionary structure matches expected format.

The multisign logic has been updated to use a dictionary structure instead of the previous Signer model. Please ensure this new structure matches the expected XRPL transaction format for multisigned transactions.


🏁 Script executed:

#!/bin/bash
# Description: Check if the new multisign dictionary structure is used consistently across the codebase

# Search for other multisign implementations to verify consistency
rg -A 5 -B 5 "Signers.*Signer.*Account" --type py

Length of output: 51


Let’s compare against the synchronous implementation to confirm the exact Signers shape:


🏁 Script executed:

#!/bin/bash
# Find synchronous transaction main.py under xrpl/transaction (exclude asyncio)
files=$(fd -t f "^main.py$" xrpl/transaction)
sync_file=$(echo "$files" | grep -v "asyncio" | head -n1)

if [[ -z "$sync_file" ]]; then
  echo "⚠️ Synchronous main.py not found under xrpl/transaction"
  exit 0
fi

echo "🔍 Inspecting synchronous file: $sync_file"

echo -e "\n--- Around multisign logic ---"
rg -n -C5 "if multisign" "$sync_file" || echo "No multisign block found"

echo -e "\n--- ‘Signers’ usage ---"
rg -n -C5 '"Signers"' "$sync_file" || echo "No Signers key usage found"

Length of output: 695


Action Required: Confirm Multisign Signers Structure

We weren’t able to locate any other multisign implementations in the sync codebase to compare against. Please double-check that the new structure in xrpl/asyncio/transaction/main.py (lines 96–123):

transaction_json["Signers"] = [
  {
    "Signer": {
      "Account": wallet.address,
      "TxnSignature": signature,
      "SigningPubKey": wallet.public_key,
    }
  }
]

• Matches the official XRPL multisign format (an array of objects, each with a single Signer key containing Account, TxnSignature, and SigningPubKey).
• Is correctly handled end-to-end (serialization, signing, deserialization).
• Aligns with any existing tests or examples in your codebase.

If you haven’t already, please compare against the XRPL Transaction Format docs to ensure full compatibility.

CHANGELOG.md (1)

13-25: Changelog accurately documents batch transaction support and related improvements.

The changelog correctly documents the addition of Batch amendment support (XLS-56d) and the related fixes for multisigning, typing improvements, and TicketSequence handling. The reorganization to separate Added and Fixed sections improves readability.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

# BaseFee × (1 + Number of Signatures Provided)
if signers_count is not None and signers_count > 0:
base_fee += net_fee * (1 + signers_count)
if transaction.transaction_type == TransactionType.BATCH:
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is a mismatch between the fee-calculations in the xrpl-py implementation and that of xrpl.js. Here is a snapshot:

image

The xrpl.js implementation does not have this transaction-type based discretion of net_fee * signers_count versus net_fee * (1 + signers_count).

Furthermore, the current implementation does not match the rippled cpp code.
image

I would expect to iterate over all the entries in the BatchSigners list to accurately compute the fees.

I understand that autofill does not have access to the signatures and hence cannot precisely calculate this fee. Should we put out a disclaimer that the client libraries do not match the rippled node in the fee expectations?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. Turns out that both are wrong and it should just be just + base_fee * signersCount in both places - this has been fixed (and tested with integration tests).
  2. rippled sees the transactions after they have been signed. This isn't comparable. The libraries see the transactions before they have been signed, so some parts of the transaction aren't available yet. The same process is done for regular multisign.

Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. Turns out that both are wrong
    OK

  2. It would be helpful to document the differences in fee-calculation between the client libraries and rippled nodes. Users should be aware of this quirk. This is useful for debugging erroring Batch transactions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I updated the docs around autofill to call it out.

The dictionary representation of a Batch.
"""
tx_dict = super().to_dict()
tx_dict["raw_transactions"] = [
Copy link
Collaborator

Choose a reason for hiding this comment

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

You could have implemented this idea by making use of NestedModel.

class RawTransaction(NestedModel):
    raw_transaction: Transaction = REQUIRED # type: ignore

class Batch(Transaction):
    """Represents a Batch transaction."""

    raw_transactions: List[RawTransaction] = REQUIRED  # type: ignore
    # instead of the current design
    # raw_transactions: List[Transaction] = REQUIRED  # type: ignore
    
    # rest of the code

I don't see how this lessens the user-experience. As a bonus, you wouldn't have had to unpack/pack the raw-transactions yourself.

@ckeshava
Copy link
Collaborator
ckeshava commented Jun 6, 2025

@mvadari I only have one concern left that needs to be addressed. Apart from that, this PR looks good.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
xrpl/asyncio/transaction/main.py (1)

562-573: ⚠️ Potential issue

Fix function closure issue with loop variable.

The static analysis correctly identifies that the nested _validate_field function doesn't properly capture the loop variable raw_txn_dict. This could lead to unexpected behavior.

Move the function definition outside the loop or pass the dictionary as a parameter:

+    def _validate_field(txn_dict: Dict[str, Any], field_name: str, expected_value: Union[str, None]) -> None:
+        if field_name not in txn_dict:
+            txn_dict[field_name] = expected_value
+        elif txn_dict[field_name] != expected_value:
+            raise XRPLException(
+                f"Must have a `{field_name}` of {repr(expected_value)} in an "
+                "inner Batch transaction."
+            )
+
     for raw_txn in transaction.raw_transactions:
         raw_txn_dict = raw_txn.to_dict()
         # ... existing validation logic ...
-        def _validate_field(field_name: str, expected_value: Union[str, None]) -> None:
-            if field_name not in raw_txn_dict:
-                raw_txn_dict[field_name] = expected_value
-            elif raw_txn_dict[field_name] != expected_value:
-                raise XRPLException(
-                    f"Must have a `{field_name}` of {repr(expected_value)} in an "
-                    "inner Batch transaction."
-                )
         
-        _validate_field("fee", "0")
-        _validate_field("signing_pub_key", "")
-        _validate_field("txn_signature", None)
+        _validate_field(raw_txn_dict, "fee", "0")
+        _validate_field(raw_txn_dict, "signing_pub_key", "")
+        _validate_field(raw_txn_dict, "txn_signature", None)
🧰 Tools
🪛 Ruff (0.11.9)

563-563: Function definition does not bind loop variable raw_txn_dict

(B023)


564-564: Function definition does not bind loop variable raw_txn_dict

(B023)


565-565: Function definition does not bind loop variable raw_txn_dict

(B023)

🧹 Nitpick comments (1)
xrpl/asyncio/transaction/main.py (1)

512-517: Consider using generator for performance optimization.

The static analysis correctly suggests using a generator expression instead of a list comprehension for better memory efficiency.

-        base_fee = base_fee * 2 + sum(
-            [
-                int(await _calculate_fee_per_transaction_type(raw_txn, client))
-                for raw_txn in batch.raw_transactions
-            ]
-        )
+        base_fee = base_fee * 2 + sum(
+            int(await _calculate_fee_per_transaction_type(raw_txn, client))
+            for raw_txn in batch.raw_transactions
+        )
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 512-517: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 341d91a and a144e60.

📒 Files selected for processing (2)
  • CHANGELOG.md (1 hunks)
  • xrpl/asyncio/transaction/main.py (15 hunks)
🧰 Additional context used
🧠 Learnings (1)
xrpl/asyncio/transaction/main.py (1)
Learnt from: ckeshava
PR: XRPLF/xrpl-py#757
File: xrpl/asyncio/transaction/main.py:505-509
Timestamp: 2025-06-05T20:52:31.065Z
Learning: The correct fee calculation for XRPL Batch transactions follows the C++ rippled implementation structure: (2 × base_fee) + sum of individual inner transaction fees + (signer_count × base_fee). Each inner transaction's fee should be calculated individually using the same fee calculation logic as standalone transactions, not assumed to be equal to base_fee.
🪛 Ruff (0.11.9)
xrpl/asyncio/transaction/main.py

319-322: Use a single if statement instead of nested if statements

(SIM102)


563-563: Function definition does not bind loop variable raw_txn_dict

(B023)


564-564: Function definition does not bind loop variable raw_txn_dict

(B023)


565-565: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)
xrpl/asyncio/transaction/main.py

[refactor] 512-517: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)


[error] 537-537: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 538-538: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 538-538: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

🪛 LanguageTool
CHANGELOG.md

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Integration test (3.12)
  • GitHub Check: Integration test (3.10)
  • GitHub Check: Integration test (3.11)
  • GitHub Check: Integration test (3.8)
  • GitHub Check: Integration test (3.13)
  • GitHub Check: Integration test (3.9)
🔇 Additional comments (10)
xrpl/asyncio/transaction/main.py (8)

42-42: LGTM: Well-structured generic type variable.

The generic type variable follows Python typing best practices and provides better type safety for transaction-related functions.


80-84: Excellent typing improvements with generic bounds.

The addition of generic type variable T bound to Transaction significantly improves type safety and developer experience across sign, autofill_and_sign, and autofill functions.

Also applies to: 126-132, 260-263


107-116: Approve updated multisign structure.

The change from the removed Signer model to a dictionary-based structure is correctly implemented and maintains compatibility with the XRPL multisign format.


240-242: Good safety check for batch inner transactions.

This validation correctly prevents direct signing of batch inner transactions, which aligns with the XRPL batch transaction specification.


285-292: Improved ticket sequence handling.

The enhanced logic properly handles the case where ticket_sequence is present by setting sequence to 0, which is the correct behavior for ticket-based transactions.


413-413: Fix X-address conversion extraction.

Correctly extracts only the classic address from the tuple returned by xaddress_to_classic_address.


510-518: Verify the batch fee calculation aligns with latest requirements.

The current implementation calculates (2 × base_fee) + sum of individual inner transaction fees, which aligns with the base structure discussed in past reviews. However, based on the retrieved learning, this should also include signer fees when signers_count is provided.

Please confirm that this implementation matches the expected behavior when signers_count is provided for batch transactions, as the multisign fee addition (lines 521-522) applies to all transaction types including batches.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 512-517: Consider using a generator instead 'sum(int(await _calculate_fee_per_transaction_type(raw_txn, client)) for raw_txn in batch.raw_transactions)'

(R1728)


533-593: Comprehensive batch autofill implementation.

The _autofill_batch function provides thorough validation and autofilling for batch inner transactions, including:

  • Sequence number management per account
  • Validation of required empty/zero fields
  • Network ID assignment
  • Proper error handling for invalid configurations

The logic correctly enforces batch transaction constraints.

🧰 Tools
🪛 Ruff (0.11.9)

563-563: Function definition does not bind loop variable raw_txn_dict

(B023)


564-564: Function definition does not bind loop variable raw_txn_dict

(B023)


565-565: Function definition does not bind loop variable raw_txn_dict

(B023)

🪛 Pylint (3.3.7)

[error] 537-537: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 538-538: Instance of 'BaseModel' has no 'account' member

(E1101)


[error] 538-538: Instance of 'BaseModel' has no 'sequence' member

(E1101)


[error] 541-541: Instance of 'BaseModel' has no 'raw_transactions' member

(E1101)

CHANGELOG.md (2)

13-13: Accurate documentation of batch amendment support.

The changelog entry correctly documents the new Batch amendment (XLS-56d) support, which aligns with the extensive code changes in this PR.


15-27: Well-organized changelog improvements.

The reorganized and expanded "Fixed" section comprehensively covers the various improvements made alongside the batch transaction feature, including autofilling, typing, and fee handling enhancements.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~17-~17: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...current" ledger for extracting sequence number - Increase default maximum payload size...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~18-~18: You might be missing the article “the” here.
Context: ...r extracting sequence number - Increase default maximum payload size for websocket clie...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

- Handle autofilling better when multisigning transactions
- Improve typing for transaction-related helper functions
- Improve handling of `TicketSequence`
- Fix issue with failing on a higher than expected fee
Copy link
Collaborator
7802

Choose a reason for hiding this comment

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

if you can explain the context of this CL entry, that will be helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

341d91a

Essentially, the max operator wasn't working properly since it was comparing strings, not numbers.

@mvadari mvadari merged commit cd6b7a2 into main Jun 6, 2025
16 checks passed
@mvadari mvadari deleted the batch branch June 6, 2025 21:26
LimpidCrypto pushed a commit to LimpidCrypto/xrpl-py that referenced this pull request Jun 7, 2025
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.

4 participants
0