Skip to content

Conversation

@Syn-McJ
Copy link
Member

@Syn-McJ Syn-McJ commented Mar 26, 2025

Issue being fixed or feature implemented

We still need to merge CoinJoin into master since it's been released. There were some CI errors that prevented merging, hopefully resolved now.

What was done?

  • Resolve CI errors

How Has This Been Tested?

Breaking Changes

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • Introduced enhanced CoinJoin mixing that improves transaction privacy by automatically grouping and mixing funds.
    • Wallet now supports dedicated CoinJoin addresses for receiving and change, optimizing user control over mixed transactions.
  • UI Updates

    • Added a new screen accessible from the actions menu for managing CoinJoin sessions.
    • Refined several interface layouts to streamline the user experience with CoinJoin features.

Syn-McJ added 30 commits January 4, 2024 17:37
feat(coinjoin): first steps for DashSync <-> DashSharedCore integration
feat(coinjoin): selectCoinsGroupedByAddresses
feat(coinjon): create_denominated callbacks
feat(coinjoin): refactor no prompt signing and availableCoins
fix(coinjoin): wait for denom tx to be published before making a collateral
chore(coinjoin): refactor some code into CoinJoinManager
feat(coinjoin): send message callbacks
fix: memory & lock issues in sortTransactions
fix: inform UI of a double spend transactions
@Syn-McJ Syn-McJ self-assigned this Mar 26, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2025

Walkthrough

This commit integrates a broad set of changes across the repository. It adds new CI steps in several GitHub Actions workflows to set up CocoaPods, upgrades dependencies in the podspec, and introduces extensive CoinJoin functionality. Many model, manager, and transaction classes have been enhanced or newly created to support CoinJoin operations, including new FFI methods, message classes, and wallet/address handling methods. UI components and storyboard files have also been updated to introduce a new CoinJoin view controller, while several test plans have been modified to skip specific CoinJoin session tests. Additionally, transaction serialization methods now support an extra “anyoneCanPay” parameter.

Changes

File(s) Change Summary
.github/workflows/{build,coverage,e2eTestsTestnet,lint,network,syncTestMainnet,syncTestTestnet,test}.yml Added a new job step “Setup CocoaPods” using maxim-lobanov/setup-cocoapods@v1 with version 1.15.2; minor formatting adjustments.
DashSync.podspec Upgraded dependency DashSharedCore from 0.4.19 to 0.5.1.
DashSync/shared/DashSync.m Inserted calls to DSCoinJoinManager in stopSyncAllChains and stopSyncForChain methods.
DashSync/shared/Libraries/DSLogger.m and DashSync/shared/Libraries/Logs/CompressingLogFileManager.{h,m} Replaced old logging mechanism with a new CompressingLogFileManager for log file compression and enhanced log file retrieval.
DashSync/shared/Models/Chain/{DSChain.m,DSChainConstants.h} Extended derivation paths in standardDerivationPathsForAccountNumber: (adding CoinJoin path) and updated bloom filter registration with CoinJoin gap limit; added constant COINBASE_MATURITY.
DashSync/shared/Models/CoinJoin/{DSCoinControl.{h,m}, DSCoinJoinBalance.{h,m}, DSCoinJoinManager.{h,m}, DSCoinJoinWrapper.{h,m}, DSCompactTallyItem.{h,m}, DSInputCoin.{h,m}, DSTransaction+CoinJoin.{h,m}, DSTransactionInput+CoinJoin.{h,m}, DSTransactionOutput+CoinJoin.{h,m}} Introduced a suite of new CoinJoin model classes and FFI methods to support coin control, balance management, coin join session handling, and memory management; added a new CoinJoin wrapper for bridging to Rust.
DashSync/shared/Models/Messages/CoinJoin/{DSCoinJoinAcceptMessage.{h,m}, DSCoinJoinEntryMessage.{h,m}, DSCoinJoinSignedInputs.{h,m}, DSSendCoinJoinQueue.{h,m}} Added new CoinJoin message classes and methods, replacing earlier Darksend message definitions.
DashSync/shared/Models/Transactions/{Base/*, Coinbase/*, Provider/*, Quorums/DSQuorumCommitmentTransaction.m} Updated transaction serialization and signing methods to include an extra anyoneCanPay parameter; new methods for payload data and size calculation added.
DashSync/shared/Models/Wallet/{DSAccount.{h,m}, DSWallet+Protected.h, DSWallet.{h,m}} Extended wallet and account classes with CoinJoin-specific derivation paths, new address getter methods, updated transaction signing (now accepting anyoneCanPay), and added methods for input value retrieval.
Example/{DashSync.xcodeproj/project.pbxproj, Actions.storyboard, Base.lproj/Main.storyboard, Contacts.storyboard, DSActionsViewController.m, DSCoinJoinViewController.{h,m}, DSTransactionsViewController.m} Introduced a new DSCoinJoinViewController and updated storyboards for CoinJoin UI; adjusted segues and layout; added new tests and modified test plans to skip CoinJoin session tests.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant VC as DSCoinJoinViewController
    participant Manager as DSCoinJoinManager
    participant MGroup as DSMasternodeGroup
    participant Wrapper as DSCoinJoinWrapper

    User->>VC: Toggle CoinJoin switch
    VC->>Manager: startCoinJoin()
    Manager->>MGroup: Initialize masternode connections
    Manager->>Wrapper: Configure mixing options and refresh keys
    Wrapper-->>Manager: Confirm mixing setup
    VC-->>User: Update UI status
Loading

Suggested reviewers

  • pankcuf

Poem

I'm a little rabbit, hopping through the code,
Seeing CoinJoin features in every node.
CocoaPods are set and logs compressed,
New views and tests keep our system blessed.
I hop with glee in digital delight,
Celebrating changes that run ever so right.
🐇🥕 Happy coding—let's keep it light!

✨ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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: 18

🔭 Outside diff range comments (1)
DashSync/shared/Models/Transactions/Quorums/DSQuorumCommitmentTransaction.m (1)

135-143: 💡 Verification agent

🧩 Analysis chain

Method signature correctly updated for CoinJoin compatibility

The toDataWithSubscriptIndex:anyoneCanPay: method implementation has been updated to include the new anyoneCanPay parameter, which is correctly passed to the superclass method.

It would be beneficial to verify that all classes that call this method have been updated to use the new signature:


🏁 Script executed:

#!/bin/bash
# Find all invocations of toDataWithSubscriptIndex: that might need updating
rg -A 2 "toDataWithSubscriptIndex:" --glob "*.m" | grep -v "anyoneCanPay"

Length of output: 5479


Action Required: Update Call Sites to Include the anyoneCanPay Parameter

The DSQuorumCommitmentTransaction implementation now correctly uses the updated method signature for CoinJoin compatibility by passing the anyoneCanPay parameter to the superclass. However, verification with the provided shell script shows that several other transaction classes still call the legacy version of toDataWithSubscriptIndex: without the new parameter. For example:

  • DashSync/shared/Models/Transactions/Coinbase/DSCoinbaseTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderRegistrationTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRegistrarTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRevocationTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateServiceTransaction.m
  • DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m
  • DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m

Please review these call sites and update them to include the anyoneCanPay argument as required, or provide a rationale if the legacy signature should be maintained.

🧹 Nitpick comments (74)
DashSync/shared/Models/Entities/DSFriendRequestEntity+CoreDataClass.m (1)

91-91: Clarify the TODO Comment

The added TODO comment (// TODO: MOCK_DASHPAY mixed only?) is ambiguous. Please clarify the intent behind this comment—whether it indicates a temporary workaround, a pending feature flag for "MOCK_DASHPAY," or something else. A more descriptive comment will help future maintainers understand when and how to address this placeholder.

Example/Tests/WalletTests.xctestplan (1)

26-26: Consider documenting rationale for skipped tests

The DSCoinJoinSessionTest is being systematically skipped across all test plans, including this one.

Consider adding a comment in the test file or documentation explaining why this test is skipped and under what conditions it should be re-enabled. This would help maintain testing quality in the future.

Example/Tests/TransactionTests.xctestplan (1)

26-26: Ensure test coverage through alternative means

While skipping DSCoinJoinSessionTest in all test plans may help resolve CI issues, it's important to ensure the CoinJoin functionality is tested through other means.

Since the CoinJoin feature appears to be a significant addition, I'd recommend creating a separate test plan specifically for CoinJoin tests that can be run manually or in a controlled environment if automated CI is problematic. Would you like me to provide a template for such a test plan?

Example/Tests/PlatformTransitionTests.xctestplan (1)

26-26: Consider documenting why DSCoinJoinSessionTest is being skipped

I see that DSCoinJoinSessionTest has been added to the skipped tests array. While this might be necessary to resolve CI errors as mentioned in the PR description, it would be helpful to add a comment or documentation explaining why this test is being skipped and whether there's a plan to enable it in the future.

Would you like me to suggest a format for documenting skipped tests in your test plans?

DashSync/shared/Models/Messages/CoinJoin/DSSendCoinJoinQueue.h (1)

22-28: Clean implementation of DSSendCoinJoinQueue class.

The class interface is minimal and follows good encapsulation principles with the read-only property. Consider adding documentation comments to explain the purpose of this class and what the send property represents in the context of CoinJoin operations.

 @interface DSSendCoinJoinQueue : DSMessageRequest
 
+/**
+ * Boolean indicating whether to send CoinJoin queue messages to peers.
+ */
 @property (nonatomic, readonly) BOOL send;
 
+/**
+ * Creates a new request with the specified send flag.
+ * @param shouldSend Whether to send CoinJoin queue messages.
+ * @return A new DSSendCoinJoinQueue instance.
+ */
 + (instancetype)requestWithShouldSend:(BOOL)shouldSend;
 
 @end
DashSync/shared/Models/CoinJoin/DSTransactionOutput+CoinJoin.h (1)

26-27: Looks good, but consider documenting memory management pattern

The FFI memory management methods are well-defined, following the malloc/free pattern. However, adding documentation comments would help clarify:

  • When these methods should be used
  • Who is responsible for calling ffi_free
  • What the ChainType parameter affects

Consider adding documentation comments like:

/**
 * Creates a TransactionOutput FFI object from this Objective-C instance.
 * @param type Chain type to use for serialization
 * @return Pointer to FFI struct that must be freed with ffi_free
 */
- (TransactionOutput *)ffi_malloc:(ChainType)type;

/**
 * Frees memory allocated for a TransactionOutput FFI object.
 * @param output Pointer to FFI struct to free
 */
+ (void)ffi_free:(TransactionOutput *)output;
Example/DashSync/DSActionsViewController.m (1)

41-43:

Details

❓ Verification inconclusive

Fix typo in the segue identifier: "CoinJoinSeque" should be "CoinJoinSegue"

There's a spelling error in the segue identifier. While this will work as long as the identifier in the storyboard has the same typo, it's better to correct it for consistency.

-    } else if ([segue.identifier isEqualToString:@"CoinJoinSeque"]) {
+    } else if ([segue.identifier isEqualToString:@"CoinJoinSegue"]) {

🏁 Script executed:

#!/bin/bash
# Check if there's a storyboard file with the same typo or the correct spelling
echo "Searching for storyboard files with CoinJoin segue..."
rg -l "CoinJoinSeque" --type=xml
rg -l "CoinJoinSegue" --type=xml

Length of output: 182


Action: Verify the CoinJoin segue identifier is consistent both in code and your storyboard.

The code in Example/DashSync/DSActionsViewController.m currently checks for @"CoinJoinSeque", which appears to be a typo. The proposed change is to update the identifier to @"CoinJoinSegue". However, our automated search in XML files did not return any references for either string, making it unclear if the storyboard segue identifier needs the same correction. Please manually verify that the storyboard is configured with the proper identifier (CoinJoinSegue) to ensure consistency and avoid runtime mismatches.

  • In Code: Update in Example/DashSync/DSActionsViewController.m

    -    } else if ([segue.identifier isEqualToString:@"CoinJoinSeque"]) {
    +    } else if ([segue.identifier isEqualToString:@"CoinJoinSegue"]) {
  • In Storyboard: Confirm that the segue’s identifier is set to CoinJoinSegue (or update it accordingly).

DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinEntryMessage.h (1)

23-29: Add documentation comments and consider implementing a common base class for CoinJoin messages

The implementation looks good, but I notice that DSCoinJoinEntryMessage and DSCoinJoinAcceptMessage have identical interfaces. This suggests potential code duplication in their implementations.

Consider:

  1. Adding documentation comments to explain the purpose of this message type:
/**
 * Represents a CoinJoin entry message sent during the initial phase of a CoinJoin session.
 * Contains serialized data related to the CoinJoin entry proposal.
 */
  1. Creating a common base class for CoinJoin message types to reduce duplication:
/**
 * Base class for CoinJoin-specific message types.
 */
@interface DSCoinJoinBaseMessage : DSMessageRequest

@property (nonatomic, readonly) NSData *data;

+ (instancetype)requestWithData:(NSData *)data;

@end

Then have DSCoinJoinEntryMessage and other similar classes inherit from this base class, only needing to implement the +type method.

DashSync/shared/Libraries/Logs/CompressingLogFileManager.h (1)

1-20: Overall implementation looks good, consider adding documentation

The CompressingLogFileManager class is properly designed as a subclass of DDLogFileManagerDefault with appropriate properties and initialization method. This will help manage log file sizes through compression.

Consider adding class and property documentation comments to explain:

  1. The purpose of this class (compressing log files when they reach a certain size)
  2. The role of the upToDate and isCompressing instance variables
  3. How the maxFileSize property affects compression behavior

Example documentation:

+/**
+ * A log file manager that automatically compresses log files when they reach a specified size.
+ * Extends DDLogFileManagerDefault with compression capabilities.
+ */
 @interface CompressingLogFileManager : DDLogFileManagerDefault
 {
+    // Tracks whether all files have been processed for compression
     BOOL upToDate;
+    // Flag indicating if compression is currently in progress
     BOOL isCompressing;
 }

+/**
+ * The maximum size (in bytes) a log file can reach before being compressed.
+ */
 @property (nonatomic, assign) unsigned long long maxFileSize;
DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinSignedInputs.h (1)

1-32: Implementation looks good, consider adding parameter documentation

The DSCoinJoinSignedInputs class is well-structured as a subclass of DSMessageRequest with appropriate properties and methods for the CoinJoin feature. The use of NS_ASSUME_NONNULL_BEGIN/END for nullability annotations is correct.

Consider adding documentation comments for the class and methods to explain:

+/**
+ * Represents signed inputs for a CoinJoin transaction.
+ * Used to communicate input signatures between participants in a CoinJoin session.
+ */
 @interface DSCoinJoinSignedInputs : DSMessageRequest

 @property (nonatomic, readonly) NSData *data;

+/**
+ * Creates a request with the provided signed input data.
+ * @param data The signed input data for the CoinJoin transaction.
+ * @return A new DSCoinJoinSignedInputs instance.
+ */
 + (instancetype)requestWithData:(NSData *)data;
+/**
+ * Returns the message type string identifier.
+ * @return The string representing this message type.
+ */
 + (NSString *)type;
DashSync/shared/Models/Managers/Chain Managers/DSMasternodeManager.h (1)

71-71: Good API extension, but consider updating related method

Adding a method to retrieve the full masternode entry object rather than just checking for its existence is a useful enhancement that provides more detailed information.

Since you've added this new method, consider updating the existing hasMasternodeAtLocation:port: method to use your new implementation for consistency:

- (DSSimplifiedMasternodeEntry *)masternodeAtLocation:(UInt128)IPAddress port:(uint32_t)port;
- (BOOL)hasMasternodeAtLocation:(UInt128)IPAddress port:(uint32_t)port;

In the implementation file (.m), you could update the existing method like:

- (BOOL)hasMasternodeAtLocation:(UInt128)IPAddress port:(uint32_t)port {
    return [self masternodeAtLocation:IPAddress port:port] != nil;
}

This would reduce code duplication and ensure both methods use the same logic for finding masternodes.

DashSync/shared/Models/Derivation Paths/DSFundsDerivationPath.h (1)

57-57: Method looks good - consider adding documentation.

The new method for creating CoinJoin derivation paths follows the pattern of existing derivation path methods. However, consider adding documentation comments to describe the purpose and behavior of this method, similar to other public API methods in the file.

+/**
+ * Creates a derivation path specifically for CoinJoin transactions.
+ * @param accountNumber The account number to use for the derivation path.
+ * @param chain The chain on which the derivation path will be used.
+ * @return A new CoinJoin derivation path instance.
+ */
 + (instancetype)coinJoinDerivationPathForAccountNumber:(uint32_t)accountNumber onChain:(DSChain *)chain;
DashSync/shared/Models/CoinJoin/DSTransactionInput+CoinJoin.h (2)

18-20: Import statement ordering could be improved.

The imports are clear but could follow a more conventional ordering pattern: Foundation frameworks first, followed by third-party imports, and finally project-specific imports.

-#import "DSTransactionInput.h"
-#import "dash_shared_core.h"
-#import <Foundation/Foundation.h>
+#import <Foundation/Foundation.h>
+#import "dash_shared_core.h"
+#import "DSTransactionInput.h"

26-27: Method signature inconsistency between instance and class methods.

The file defines both an instance method ffi_malloc and a class method ffi_free:. This is inconsistent and could lead to confusion. Either both should be instance methods or both should be class methods.

-// Current inconsistent implementation
-@interface DSTransactionInput (CoinJoin)
-
-- (TransactionInput *)ffi_malloc;
-+ (void)ffi_free:(TransactionInput *)input;
-
-@end

+// Option 1: Both as instance methods
+@interface DSTransactionInput (CoinJoin)
+
+- (TransactionInput *)ffi_malloc;
+- (void)ffi_free:(TransactionInput *)input;
+
+@end

+// Option 2: Both as class methods (preferred for memory management)
+@interface DSTransactionInput (CoinJoin)
+
++ (TransactionInput *)ffi_malloc:(DSTransactionInput *)input;
++ (void)ffi_free:(TransactionInput *)input;
+
+@end
DashSync/shared/Models/Managers/Chain Managers/DSPeerManager.h (2)

78-78: Property naming could be more descriptive.

The property name shouldSendDsq is somewhat cryptic. Consider using a more descriptive name like shouldSendCoinJoinRequests to better communicate its purpose, especially for developers not familiar with the "dsq" abbreviation (which likely stands for "DarkSend Queue").

-@property (nonatomic, readonly) BOOL shouldSendDsq;
+@property (nonatomic, readonly) BOOL shouldSendCoinJoinRequests;

96-99: Method naming could be more consistent with property naming.

The method shouldSendDsq: is a setter for the shouldSendDsq property. Consider renaming it to follow Objective-C's setter convention, such as setShouldSendDsq:. Also, consider adding documentation to explain the purpose of this method.

 // MARK: CoinJoin

-// No documentation
-- (void)shouldSendDsq:(BOOL)shouldSendDsq;
+/**
+ * Sets whether CoinJoin queue requests should be sent to connected peers.
+ * @param shouldSendDsq If YES, CoinJoin queue requests will be sent to peers.
+ */
+- (void)setShouldSendDsq:(BOOL)shouldSendDsq;
DashSync/shared/Models/CoinJoin/DSTransactionInput+CoinJoin.m (1)

1-58: Ensure proper documentation for FFI methods

While the code is well-structured, consider adding method documentation that explains the purpose of these FFI methods and how they're used in the CoinJoin process. This would help other developers understand the memory management requirements when working with these methods.

+/**
+ * Allocates and initializes a C-compatible TransactionInput structure from this Objective-C object.
+ * Caller is responsible for freeing the returned structure using +ffi_free:.
+ * @return A pointer to a newly allocated TransactionInput structure
+ */
- (TransactionInput *)ffi_malloc {
+/**
+ * Frees memory allocated for a TransactionInput structure and its fields.
+ * @param input Pointer to the TransactionInput structure to free
+ */
+ (void)ffi_free:(TransactionInput *)input {
DashSync/shared/Models/CoinJoin/DSCompactTallyItem.h (1)

29-30: Inconsistent method declaration style

There's a mismatch in method declaration styles: ffi_malloc: is an instance method while ffi_free: is a class method. This is inconsistent with the pattern established in DSTransactionInput+CoinJoin where both malloc and free are class methods.

-  - (CompactTallyItem *)ffi_malloc:(ChainType)type;
+  + (CompactTallyItem *)ffi_malloc:(ChainType)type forItem:(DSCompactTallyItem *)item;

Or alternatively, if the instance method approach is preferred:

-  + (void)ffi_free:(CompactTallyItem *)item;
+  - (void)ffi_free:(CompactTallyItem *)item;

Choose a consistent pattern across related classes to maintain code readability.

DashSync/shared/Models/Transactions/Coinbase/DSCoinbaseTransaction.m (1)

104-112: Consider updating method documentation

The method documentation comments should be updated to include information about the new anyoneCanPay parameter and its purpose in the context of CoinJoin transactions.

// Returns the binary transaction data that needs to be hashed and signed with the private key for the tx input at
// subscriptIndex. A subscriptIndex of NSNotFound will return the entire signed transaction.
+// The anyoneCanPay parameter determines if other inputs can be added to the transaction without invalidating
+// existing signatures, which is essential for CoinJoin transactions.
- (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex
                        anyoneCanPay:(BOOL)anyoneCanPay {
Example/DashSync/DSCoinJoinViewController.h (1)

1-32: LGTM: Header file looks well-structured.

The new DSCoinJoinViewController header file is properly structured with appropriate properties for managing CoinJoin functionality in the UI. The class contains all necessary components to interface with the CoinJoin manager and present relevant UI controls to the user.

Consider adding brief documentation comments to explain the purpose of this class and its properties to improve code maintainability for other developers.

DashSync/shared/Models/CoinJoin/DSInputCoin.h (1)

25-36: Improve documentation for better understanding of the class.

This class seems to be a critical part of the CoinJoin implementation, but lacks documentation explaining its purpose and usage.

Consider adding class-level documentation and method comments, especially for the FFI methods that interface with non-Objective-C code. This would help other developers understand:

  1. The purpose of this class in the CoinJoin workflow
  2. How the FFI methods should be used
  3. Memory management expectations for the foreign types
DashSync/shared/Models/CoinJoin/Utils/DSBackoff.m (1)

20-43: Consider adding thread safety for shared usage.

This utility class might be accessed from multiple threads if CoinJoin operations run concurrently, but it lacks any thread safety mechanisms.

Consider adding thread safety using dispatch queues or locks when accessing shared properties like _backoff and _retryTime.

DashSync/shared/Models/CoinJoin/DSTransaction+CoinJoin.h (1)

24-31: Consider refining method naming and adding documentation

The category methods could benefit from clearer naming and documentation:

  1. The initWithTransaction:onChain: method doesn't follow Objective-C initializer conventions - initializers typically return instancetype, not a specific type like DSTransaction *. This looks more like a conversion method than a true initializer.

  2. All three methods lack documentation explaining their purpose, parameters, and return values, which would be helpful for other developers.

Consider:

  • Renaming the first method to better reflect its purpose (e.g., transactionWithFFITransaction:onChain:)
  • Adding documentation comments for all three methods explaining their purpose in the FFI bridge
 @interface DSTransaction (CoinJoin)
 
-  - (DSTransaction *)initWithTransaction:(Transaction *)transaction onChain:(DSChain *)chain;
+  /**
+   * Creates a DSTransaction instance from a C Transaction struct.
+   * @param transaction The C Transaction struct.
+   * @param chain The blockchain the transaction belongs to.
+   * @return A new DSTransaction instance.
+   */
+  - (DSTransaction *)transactionWithFFITransaction:(Transaction *)transaction onChain:(DSChain *)chain;
 
+  /**
+   * Allocates memory for a C Transaction struct.
+   * @param chainType The type of blockchain.
+   * @return A pointer to the allocated Transaction struct.
+   */
   - (Transaction *)ffi_malloc:(ChainType)chainType;
+  
+  /**
+   * Frees memory allocated for a C Transaction struct.
+   * @param tx The Transaction struct to free.
+   */
   + (void)ffi_free:(Transaction *)tx;
DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinSignedInputs.m (2)

22-47: Implementation looks clean but could use documentation

The DSCoinJoinSignedInputs implementation is straightforward and follows standard Objective-C patterns.

Consider adding documentation to explain the purpose of this class and its methods within the CoinJoin process:

 @implementation DSCoinJoinSignedInputs
 
+/**
+ * Creates an instance with the provided data.
+ * @param data The signed inputs data.
+ * @return A new DSCoinJoinSignedInputs instance.
+ */
 + (instancetype)requestWithData:(NSData *)data {
     return [[DSCoinJoinSignedInputs alloc] initWithData:data];
 }
 
+/**
+ * Returns the message type for CoinJoin signed inputs.
+ * @return The message type string.
+ */
 + (NSString *)type {
     return MSG_COINJOIN_SIGNED_INPUTS;
 }

32-46: Consider thread safety for data access

The implementation stores and accesses the NSData directly, which is generally fine.

Consider implementing defensive copying of the data for better protection against unintended modifications:

 - (instancetype)initWithData:(NSData *)data {
     self = [super init];
     if (self) {
-        _data = data;
+        _data = [data copy]; // Create a defensive copy
     }
     return self;
 }

 - (NSString *)type {
     return DSCoinJoinSignedInputs.type;
 }

 - (NSData *)toData {
-    return self.data;
+    return [self.data copy]; // Return a copy to prevent external modification
 }
DashSync/shared/Models/Platform/Transitions/BlockchainIdentity/DSBlockchainIdentityCloseTransition.m (1)

90-98: Method signature update correctly propagated to commented code

The method signature for toDataWithSubscriptIndex: has been updated to include the anyoneCanPay parameter, and the call to the superclass method has been updated accordingly. This change is consistent with the other transaction classes.

Note that this code is actually commented out (appears to be legacy or reference code). Consider either:

  1. Removing the commented-out code entirely if it's no longer needed, or
  2. Adding a comment explaining why this implementation is preserved for reference
-//- (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex anyoneCanPay:(BOOL)anyoneCanPay
-//{
-//    NSMutableData * data = [[super toDataWithSubscriptIndex:subscriptIndex anyoneCanPay:anyoneCanPay] mutableCopy];
-//    NSData * payloadData = [self payloadData];
-//    [data appendVarInt:payloadData.length];
-//    [data appendData:payloadData];
-//    if (subscriptIndex != NSNotFound) [data appendUInt32:SIGHASH_ALL];
-//    return data;
-//}
+// Removed legacy implementation

Or if keeping for reference:

+// Legacy implementation kept for reference - current implementation now in DSBlockchainIdentityCloseTransition.m
 //- (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex anyoneCanPay:(BOOL)anyoneCanPay
 //{
 //    NSMutableData * data = [[super toDataWithSubscriptIndex:subscriptIndex anyoneCanPay:anyoneCanPay] mutableCopy];
Example/DashSync/DSCoinJoinViewController.m (1)

44-61: startCoinJoin implementation may benefit from additional error handling.

The method properly initializes the CoinJoin manager and starts the process, but doesn't handle potential failures or provide user feedback.

Consider adding error handling and user feedback:

- (void)startCoinJoin {
    if (self.coinJoinManager == NULL) {
        self.coinJoinManager = [DSCoinJoinManager sharedInstanceForChain:self.chainManager.chain];
    }
    
    [self.coinJoinManager start];
    [self.coinJoinManager refreshUnusedKeys];
    [self.coinJoinManager initMasternodeGroup];
    [self.coinJoinManager setStopOnNothingToDo:true];
    
    if (![self.coinJoinManager startMixing]) {
        DSLog(@"[OBJ-C] CoinJoin: Mixing has been started already.");
+       // Update UI to indicate mixing is already in progress
+       [self updateStatusWithMessage:@"Mixing already in progress"];
    }
    
    [self.coinJoinManager doAutomaticDenominatingWithDryRun:NO completion:^(BOOL success) {
-        
+        if (success) {
+            [self updateStatusWithMessage:@"Denominating successful"];
+        } else {
+            [self updateStatusWithMessage:@"Denominating failed"];
+            // Consider resetting the switch if the operation failed
+            dispatch_async(dispatch_get_main_queue(), ^{
+                self.coinJoinSwitch.on = NO;
+            });
+        }
    }];
}

+// Helper method to update status
+- (void)updateStatusWithMessage:(NSString *)message {
+    // Update a status label or other UI element
+    dispatch_async(dispatch_get_main_queue(), ^{
+        self.statusLabel.text = message;
+    });
+}
DashSync/shared/Models/CoinJoin/Utils/DSBackoff.h (1)

20-33: New backoff utility class needs documentation

The DSBackoff class appears to implement an exponential backoff algorithm for retry mechanisms, which is useful for network operations in CoinJoin. While the implementation looks good, it lacks documentation explaining the purpose and behavior of the class and its methods.

Consider adding documentation comments to explain:

  • The purpose of the class
  • How the backoff algorithm works
  • What trackSuccess and trackFailure methods do to the backoff state
  • The expected usage pattern in CoinJoin contexts
DashSync/shared/Models/CoinJoin/DSCoinJoinBalance.h (1)

23-34: New CoinJoin balance tracking class needs documentation

The DSCoinJoinBalance class introduces multiple properties for tracking various balance states in CoinJoin operations, but lacks documentation explaining what each balance type represents and how they're used.

Consider adding documentation comments to explain:

  • The purpose of each balance type (trusted, untrusted, denominated, anonymized, etc.)
  • How these balances relate to CoinJoin operations
  • How watch-only balances differ from regular balances
DashSync/shared/Models/CoinJoin/DSCompactTallyItem.m (2)

31-51: FFI memory allocation is correctly implemented, but could be improved.

The method allocates memory for the CompactTallyItem structure and its components, including the transaction destination and input coins array. However, there's a potential issue with type handling and an unnecessary variable.

Consider these improvements:

  1. Line 37 creates a scriptData variable unnecessarily - you can pass self.txDestination directly to data_malloc
  2. The txDestination property appears to be accessed as both a string (for length) and data (for content) - ensure the property type is consistent
- NSUInteger length = self.txDestination.length;
- tallyItem->tx_destination_length = (uintptr_t)length;
- NSData *scriptData = self.txDestination;
- tallyItem->tx_destination = data_malloc(scriptData);
+ tallyItem->tx_destination_length = (uintptr_t)self.txDestination.length;
+ tallyItem->tx_destination = data_malloc(self.txDestination);

53-67: Memory deallocation is thorough but has a type inconsistency.

The ffi_free: method properly frees all allocated memory, including nested structures. However, there's a type inconsistency in the loop counter.

For type consistency, consider changing the loop counter type to match the size type:

- for (int i = 0; i < item->input_coins_size; i++) {
+ for (uintptr_t i = 0; i < item->input_coins_size; i++) {

This matches the type used in the ffi_malloc: method and the input_coins_size field.

DashSync/shared/Models/Managers/Chain Managers/DSMasternodeManager.m (1)

164-166: Function signature has changed but is being used as a boolean.

The method hasMasternodeAtLocation:port: now returns a DSSimplifiedMasternodeEntry * object instead of a BOOL, but is still being used in a boolean context by checking if the result is not nil. This change in return type could lead to confusion for callers expecting a boolean value.

Consider renaming this method to better reflect its new behavior, such as findMasternodeAtLocation:port: to clearly indicate it returns an object or nil.

DashSync/shared/Models/CoinJoin/DSTransaction+CoinJoin.m (2)

68-70: Improve clarity for NSNull handling.

Using NSNull for nil addresses that will later be converted to OP_RETURN scripts is a valid approach, but it could be confusing without proper documentation.

Consider adding a comment explaining this pattern or create a helper method to make the intention clearer.

- [addresses addObject:address ?: [NSNull null]]; // Use NSNull turned into OP_RETURN script later
+ // Nil addresses will be converted to OP_RETURN scripts during transaction creation
+ [addresses addObject:address ?: [NSNull null]];

78-107: Good memory management, but add documentation for FFI functions.

The ffi_malloc: method correctly allocates memory for the Transaction struct and its components. However, as this is part of a Foreign Function Interface (FFI), adding more documentation would help future developers understand these critical memory management functions.

- - (Transaction *)ffi_malloc:(ChainType)chainType {
+ /**
+  * Allocates and populates a C-style Transaction structure from this Objective-C object.
+  * Caller is responsible for freeing the memory using +ffi_free: method.
+  *
+  * @param chainType The type of chain this transaction belongs to
+  * @return A pointer to the allocated Transaction structure
+  */
+ - (Transaction *)ffi_malloc:(ChainType)chainType {
DashSync/shared/Models/CoinJoin/DSCoinJoinBalance.m (1)

22-44: Consider using a builder pattern for clarity with many parameters.

The class method has 9 parameters which makes it difficult to use correctly and maintain. A builder pattern or a dictionary-based approach would make this more manageable.

Alternative approach using a dictionary:

+ /**
+  * Creates a balance object with the specified balance values.
+  *
+  * @param balanceDict Dictionary with keys for each balance type
+  * @return Initialized DSCoinJoinBalance object
+  */
+ + (DSCoinJoinBalance *)balanceWithDictionary:(NSDictionary *)balanceDict {
+     DSCoinJoinBalance *balance = [[DSCoinJoinBalance alloc] init];
+     balance.myTrusted = [balanceDict[@"myTrusted"] unsignedLongLongValue];
+     balance.denominatedTrusted = [balanceDict[@"denominatedTrusted"] unsignedLongLongValue];
+     balance.anonymized = [balanceDict[@"anonymized"] unsignedLongLongValue];
+     balance.myImmature = [balanceDict[@"myImmature"] unsignedLongLongValue];
+     balance.myUntrustedPending = [balanceDict[@"myUntrustedPending"] unsignedLongLongValue];
+     balance.denominatedUntrustedPending = [balanceDict[@"denominatedUntrustedPending"] unsignedLongLongValue];
+     balance.watchOnlyTrusted = [balanceDict[@"watchOnlyTrusted"] unsignedLongLongValue];
+     balance.watchOnlyUntrustedPending = [balanceDict[@"watchOnlyUntrustedPending"] unsignedLongLongValue];
+     balance.watchOnlyImmature = [balanceDict[@"watchOnlyImmature"] unsignedLongLongValue];
+     
+     return balance;
+ }
DashSync/shared/Models/Transactions/Base/DSTransaction.h (3)

93-94: Clarify property naming to reduce ambiguity.
Naming properties as direction and dashAmount might lead to confusion in multi-asset contexts or in code that manages BTC-like assets as well. A more descriptive naming pattern such as transactionDirection and transactionAmount could improve clarity.

-@property (nonatomic, readonly) DSTransactionDirection direction;
-@property (nonatomic, readonly) uint64_t dashAmount;
+@property (nonatomic, readonly) DSTransactionDirection transactionDirection;
+@property (nonatomic, readonly) uint64_t transactionAmount;

109-109: Confirm alignment with established naming conventions.
The property isImmatureCoinBase is descriptive, but code elsewhere may use variants like isCoinbaseTransaction or isImmatureCoinbase. Merit verifying or aligning the name across the codebase for consistency.


177-177: Validate the coin maturity flow in specialized transactions.
getBlocksToMaturity helps identify spendable status for coinbase outputs. Ensure it accounts for all special transaction types that might follow similar maturity rules.

DashSync/shared/Libraries/Logs/CompressingLogFileManager.m (3)

1-40: Provide clear logging levels and fallback strategies.
This file introduces custom macros (NSLogError, NSLogWarn, etc.) and a fixed LOG_LEVEL. Consider using the built-in CocoaLumberjack macros or dynamic log levels to allow flexible runtime logging control.


189-225: Confirm operational flow upon compression success/failure.
compressionDidSucceed: calls compressNextLogFile, while compressionDidFail: retries after a delay. Ensure that re-trying won't cause repeated indefinite failures, e.g., if there's a permanent filesystem issue.

Would you like a helper solution that monitors the number of consecutive failures and escalates if a threshold is reached?


515-561: Use unique naming for temp file paths to avoid collisions.
tempFilePathByAppendingPathExtension: and fileNameByAppendingPathExtension: are straightforward. Confirm that concurrency or multiple processes won't generate the same temp filename simultaneously.

DashSync/shared/Models/CoinJoin/DSCoinControl.m (1)

76-87: Use built-in membership check instead of manual loop.

Instead of iterating through self.setSelected to check membership, you can directly do:

return [self.setSelected containsObject:dsutxo_obj(utxo)];

This avoids an O(n) loop each time you check a UTXO.

DashSync/shared/Models/CoinJoin/DSCoinControl.h (1)

24-50: Potential for a convenience or builder-style initializer.

With many boolean and numeric properties, consider adding a convenience initializer or configuration methods to reduce constructor overload and ensure clarity, especially when toggling multiple coin control options (e.g., allowWatchOnly, overrideFeeRate, etc.).

DashSync/shared/Models/CoinJoin/DSCoinJoinWrapper.h (1)

33-49: Add usage documentation for newly introduced methods.
These methods facilitate critical steps of the CoinJoin process but have no inline documentation. Briefly explain their purpose, expected parameters, and return behavior to ease onboarding for new developers and to promote clarity.

DashSync/shared/Models/Network/DSPeer.m (2)

381-381: Consider removing the commented-out logging.
Leaving logging statements commented out can clutter the code. Remove them or guard them with a debug flag if they are occasionally helpful.

-//    DSLog(@"%@:%u sendRequest: [%@]: %@", self.host, self.port, type, [payload hexString]);

1823-1842: Watch for concurrency in shared manager calls.
These new acceptCoinJoin* methods delegate to [DSCoinJoinManager sharedInstanceForChain:]. Double-check concurrency protections—multiple peers might asynchronously call the shared manager. Consider locking or queue dispatch if needed to avoid race conditions.

DashSync/shared/Models/Wallet/DSAccount.m (4)

166-170: Checking for multiple CoinJoin derivation paths.

Your assertion ensures each account can only hold a single CoinJoin derivation path. Great approach for avoiding confusion. Double-check that this scenario never needs multiple such derivation paths in the future.

Consider providing a more descriptive assertion message, for instance:

- NSAssert(TRUE, @"There should only be one CoinJoin derivation path");
+ NSAssert(FALSE, @"Duplicate CoinJoin derivation path encountered");

241-241: Minor adjustment in transaction loading.

Check if reformatting or a new comment was intended here. The functional change is unclear.

If this is only a spacing fix, consider combining it with other relevant changes for clarity.


483-505: Extending registerAddressesWithGapLimit:(...)coinJoinGapLimit:(...)error:.

You handle three different gap limits: normal, DashPay, and CoinJoin. Encouraging separation of concerns. The expanded logic is consistent. Validate test coverage to ensure coinJoinGapLimit is applied correctly.

Consider extracting the gapLimiting logic into a small helper function for readability, especially as you add more path types in the future.


713-759: Refined transaction size/locktime checks within updateBalance.

You’ve introduced or adjusted logging and validation for transaction sizes, lockTimes, dust outputs, etc. This is beneficial for security and consistency. However, large blocks of #if DEBUG logging can become unwieldy.

Consider grouping the debug logs and adding more descriptive log statements to help with production debugging.

DashSync/shared/Models/CoinJoin/Utils/DSMasternodeGroup.m (6)

37-56: Private properties and interface.

Properties effectively unify group logic for masternodes, sessions, pending states, and backoff logic. Atomic usage of _maxConnections is consistent but ensure thread safety for other mutable properties.

You might consider marking _maxConnections atomic or using synchronized reads where needed for absolute safety.


83-91: - startAsync
Sets _isRunning to true, registers sync-state notifications, triggers connections. Straightforward. Ensure that repeated calls don’t accidentally re-subscribe notifications or lead to concurrency issues.

If startAsync can be called multiple times, consider unsubscribing prior to re-subscribing to avoid duplicates.


101-115: - isMasternodeOrDisconnectRequested:port:
Checks if a masternode is in connected or pending closure sets. Straight to the point.

For clarity, rename to isMasternodeConnectedOrPendingDisconnect: to convey the meaning more precisely.


194-245: - triggerConnectionsJobWithDelay:
Schedules connections after a delay, checks chain sync status, ensures we have not exceeded max connections, and tries to get the next peer. Good structure.

Consider separating the environment checks (e.g., chain sync, new block wait, mixing enabled) into a smaller method for clarity.


409-459: - connectTo:
Checks if peer is a valid masternode session, sets up delegates, and attempts to connect. Key logic for initiating new connections. Possibly add extra checks for spurious repeated connections.

Log a warning if peer is already connecting or connected to avoid spamming reconnections.


499-554: - peer:disconnectedWithError:
Removes peer from pending/connected sets, updates backoff, and triggers reconnection if needed. Also checks if that peer was in the pending-closing list and cleans up session references. Well-structured.

Consider splitting the logic for normal disconnect vs. an intended closure to keep it simpler.

DashSync/shared/Models/CoinJoin/DSCoinJoinWrapper.m (3)

43-51: - registerCoinJoin:
Initializes the Rust client manager via FFI. This is critical. Ensure that subsequent calls don’t inadvertently re-register or leak memory.

Add clarity around repeated calls. If clientManager is already set, do you skip re-registering?


133-147: - processMessageFrom:message:type:
Similar bridging, but includes a message type. Freed after usage. Looks correct.

Validate that the string length for message_type in Rust can handle arbitrary input.


279-284: - dealloc
Unregisters the client manager to free resources. Ensure no further references to _clientManager remain.

Potentially ensure a shutdown or stop logic is invoked prior for a graceful teardown.

DashSync/shared/Models/Wallet/DSAccount.h (6)

57-58: Ensure property is clearly documented.
coinJoinDerivationPath is a helpful read-only property. Consider adding a short doc comment describing its intended usage (e.g., how addresses are derived, whether it's created eagerly or lazily, etc.).


100-111: Clarify naming and usage of CoinJoin address arrays.
The new properties (coinJoinReceiveAddress, coinJoinChangeAddress, usedCoinJoinReceiveAddresses, allCoinJoinReceiveAddresses) suggest different sets of addresses (e.g., "used" vs. "all"). Consider clarifying the naming or associated doc comments to prevent confusion, especially distinguishing "issued" from "used".


118-118: Consider simplifying the parameter list.
The additional coinJoinGapLimit parameter might be consolidated (e.g., using a config object) if more parameters are added in the future. This can improve readability and reduce method signature length.


198-203: Complete the doc comment.
The doc comment here is partially empty between lines 198–203. Consider adding details, for instance, clarifying whether it prompts for a passphrase or how the result is returned.


205-215: Check method name overlap.
We now have two signTransaction: methods. For clarity, you could unify or rename them to highlight the anyoneCanPay: parameter. This helps avoid confusion and clarifies usage.


283-285: Consider returning a typed array.
- (NSArray *)amountsSentByTransaction: could return NSArray<NSNumber *> * for stronger type checking.

DashSync/shared/Models/Managers/Chain Managers/DSTransactionManager.m (5)

290-294: Review PII or sensitive data logging.
DSLogPrivate might reveal transaction details or hashes. Confirm that this usage aligns with the privacy and logging guidelines.


307-308: Minor style consistency.
Declaring BOOL updateTransaction = NO; and a blank line might break code style consistency. Consider removing extra blank lines if not needed.


1141-1148: Standardize error handling.
Returning an NSError with code 401 for double spend might be conflated with 401 Unauthorized in some contexts. Consider custom error domain or code for double-spend conflicts, or ensure clarity around the meaning of 401 here.


1785-1791: Nested async block.
Dispatching within dispatch_async can be simplified if no additional checks are needed. Otherwise, ensure it doesn't cause unexpected delays.


1139-1148: Double spend error:
Here, a 401 code is used to signify “Double spend.” While functional, consider adding a dedicated error code for clarity.

- error = [NSError errorWithCode:401 localizedDescriptionKey:@"Double spend"];
+ // optionally define a distinct code for double spend scenario
+ error = [NSError errorWithCode:DSErrorDoubleSpend localizedDescriptionKey:@"Double spend"];
DashSync/shared/Models/CoinJoin/DSCoinJoinManager.h (2)

57-95: Broad method set for management.
These methods expand functionality significantly. If this file grows, consider grouping them by category (e.g., “Masternode Management,” “Coin Selection,” “Mixing Lifecycle”) to improve maintainability. Also ensure concurrency handling if mixing runs on multiple threads.


96-102: Event handler naming.
Methods like onSessionComplete:, onMixingComplete:, etc. are consistent in prefixing with "on". However, consider standard naming for clarity, e.g., notifyMixingComplete: or didCompleteMixing:.

DashSync/shared/Models/CoinJoin/DSCoinJoinManager.m (2)

39-41: Consider clarifying default constants.

The arbitrary values for DEFAULT_MAX_DEPTH and MIN_BLOCKS_TO_WAIT might benefit from explanatory comments or self-documenting names. This can help future maintainers understand why these values were chosen.


374-491: Potential performance concern with large unspent sets.

This method iterates over all unspent outputs, checks conditions, and accumulates results for each. For large wallets, this can become expensive. Consider either indexing unspent outputs by address, or caching frequently used data to reduce computational overhead.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dba479 and a2e7536.

⛔ Files ignored due to path filters (1)
  • Example/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (102)
  • .github/workflows/build.yml (2 hunks)
  • .github/workflows/coverage.yml (1 hunks)
  • .github/workflows/e2eTestsTestnet.yml (1 hunks)
  • .github/workflows/lint.yml (1 hunks)
  • .github/workflows/network.yml (1 hunks)
  • .github/workflows/syncTestMainnet.yml (1 hunks)
  • .github/workflows/syncTestTestnet.yml (1 hunks)
  • .github/workflows/test.yml (1 hunks)
  • DashSync.podspec (1 hunks)
  • DashSync/shared/DashSync.m (2 hunks)
  • DashSync/shared/Libraries/DSLogger.m (2 hunks)
  • DashSync/shared/Libraries/Logs/CompressingLogFileManager.h (1 hunks)
  • DashSync/shared/Libraries/Logs/CompressingLogFileManager.m (1 hunks)
  • DashSync/shared/Models/Chain/DSChain.m (2 hunks)
  • DashSync/shared/Models/Chain/DSChainConstants.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinControl.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinControl.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinBalance.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinBalance.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinManager.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinManager.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinWrapper.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCoinJoinWrapper.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCompactTallyItem.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSCompactTallyItem.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSInputCoin.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSInputCoin.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransaction+CoinJoin.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransaction+CoinJoin.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransactionInput+CoinJoin.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransactionInput+CoinJoin.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransactionOutput+CoinJoin.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/DSTransactionOutput+CoinJoin.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/Utils/DSBackoff.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/Utils/DSBackoff.m (1 hunks)
  • DashSync/shared/Models/CoinJoin/Utils/DSMasternodeGroup.h (1 hunks)
  • DashSync/shared/Models/CoinJoin/Utils/DSMasternodeGroup.m (1 hunks)
  • DashSync/shared/Models/Derivation Paths/DSDerivationPath.h (2 hunks)
  • DashSync/shared/Models/Derivation Paths/DSDerivationPath.m (1 hunks)
  • DashSync/shared/Models/Derivation Paths/DSFundsDerivationPath.h (2 hunks)
  • DashSync/shared/Models/Derivation Paths/DSFundsDerivationPath.m (3 hunks)
  • DashSync/shared/Models/Entities/DSFriendRequestEntity+CoreDataClass.m (1 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSKeyManager.m (1 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSMasternodeManager.h (1 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSMasternodeManager.m (1 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSPeerManager.h (2 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSPeerManager.m (4 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSTransactionManager.h (2 hunks)
  • DashSync/shared/Models/Managers/Chain Managers/DSTransactionManager.m (20 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinAcceptMessage.h (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinAcceptMessage.m (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinEntryMessage.h (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinEntryMessage.m (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinSignedInputs.h (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinSignedInputs.m (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSSendCoinJoinQueue.h (1 hunks)
  • DashSync/shared/Models/Messages/CoinJoin/DSSendCoinJoinQueue.m (1 hunks)
  • DashSync/shared/Models/Network/DSPeer.h (1 hunks)
  • DashSync/shared/Models/Network/DSPeer.m (6 hunks)
  • DashSync/shared/Models/Platform/Transitions/BlockchainIdentity/DSBlockchainIdentityCloseTransition.m (1 hunks)
  • DashSync/shared/Models/Platform/Transitions/BlockchainIdentity/DSBlockchainIdentityUpdateTransition.m (1 hunks)
  • DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m (2 hunks)
  • DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Base/DSTransaction.h (6 hunks)
  • DashSync/shared/Models/Transactions/Base/DSTransaction.m (18 hunks)
  • DashSync/shared/Models/Transactions/Coinbase/DSCoinbaseTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Provider/DSProviderRegistrationTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRegistrarTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRevocationTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateServiceTransaction.m (1 hunks)
  • DashSync/shared/Models/Transactions/Quorums/DSQuorumCommitmentTransaction.m (1 hunks)
  • DashSync/shared/Models/Wallet/DSAccount.h (8 hunks)
  • DashSync/shared/Models/Wallet/DSAccount.m (43 hunks)
  • DashSync/shared/Models/Wallet/DSWallet+Protected.h (1 hunks)
  • DashSync/shared/Models/Wallet/DSWallet.h (2 hunks)
  • DashSync/shared/Models/Wallet/DSWallet.m (4 hunks)
  • Example/DashSync.xcodeproj/project.pbxproj (12 hunks)
  • Example/DashSync/Actions.storyboard (24 hunks)
  • Example/DashSync/Base.lproj/Main.storyboard (63 hunks)
  • Example/DashSync/Contacts.storyboard (17 hunks)
  • Example/DashSync/DSActionsViewController.m (2 hunks)
  • Example/DashSync/DSCoinJoinViewController.h (1 hunks)
  • Example/DashSync/DSCoinJoinViewController.m (1 hunks)
  • Example/DashSync/DSTransactionsViewController.m (3 hunks)
  • Example/DashSync/Wallets.storyboard (7 hunks)
  • Example/Tests/CoinJoinTests.xctestplan (1 hunks)
  • Example/Tests/CryptoTests.xctestplan (1 hunks)
  • Example/Tests/DSCoinJoinSessionTest.m (1 hunks)
  • Example/Tests/DerivationTests.xctestplan (1 hunks)
  • Example/Tests/FullUnitTestPlan.xctestplan (1 hunks)
  • Example/Tests/GovernanceTests.xctestplan (1 hunks)
  • Example/Tests/LibraryTests.xctestplan (1 hunks)
  • Example/Tests/LockTests.xctestplan (1 hunks)
  • Example/Tests/MainnetSyncTests.xctestplan (1 hunks)
  • Example/Tests/MasternodeListTests.xctestplan (1 hunks)
  • Example/Tests/Metrics.xctestplan (1 hunks)
  • Example/Tests/PaymentTests.xctestplan (1 hunks)
  • Example/Tests/PlatformTransitionTests.xctestplan (1 hunks)
  • Example/Tests/TestnetE2ETests.xctestplan (1 hunks)
  • Example/Tests/TestnetSyncTests.xctestplan (1 hunks)
  • Example/Tests/TransactionTests.xctestplan (1 hunks)
  • Example/Tests/WalletTests.xctestplan (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Testnet E2E Tests
  • GitHub Check: Objective-C Linter
  • GitHub Check: Code coverage
  • GitHub Check: Mainnet Chain
  • GitHub Check: Testnet Chain
🔇 Additional comments (245)
Example/DashSync/Base.lproj/Main.storyboard (4)

2-2: Updated interface builder tools version.

The storyboard file has been updated to use the newer versions of Xcode tools: InterfaceBuilder and IBCocoaTouchPlugin. This is a standard update when working with a newer version of Xcode.

Also applies to: 6-6


84-84: Background color change improves UI layering.

The header view background color has been changed from white to transparent (alpha 0), which allows for better visual layering in the UI hierarchy. This is a good UI improvement that will make the interface appear less cluttered.


124-1543: Layout positioning adjustments for table view cells.

These changes represent automatic adjustments to frame rectangles, positions, and constraints in the storyboard. These are generated by Interface Builder when layouts are modified and don't require manual review as they're derived from higher-level design changes.


1-2989: Missing explicit CoinJoin UI elements for feature implementation.

While the PR title and AI summary reference CoinJoin functionality, I don't see any explicit UI elements (labels, view controllers, table cells) named "CoinJoin" in this storyboard file. Ensure the CoinJoin feature is properly exposed in the UI if that's the intention of this PR.

Could you verify if the CoinJoin UI elements are defined in another storyboard file or implemented programmatically? This would help ensure the feature is properly exposed to users.

DashSync.podspec (1)

37-37:

Details

❓ Verification inconclusive

Verify compatibility with updated DashSharedCore version

The DashSharedCore dependency has been updated from version 0.4.19 to 0.5.1, which is a significant version jump. This change likely includes new functionality required for CoinJoin implementation.

Ensure that all usage of this dependency throughout the codebase has been updated to accommodate any breaking changes introduced in this version upgrade.


🌐 Web query:

What changed between DashSharedCore 0.4.19 and 0.5.1?

💡 Result:

The provided search results do not contain specific information about changes between DashSharedCore versions 0.4.19 and 0.5.1. None of the listed changelogs reference a component or project named "DashSharedCore," and the version numbers 0.4.19/0.5.1 do not appear in any of the documented releases for Dashy, Argo CD, Uppy, GitLab Runner, or the git-changelog Python package.

For accurate release notes, you would need to consult the official DashSharedCore changelog or repository. If this is part of a larger framework, ensure you're checking the correct component's documentation.

Citations:


Please verify compatibility with DashSharedCore 0.5.1

The dependency in DashSync.podspec has been updated from version 0.4.19 to 0.5.1, representing a significant jump. Since the web query did not return specific details about the changes between these versions, please ensure that you consult the official DashSharedCore changelog or repository for any breaking changes or new migration considerations. Also, verify that all usage within the codebase is compatible with the new version.

  • File: DashSync.podspec (line 37)
  • Snippet unchanged:
      s.dependency 'DashSharedCore', '0.5.1'
    
.github/workflows/lint.yml (1)

46-49: Good addition of pinned CocoaPods version

Adding a specific step to set up CocoaPods with a pinned version (1.15.2) is a good practice for CI workflows. This ensures consistent dependency resolution across different environments and prevents potential issues with varying CocoaPods versions.

.github/workflows/build.yml (2)

47-50: Good addition of pinned CocoaPods version

Adding a specific step to set up CocoaPods with a pinned version (1.15.2) is consistent with the change in the lint workflow and ensures that all CI jobs use the same version of CocoaPods. This is a good practice for maintaining consistency across different workflow steps.


66-67: LGTM: Proper file termination

Adding a trailing newline at the end of the file is a good practice for text files.

Example/Tests/FullUnitTestPlan.xctestplan (1)

18-18: Verify test coverage for CoinJoin functionality

The DSCoinJoinSessionTest has been added to the skipped tests list. Since this PR implements CoinJoin functionality, skipping this test raises questions about how the feature is being validated.

Could you explain why this test is being skipped? Is there alternative test coverage for CoinJoin functionality in other test plans or through different means? Please ensure that the CoinJoin implementation is adequately tested through other test cases or methods.

Example/Tests/LibraryTests.xctestplan (1)

26-26: Skip configuration for CoinJoin session test added.

The test DSCoinJoinSessionTest has been added to the skipped tests list. This appears to be part of a broader pattern where this test is being skipped across multiple test plans. Is there a specific reason for excluding this test from regular execution? Please consider adding a comment or creating a ticket to track the rationale and any plans to enable this test in the future.

Example/Tests/DerivationTests.xctestplan (1)

25-25: CoinJoin session test consistently skipped across test plans.

The DSCoinJoinSessionTest has been added to the skipped tests list, consistent with changes in other test plans. While skipping tests can be necessary, it's important to document why this test is being excluded across multiple plans. Is this due to test instability, performance concerns, or specific environmental requirements?

Example/Tests/TestnetE2ETests.xctestplan (1)

25-25: CoinJoin test skipping pattern continues in E2E tests.

The DSCoinJoinSessionTest has been added to the skipped tests list here as well, following the same pattern seen in other test plans. Given that the PR mentions CI error resolution, is skipping this test a temporary measure to get the feature merged, or will it remain skipped permanently? If temporary, consider adding a TODO comment with a ticket reference.

Example/Tests/MasternodeListTests.xctestplan (1)

26-26: Test skipping pattern confirmed across multiple test plans.

The addition of DSCoinJoinSessionTest to the skipped tests list is consistent with changes in other test plans. Since this appears to be a deliberate pattern, it would be beneficial to:

  1. Document the reason for skipping these tests
  2. Create a ticket to track re-enabling them if they're meant to be temporary
  3. Consider adding a comment in the test itself explaining why it's skipped

This consistent approach ensures the test configuration remains maintainable as the CoinJoin feature evolves.

Example/Tests/TestnetSyncTests.xctestplan (1)

25-25: CoinJoin test has been added to skipped tests

The DSCoinJoinSessionTest is being added to the list of skipped tests. This aligns with the PR's mention of resolving CI errors, but systematically skipping tests might mask potential issues.

What is the reason for skipping this test? Is there a plan to enable it in the future once the CoinJoin feature is more stable?

Example/Tests/CryptoTests.xctestplan (1)

37-37: CoinJoin test consistently skipped across test plans

The DSCoinJoinSessionTest has been added to the skipped tests here as well, continuing the pattern seen in other test plans.

Could there be a more targeted approach than skipping this test across all test plans? For example, could some test plans run a subset of the CoinJoin tests that are more stable?

Example/Tests/MainnetSyncTests.xctestplan (1)

26-26: Consistent with other test plans.

The addition of "DSCoinJoinSessionTest" to skipped tests is properly placed in alphabetical order and matches the pattern seen in other test plans.

Example/Tests/GovernanceTests.xctestplan (1)

26-26: LGTM - Matches pattern in other test plans.

The "DSCoinJoinSessionTest" has been added to the skipped tests list in the correct alphabetical position, consistent with other test plan files.

Example/Tests/LockTests.xctestplan (1)

25-25: Consistent test skipping across test plans

The addition of DSCoinJoinSessionTest to the skipped tests is consistent with the changes made to other test plans. This is a good practice to ensure consistent test behavior across different test configurations.

DashSync/shared/Models/Chain/DSChainConstants.h (1)

86-86: Appropriate addition of COINBASE_MATURITY constant

The addition of the COINBASE_MATURITY constant with a value of 100 is correct and follows standard blockchain practices. This constant defines that coinbase transaction outputs can only be spent after 100 new blocks, which is an important parameter for transaction validation and will be particularly relevant for the CoinJoin feature being implemented.

.github/workflows/test.yml (1)

55-59: Good addition of explicit CocoaPods setup step

Adding a specific step to set up CocoaPods with a fixed version (1.15.2) is a good practice. This ensures consistent build environments across different CI runs and developers' machines, which helps prevent "works on my machine" issues.

.github/workflows/coverage.yml (1)

46-49: CocoaPods Setup Step Integration
The new "Setup CocoaPods" step is correctly inserted after adding the Rust targets and before running dependency installation. Using maxim-lobanov/setup-cocoapods@v1 with the explicit version 1.15.2 ensures consistency with other workflows.

.github/workflows/syncTestMainnet.yml (1)

47-50: Consistent CocoaPods Setup in SyncTestMainnet Workflow
The addition of the "Setup CocoaPods" step using maxim-lobanov/setup-cocoapods@v1 (version 1.15.2) is well-placed and maintains consistency with other CI workflows. This should help to ensure that CocoaPods is properly configured before dependency installation.

.github/workflows/network.yml (1)

46-49: CocoaPods Configuration in Network Workflow
The updated step correctly adds CocoaPods setup after the Rustup target step. Pinning the CocoaPods version to 1.15.2 helps maintain uniformity across workflows. Consider monitoring future CocoaPods releases for any potential required updates.

.github/workflows/e2eTestsTestnet.yml (1)

48-51: E2E Tests Workflow – CocoaPods Setup Step
The newly introduced "Setup CocoaPods" step using maxim-lobanov/setup-cocoapods@v1 with version 1.15.2 is placed appropriately after adding Rust targets and before dependency installation. This change aligns the E2E tests setup with other workflows, ensuring dependable dependency management for iOS components.

Example/DashSync.xcodeproj/project.pbxproj (6)

69-70: New CoinJoin files added to the project

The project has been updated to include the new CoinJoin functionality with:

  • DSCoinJoinSessionTest.m for testing CoinJoin sessions
  • DSCoinJoinViewController.m for the user interface

These additions align with the PR's goal of integrating CoinJoin functionality.


623-626: File references for CoinJoin implementation added

The project now includes:

  • A dedicated test plan for CoinJoin tests
  • Header and implementation files for the CoinJoin view controller

This provides a good structure for the new feature implementation.


1471-1471: Organized test structure with dedicated CoinJoin group

Adding a specific test group for CoinJoin tests helps maintain a clean organization of test files.


2072-2073: CoinJoin view controller added to Actions group

The view controller is appropriately placed in the Actions group alongside other action-related controllers.


3202-3202: Verify impact of enabling fast math optimizations

The project now uses GCC_FAST_MATH = YES for both debug and release builds. While this can improve performance, it may affect floating-point calculations by:

  • Disabling IEEE 754 compliance checks
  • Assuming NaN values don't occur
  • Eliminating division by zero checks

Consider verifying if CoinJoin operations involve critical floating-point calculations that might be affected by these optimizations. If precision is crucial for cryptographic operations, this setting might need reconsideration.

Also applies to: 3258-3258


3327-3327: Addition of -ld64 linker flag

The -ld64 linker flag has been added to the project. This explicitly specifies the linker to use.

Please confirm this flag is necessary. Typically, Xcode selects the appropriate linker automatically based on the target platform, and explicitly specifying it is only needed for special cases.

Also applies to: 3389-3389

Example/Tests/CoinJoinTests.xctestplan (1)

1-60: New test plan for CoinJoin functionality looks well-structured.

This is a good setup for isolating CoinJoin-specific tests. I noticed almost all tests are skipped, which makes sense for focused testing, but would be helpful to eventually include a comment explaining the test plan's specific focus.

DashSync/shared/Models/Derivation Paths/DSDerivationPath.m (1)

499-501: Added support for CoinJoin in derivation path references.

The addition of the CoinJoin case in the referenceName method is properly implemented and consistent with the existing code style. This change correctly supports the new derivation path reference type for CoinJoin functionality.

Example/Tests/DSCoinJoinSessionTest.m (1)

34-35:

Details

❓ Verification inconclusive

Review TODO comment for clarification needed.

The TODO comment suggests uncertainty about the COINJOIN_RANDOM_ROUNDS constant. This should be resolved before finalizing the test.


🏁 Script executed:

#!/bin/bash
# Search for the definition of COINJOIN_RANDOM_ROUNDS constant

echo "Searching for COINJOIN_RANDOM_ROUNDS definition:"
rg -A 2 -B 2 "COINJOIN_RANDOM_ROUNDS" --type c --type objc --type h

Length of output: 1211


Clarify the "TODO: check" on COINJOIN_RANDOM_ROUNDS Usage

The constant COINJOIN_RANDOM_ROUNDS is defined and applied consistently in both production and test files. However, the lingering "// TODO: check" in the test remains ambiguous. Please either clarify what specific behavior or value needs further verification for COINJOIN_RANDOM_ROUNDS or remove the comment if the current usage is correct.

  • Located in Example/Tests/DSCoinJoinSessionTest.m at lines 34-35.
  • Confirmed its usage in DashSync/shared/Models/CoinJoin/DSCoinJoinManager.m.
.github/workflows/syncTestTestnet.yml (1)

48-51: Good addition to fix CI issues

Adding a specific CocoaPods setup step with a pinned version (1.15.2) helps ensure consistent build environments and addresses the CI errors mentioned in the PR description.

This change appropriately places the CocoaPods setup step after Rust target configuration and before dependency installation, ensuring the right environment is established before proceeding with the build.

DashSync/shared/Models/Derivation Paths/DSFundsDerivationPath.h (1)

13-13:

Details

❓ Verification inconclusive

Verify if the large gap limit value is necessary for CoinJoin.

The newly added constant SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN is set to 400, which is significantly higher than other gap limits (e.g., SEQUENCE_GAP_LIMIT_INITIAL is 100). While this may be intentional for CoinJoin operations which typically require more addresses, ensure this value isn't unnecessarily large as it could impact performance when scanning the blockchain.


🏁 Script executed:

#!/bin/bash
# Look for uses of this constant to understand its impact

echo "Searching for uses of SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN constant..."
rg -A 3 "SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN"

echo "Checking if there are special load address implementations for CoinJoin..."
rg "loadAddresses.*CoinJoin" -A 5

Length of output: 3182


Confirm the Justification for a 400-Gap Limit on CoinJoin

I've confirmed that the constant SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN is indeed used in several parts of the codebase (in DSFundsDerivationPath.h, DSTransactionManager.m, and DSChain.m) and is passed as the parameter for registering addresses within CoinJoin operations. There is no specialized address-loading logic for CoinJoin—CoinJoin simply relies on this higher gap limit compared to the standard (100) gap limit.

Please verify that setting the gap limit to 400 is intentional based on CoinJoin's operational requirements and performance benchmarks. If 400 is necessary to support CoinJoin properly, consider adding a brief comment in the code explaining this rationale to assist future maintainers. Otherwise, revisiting this value may help optimize blockchain scanning performance.

DashSync/shared/Models/Managers/Chain Managers/DSKeyManager.m (1)

195-198: Good defensive programming addition.

The added input validation is a good defensive programming practice. It prevents potential crashes or unexpected behavior by checking for nil or empty data before processing.

DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m (1)

83-85: Method signature updated to include anyoneCanPay parameter

The method has been properly updated to include the anyoneCanPay parameter and correctly passes it to the superclass method. This change is part of the CoinJoin feature implementation, allowing for greater flexibility in transaction signing.

The anyoneCanPay flag is important for CoinJoin transactions as it allows signing inputs independently, which is a key requirement for the CoinJoin mixing process.

DashSync/shared/Models/Derivation Paths/DSDerivationPath.h (2)

49-49: Added CoinJoin feature purpose definition

Adding FEATURE_PURPOSE_COINJOIN with value 4 is appropriate for the CoinJoin feature integration.


86-86: Added CoinJoin derivation path reference

Adding DSDerivationPathReference_CoinJoin = 15 to the enum properly extends the derivation path references to support CoinJoin functionality. This change integrates well with the existing enumeration structure.

DashSync/shared/Models/Messages/CoinJoin/DSSendCoinJoinQueue.m (4)

18-21: Proper imports for the new CoinJoin message class

The imports are appropriate for the functionality being implemented. The class includes the necessary header files for its operation.


24-26: Factory method for creating CoinJoin queue messages

The implementation of the factory method follows good Objective-C patterns by providing a convenient way to create instances of this class.


28-34: Initializer properly sets up the message type

The initializer correctly calls the superclass initializer with the appropriate message type (MSG_SENDDSQ) and stores the boolean flag.


36-38: Serialization method for the CoinJoin queue message

The toData method efficiently serializes the boolean value into a single byte, which is appropriate for this type of flag message.

DashSync/shared/Models/Wallet/DSWallet+Protected.h (1)

49-49:

Details

❓ Verification inconclusive

Security concern: Method added to access seed without authentication

The addition of requestSeedNoAuth method raises security concerns as it appears to provide access to the wallet's seed data without requiring authentication.

While this may be necessary for CoinJoin operations, accessing the seed without authentication could potentially expose sensitive cryptographic material if not properly controlled.

Please verify that:

  1. This method is only used in secure contexts
  2. There are appropriate safeguards to prevent unauthorized access
  3. The implementation includes proper access controls

🏁 Script executed:

#!/bin/bash
# Search for usages of requestSeedNoAuth to understand its context and security controls
rg -A 3 -B 3 "requestSeedNoAuth" --type objc --type h

Length of output: 2421


Action: Verify secure usage of requestSeedNoAuth

After checking the code, I noted the following:

  • Declaration & Implementation:

    • The method is declared in DashSync/shared/Models/Wallet/DSWallet+Protected.h and implemented in DashSync/shared/Models/Wallet/DSWallet.m.
    • The implementation includes a comment clarifying that this method is invoked “when we request the seed without a pin code,” suggesting it’s meant for specific use cases (e.g., CoinJoin operations).
  • Usage Context:

    • In DashSync/shared/Models/Wallet/DSAccount.m, the method is called within an @autoreleasepool intended to manage sensitive data, reinforcing that its use is confined to controlled internal operations.

Recommendations:

  • Secure Context Assumptions: Ensure that every invocation of requestSeedNoAuth is indeed limited to the intended secure contexts (e.g., during CoinJoin operations).
  • Access Controls: Confirm that higher-level components (or surrounding methods) enforce proper safeguards so that no unauthorized part of the codebase can access seed data unexpectedly.
  • Documentation: It might be beneficial to add explicit comments or documentation that outline the intended use and any protection mechanisms that exist, to prevent accidental misuse in the future.

Please verify that these conditions hold across all relevant code paths.

DashSync/shared/Models/CoinJoin/DSTransactionInput+CoinJoin.m (4)

18-22: Code includes proper imports

The category implementation includes all necessary imports for BigIntTypes, DSTransactionInput base class, category interface, and utility methods from NSData.


23-24: Category declaration looks good

The category declaration properly extends DSTransactionInput with CoinJoin functionality.


25-40: Implementation of ffi_malloc method handles memory allocation correctly

The implementation properly allocates memory for a TransactionInput structure and initializes all its fields from the Objective-C object. It correctly handles hash, index, sequence, script, and signature data.


42-56: Memory cleanup in ffi_free is robust

The ffi_free method properly checks for null pointers before attempting to free memory, which prevents potential crashes. The memory freeing sequence is also correct - freeing contained objects before freeing the container.

DashSync/shared/Models/CoinJoin/DSCompactTallyItem.h (3)

18-20: Imports look good

The header includes the necessary Foundation framework and DSInputCoin.h for dependent types.


23-28: Class interface and properties are well defined

The DSCompactTallyItem class has appropriate property declarations with proper memory management attributes (strong references) and appropriate types.


1-34:

Details

❓ Verification inconclusive

Missing CompactTallyItem struct definition

The header refers to a CompactTallyItem struct type and ChainType enum, but these aren't defined or imported in this file. Consider adding the struct definition or import the appropriate header that defines these types.

Please verify that the CompactTallyItem struct and ChainType enum are properly defined in another header file that's accessible to this class.


🏁 Script executed:

#!/bin/bash
# Check for CompactTallyItem struct definition
echo "Searching for CompactTallyItem definition:"
rg -A 5 "typedef struct.*CompactTallyItem" --type c --type cpp --type objc
echo "---"
echo "Searching for ChainType definition:"
rg -A 5 "typedef enum.*ChainType" --type c --type cpp --type objc

Length of output: 335


Double-check the definitions for CompactTallyItem and ChainType.

The header in DashSync/shared/Models/CoinJoin/DSCompactTallyItem.h references a CompactTallyItem struct and a ChainType enum, but our search didn’t reveal any definitions or imports for these types. Please manually verify if these types are defined in an external header or elsewhere in the codebase. If they are found in another header, update the imports accordingly; otherwise, consider adding the necessary definitions to resolve potential compilation issues.

  • File: DashSync/shared/Models/CoinJoin/DSCompactTallyItem.h, Lines: 1-34
Example/DashSync/Contacts.storyboard (4)

2-6: Updated tooling versions in storyboard

The storyboard file has been updated with newer Xcode tooling versions:

  • toolsVersion updated from "19162" to "22505"
  • IBCocoaTouchPlugin updated from "19144" to "22504"

These updates are necessary to support development with the latest Xcode version.


51-51: Improved color handling with system colors

The storyboard now uses systemBackgroundColor instead of hardcoded white colors, which provides better support for Dark Mode in iOS.

Also applies to: 665-665


54-54: Updated layout positioning for UI elements

The y-position values for various UI elements have been adjusted, likely to accommodate display changes in newer iOS versions or to improve overall layout appearance. These changes are consistent throughout the storyboard.

Also applies to: 125-125, 150-150, 180-180, 274-274, 319-319, 366-366, 395-395, 424-424, 453-453, 490-490, 527-527, 564-564, 640-640, 648-648, 704-704


1-725:

Details

❌ Incorrect review comment

Missing CoinJoin UI elements

Despite the PR being focused on adding CoinJoin functionality, there doesn't appear to be any new UI elements or controllers specific to CoinJoin in this storyboard. Consider adding CoinJoin-specific UI components to enable user interaction with the new feature.

Let's verify if CoinJoin UI elements might be defined in other storyboard files:


🏁 Script executed:

#!/bin/bash
# Search for CoinJoin UI elements in other storyboard files
echo "Searching for CoinJoin UI components in storyboards:"
rg -A 3 "CoinJoin" --type=xml --glob="*.storyboard"
echo "---"
echo "Searching for CoinJoin view controllers:"
rg -A 3 "DSCoinJoin.*ViewController" --type=objc --type=h

Length of output: 3704


CoinJoin UI Is Present, But in the Correct Location

After verifying, the CoinJoin-specific UI components are implemented in the Actions storyboard—not in Contacts.storyboard. In particular:

  • The Actions storyboard (located at Example/DashSync/Actions.storyboard) contains a label with the text "CoinJoin" and a segue (identifier "CoinJoinSeque") that leads to the DSCoinJoinViewController.
  • The CoinJoin view controller (DSCoinJoinViewController) is correctly defined and wired (including its coinJoinSwitch outlet).

Based on this, the absence of CoinJoin UI elements in Contacts.storyboard is expected. Please confirm that this separation aligns with the intended design.

Likely an incorrect or invalid review comment.

DashSync/shared/Models/Transactions/Coinbase/DSCoinbaseTransaction.m (3)

106-107: Updated method signature to support anyoneCanPay flag

The toDataWithSubscriptIndex: method now includes an additional anyoneCanPay: parameter, which is important for CoinJoin transactions. This parameter allows inputs to be added to a transaction without invalidating existing signatures.


109-109: Updated superclass method call to include new parameter

The call to the superclass implementation properly passes the new anyoneCanPay parameter, maintaining consistent behavior.


1-126:

Details

❓ Verification inconclusive

Consider testing CoinJoin transactions with anyoneCanPay flag

The addition of the anyoneCanPay flag is a significant change to transaction signing. Ensure comprehensive testing of this feature with CoinJoin transactions to verify that transaction signatures remain valid when inputs are added or modified.

Are there test cases that validate the behavior of transactions using the anyoneCanPay flag, especially in the context of CoinJoin operations?


🏁 Script executed:

#!/bin/bash
# Check for tests related to anyoneCanPay and CoinJoin
echo "Searching for anyoneCanPay tests:"
rg -A 5 "anyoneCanPay.*test" --type objc --type=m
echo "---"
echo "Searching for CoinJoin tests:"
rg -B 1 -A 5 "test.*CoinJoin" --type objc --type=m

Length of output: 317


Action: Verify test coverage for CoinJoin transactions with the anyoneCanPay flag

The recent search for tests (using rg with file type adjustments) did not yield clear results. Please manually confirm whether our test suite covers the following:

  • anyoneCanPay flag behavior: Validate that transaction signatures remain correct when inputs are added/modified.
  • CoinJoin transactions: Ensure tests simulate scenarios where multiple inputs interact safely under the anyoneCanPay signing mode.

If such tests are missing or incomplete, please add comprehensive coverage to prevent potential regressions.

DashSync/shared/Models/Platform/Transitions/BlockchainIdentity/DSBlockchainIdentityUpdateTransition.m (1)

168-170:

Details

❓ Verification inconclusive

Method signature updated for CoinJoin support.

The method has been correctly updated to include the anyoneCanPay parameter and pass it to the superclass implementation.

Since this is a public-facing API change, we should verify that all callers of this method have been updated to provide the anyoneCanPay parameter.


🏁 Script executed:

#!/bin/bash
# Find all calls to toDataWithSubscriptIndex: that might need updating
rg -A 2 -B 2 "toDataWithSubscriptIndex:" --glob "*.m" | grep -v "anyoneCanPay"

Length of output: 8120


API Change Verification Needed for CoinJoin Support

The updated method in DSBlockchainIdentityUpdateTransition.m now correctly includes the anyoneCanPay parameter when it calls its superclass implementation. However, a grep search across the codebase revealed several implementations of toDataWithSubscriptIndex: (for example, in the following files) that do not pass an anyoneCanPay parameter:

  • DashSync/shared/Models/Transactions/Quorums/DSQuorumCommitmentTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRegistrarTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateServiceTransaction.m
  • DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRevocationTransaction.m
  • DashSync/shared/Models/Transactions/Coinbase/DSCoinbaseTransaction.m
  • DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m
  • DashSync/shared/Models/Transactions/Base/DSTransaction.m
  • DashSync/shared/Models/Transactions/Provider/DSProviderRegistrationTransaction.m

Because this is a public-facing API change, please take a closer look to ensure that all external callers expected to use the updated signature are indeed passing the new anyoneCanPay parameter. Verify whether the above occurrences represent legacy implementations that aren’t intended to use the CoinJoin API or if they also require an update.

DashSync/shared/Models/Managers/Chain Managers/DSPeerManager.m (4)

60-60: Import added for CoinJoin functionality.

The import for DSSendCoinJoinQueue.h is necessary to support the new CoinJoin feature being integrated.


700-703: Improved error handling with better logging.

The refactored conditional expands the single-line check into a more readable structure with clearer error logging, which aids in debugging when connections fail due to wallet creation issues.


887-891: Added CoinJoin request support to peer connections.

This code properly checks if CoinJoin queue requests should be sent (self.shouldSendDsq), and integrates with the peer connection flow to send these requests when needed.


1074-1080: New method for CoinJoin queue management.

This method provides the functionality to enable or disable CoinJoin queue requests across all connected peers, which is essential for the CoinJoin feature. The implementation correctly iterates through all connected peers and sends the appropriate request.

DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRegistrarTransaction.m (1)

183-187:

Details

❓ Verification inconclusive

Updated method signature to support CoinJoin.

The method toDataWithSubscriptIndex: has been updated to include an anyoneCanPay parameter, which is passed to the superclass implementation. This change supports the CoinJoin functionality by allowing transactions to be signed with the SIGHASH_ANYONECANPAY flag.

Make sure similar changes have been applied to other transaction classes that might need the anyoneCanPay parameter to maintain consistency across the codebase.


🏁 Script executed:

#!/bin/bash
# Check if other transaction classes have been updated with anyoneCanPay parameter
echo "Searching for other transaction classes that need to be updated with anyoneCanPay parameter..."
rg -A 1 "toDataWithSubscriptIndex:" --type objc | grep -v "anyoneCanPay"

Length of output: 3337


Verify consistency of the anyoneCanPay update across transaction classes

The updated signature in DSProviderUpdateRegistrarTransaction.m now correctly accepts the anyoneCanPay parameter to support CoinJoin. However, our grep search shows that several other transaction classes still use the previous implementation without the anyoneCanPay parameter. Please verify if these classes are intended to remain unchanged or if they also need to be updated to support CoinJoin functionality. For example:

  • Base Transactions:

    • DSAssetLockTransaction.m
    • DSAssetUnlockTransaction.m
  • Provider Transactions:

    • DSProviderRegistrationTransaction.m
    • DSProviderUpdateServiceTransaction.m
    • DSProviderUpdateRevocationTransaction.m
  • Other Transactions:

    • DSQuorumCommitmentTransaction.m
    • DSCoinbaseTransaction.m

Ensure that the design intentionally excludes the parameter in these cases or update them accordingly to maintain consistency across the codebase.

DashSync/shared/Models/CoinJoin/DSTransactionOutput+CoinJoin.m (1)

48-60: Memory cleanup for FFI structures.

The method properly handles freeing the memory allocated for the C struct, including checks for NULL pointers before attempting to free memory.

DashSync/shared/DashSync.m (3)

22-22: Import for CoinJoin manager integration.

This import is necessary to access the CoinJoin manager functionality.


126-127: Properly stop CoinJoin operations before disconnecting peers.

This ensures CoinJoin operations are cleanly stopped before disconnecting peer managers when stopping sync for all chains, preventing potential race conditions or resource leaks.


133-133: Stop CoinJoin manager for specific chain.

This parallels the change in stopSyncAllChains but for a single chain, maintaining consistency in how CoinJoin operations are handled during shutdown.

DashSync/shared/Models/Transactions/Provider/DSProviderRegistrationTransaction.m (2)

232-233: Method signature updated to support CoinJoin functionality.

The addition of the anyoneCanPay parameter allows the transaction to be compatible with CoinJoin operations. This flag is crucial for indicating whether a transaction signature permits combining with other transactions.


235-235: Implementation properly forwards the anyoneCanPay flag to the superclass.

The implementation correctly passes the new parameter to the superclass method, ensuring consistent behavior throughout the transaction hierarchy.

Example/DashSync/Wallets.storyboard (5)

2-2: Updated toolsVersion to support newer Xcode development environment.

The toolsVersion has been updated from 21507 to 32700.99.1234, indicating compatibility with a newer Xcode version.


6-6: Updated IBCocoaTouchPlugin version for compatibility.

The IBCocoaTouchPlugin version has been updated to 22685, ensuring compatibility with the newer toolset.


8-8: Added support for system colors in document resources.

This addition enables the use of iOS system colors, which automatically adapt to light/dark mode and other appearance settings. This improves UI consistency and user experience.


664-664: Updated background colors to use system colors for better appearance adaptation.

Changed from custom gray colors to system background colors, which will adapt to the user's preferred appearance (light/dark mode), improving accessibility and user experience.

Also applies to: 852-852, 1017-1017


1387-1389: Added systemBackgroundColor resource definition.

Added a proper system color resource definition that will be used throughout the interface, ensuring consistent appearance.

Example/DashSync/DSCoinJoinViewController.m (2)

25-31: LGTM: IBAction properly handles the CoinJoin switch state changes.

The method correctly calls either startCoinJoin or stopCoinJoin based on the switch state.


18-22:

Details

❌ Incorrect review comment

Interface file imports appear correct, but property declarations are missing.

The code imports necessary headers but doesn't show property declarations for UI elements or the coinJoinManager.

Verify that the header file includes the necessary property declarations:


🏁 Script executed:

#!/bin/bash
# Check for property declarations in the header file
grep -A 20 "@interface DSCoinJoinViewController" --include="*.h" -r .

Length of output: 866


Interface File Property Declarations Verified
After reviewing the header file, all necessary property declarations for UI elements and the coinJoinManager are present. Specifically, the following properties were confirmed in Example/DashSync/DSCoinJoinViewController.h:

  • DSChainManager *chainManager
  • IBOutlet UISwitch *coinJoinSwitch
  • IBOutlet UILabel *infoLabel
  • DSCoinJoinManager *coinJoinManager

Thus, the comment suggesting that property declarations are missing is incorrect.

Likely an incorrect or invalid review comment.

DashSync/shared/Models/Transactions/Provider/DSProviderUpdateRevocationTransaction.m (2)

151-152: Method signature updated to support CoinJoin functionality.

The addition of the anyoneCanPay parameter aligns with the changes made throughout the codebase to support CoinJoin operations. This flag is crucial for transaction signing in CoinJoin.


154-154: Implementation properly forwards the anyoneCanPay flag to the superclass.

The implementation correctly passes the new parameter to the superclass method, ensuring consistent behavior throughout the transaction hierarchy.

DashSync/shared/Models/Transactions/Provider/DSProviderUpdateServiceTransaction.m (1)

200-203: Method signature updated to support CoinJoin functionality

The toDataWithSubscriptIndex: method has been updated to include an anyoneCanPay parameter, which is essential for CoinJoin transactions. The implementation correctly passes this parameter to the superclass method.

DashSync/shared/Libraries/DSLogger.m (2)

53-59: Enhanced logging with compression

Good improvement to the logging system. Adding compression for log files will help reduce storage usage on mobile devices. The 5MB size limit and 10 file retention policy are reasonable choices.


67-82: Updated log file retrieval to support compressed logs

The updated logFiles method now correctly handles both .log and .gz file extensions, ensuring compressed logs are properly included in the returned array.

DashSync/shared/Models/CoinJoin/DSInputCoin.m (3)

23-32: Initialization looks correct.

The initializer properly captures transaction data for a specific output index, storing the outpoint hash, index, output reference, and amount. This implementation is clean and straightforward.


34-42: FFI memory allocation is properly implemented.

The ffi_malloc: method correctly allocates memory for the FFI structure, setting all required fields from the Objective-C object. The pattern of allocating memory for complex types (like the hash and output) follows good practices.


44-56: Memory deallocation is thorough and safe.

The ffi_free: method implements proper memory management by:

  1. Checking for null before attempting to free memory
  2. Freeing nested allocated objects first
  3. Finally freeing the containing structure

This pattern prevents memory leaks and avoids attempting to free null pointers.

DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinEntryMessage.m (4)

23-25: Simple factory method implementation.

The class method provides a convenient way to create instances and follows standard Objective-C patterns.


27-29: Message type is correctly defined.

This method returns a constant string (MSG_COINJOIN_ENTRY) which allows for consistent message type identification.


31-37: Initializer properly stores data.

The initialization method is straightforward, storing the provided data for later retrieval.


39-45: Accessor methods are correctly implemented.

Both the type and toData methods are simple accessors that return the appropriate values. The instance method type correctly delegates to the class method, promoting code reuse.

DashSync/shared/Models/Wallet/DSWallet.h (2)

178-178: Added CoinJoin gap limit parameter.

The method signature has been updated to include a coinJoinGapLimit parameter, which is appropriate for the CoinJoin functionality being integrated. This parameter will help control the generation of addresses specific to CoinJoin operations.


192-193: New method for validating input spendability.

The added method inputValue:inputIndex: provides a way to check if a specific input is valid and hasn't been previously spent, returning its value or -1 if invalid. This is essential for CoinJoin operations where input validity needs to be verified.

DashSync/shared/Models/CoinJoin/DSCompactTallyItem.m (1)

22-29: Basic initialization looks good.

The initializer properly sets up initial values for amount and creates an empty array for input coins.

DashSync/shared/Models/Messages/CoinJoin/DSCoinJoinAcceptMessage.m (1)

1-47: Implementation looks clean and follows best practices.

The DSCoinJoinAcceptMessage class is well-implemented, providing the necessary methods for handling CoinJoin accept messages including initialization, type identification, and data serialization. The code follows standard Objective-C patterns and is consistent with other message handling classes in the codebase.

Example/DashSync/Actions.storyboard (3)

2-9: Successfully updated tooling and added system colors support.

The storyboard has been updated to the latest tooling versions and now includes system colors capability, which is good for maintaining compatibility with recent iOS versions.


109-131: CoinJoin UI element properly added to the actions table.

The new CoinJoin table view cell has been correctly implemented with proper constraints and connection to the CoinJoin view controller. This follows the same pattern as other action items in the table.


767-826: CoinJoin view controller implementation looks good.

The new DSCoinJoinViewController has been properly integrated with a well-configured UI layout following the same patterns as other similar controllers. The outlets are correctly connected and the controller includes action handling for the CoinJoin switch.

DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m (4)

63-65: Well-structured method delegation.

The payloadData method delegates to basePayloadData, which is a good design pattern allowing for future specialization in subclasses if needed.


67-78: Solid implementation of payload serialization.

The basePayloadData method properly constructs the transaction payload, including the special transaction version, credit output count, and output details. The implementation is correct and follows the pattern established in the rest of the codebase.


80-87: Thread-safe transaction serialization with support for anyoneCanPay.

The addition of the anyoneCanPay parameter to the serialization method is a good enhancement that provides more flexibility for signing. The implementation correctly uses synchronization to ensure thread safety.


89-91: Simple and effective size calculation method.

The size method correctly calculates the total transaction size by adding the payload data length to the parent class's size. This follows good object-oriented principles by reusing the parent's functionality.

DashSync/shared/Models/Derivation Paths/DSFundsDerivationPath.m (3)

40-44: CoinJoin derivation path implementation looks good.

The new method creates a specialized derivation path for CoinJoin with proper feature purpose constants and account indexing. The implementation is consistent with other derivation path creation methods in the class.


116-128: Improved gap limit selection based on derivation path type.

The modification to select gap limits based on path type (particularly distinguishing anonymous funds paths for CoinJoin) is a good enhancement. This allows for different address management strategies depending on the path's purpose.


153-155: Improved error handling for unloaded addresses.

This change enhances robustness by returning an empty array rather than potentially failing when addresses haven't been loaded for non-transient wallets. This is a good defensive programming practice.

Example/DashSync/DSTransactionsViewController.m (4)

12-12: Good addition of DSCoinJoinManager import.

This import is necessary for the CoinJoin transaction type determination functionality being added later in the file.


320-320: Simplifying balance calculation improves readability.

Replacing a potentially more complex balance calculation with a direct call to [account balance] makes the code more maintainable and easier to understand.


369-396: Well-structured CoinJoin transaction type detection and display.

The code properly identifies CoinJoin transaction types and assigns appropriate display strings. The switch statement handles all known transaction types with a default case for unknown types.


397-418: Good organization of conditional logic for transaction display.

The code maintains the original transaction display logic inside an else clause while adding CoinJoin-specific display logic. This approach maintains backward compatibility while adding new functionality.

DashSync/shared/Models/CoinJoin/Utils/DSMasternodeGroup.h (5)

1-16: Well-documented license header.

The license header clearly indicates MIT licensing terms, which is important for open-source projects.


18-25: Appropriate imports and forward declaration.

The file imports only the necessary headers and uses a forward declaration for DSCoinJoinManager to avoid circular dependencies.


26-29: Good interface definition with appropriate protocol adoption.

The class inherits from NSObject and adopts the DSPeerDelegate protocol, which is appropriate for a class that will interact with peers. The isRunning property is correctly marked as atomic and readonly for thread safety.


30-40: Well-designed API for masternode management.

The class provides a comprehensive set of methods for initializing, starting, stopping, and managing masternode connections. The method names clearly indicate their purpose, and the parameters are appropriately typed.


38-39:

Details

❓ Verification inconclusive

Verify block parameter capturing.

Ensure that the block parameter in forPeer:port:warn:withPredicate: doesn't create strong reference cycles. Consider adding __weak typeof(self) weakSelf = self; in the implementation before using self in the block.


🏁 Script executed:

#!/bin/bash
# Check implementation for weak self usage in the predicate block

# Search for the implementation file
fd -e m "DSMasternodeGroup" --exec rg -A 10 "forPeer:(UInt128)ip port:(uint16_t)port warn:(BOOL)warn withPredicate:" {} \;

Length of output: 125


Action Required: Verify Weak Capturing in Block Implementation

The initial search for the implementation of the forPeer:port:warn:withPredicate: method did not return any matching context, so we can’t confirm whether a weak reference to self is used in the predicate block. Please manually verify the implementation (likely in DSMasternodeGroup.m) that calls this method to ensure that self is captured weakly (e.g., using __weak typeof(self) weakSelf = self;) to avoid strong reference cycles.

  • File to check: DSMasternodeGroup.m (implementation of forPeer:port:warn:withPredicate:)
  • Verification: Confirm that a weak reference is established before referencing self in the block.
DashSync/shared/Models/Chain/DSChain.m (2)

654-661: CoinJoin derivation path added to standard derivation paths

The implementation now properly includes CoinJoin derivation paths in the standard derivation paths for both zero and non-zero account numbers. This allows the wallet to generate and manage addresses specifically for CoinJoin operations, enhancing privacy features.


1233-1234: CoinJoin gap limit parameter added to address registration

The update to the registerAddressesWithGapLimit method now includes a coinJoinGapLimit parameter set to SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN. This allows the wallet to properly register and track CoinJoin-specific addresses with an appropriate gap limit, ensuring that enough addresses are available for CoinJoin operations.

DashSync/shared/Models/Managers/Chain Managers/DSMasternodeManager.m (1)

168-175: LGTM! Good reuse of functionality.

This new method extracts the functionality previously contained in hasMasternodeAtLocation:port: and provides a clearer interface by returning the actual masternode entry rather than just a boolean. This improves reusability and follows good design principles.

DashSync/shared/Models/CoinJoin/DSTransaction+CoinJoin.m (1)

109-131: LGTM! Properly handles memory deallocation with null checks.

The ffi_free: method correctly handles memory deallocation for the Transaction struct and its components, including checking for null pointers before attempting to free memory, which prevents potential crashes.

DashSync/shared/Models/CoinJoin/DSCoinJoinBalance.m (2)

46-59: LGTM! Good memory allocation with proper field mapping.

The ffi_malloc method correctly allocates and populates a C-style Balance structure. Each property is properly mapped from the Objective-C object to the C structure.


61-65: LGTM! Proper null check before freeing memory.

The ffi_free: method correctly checks if the balance pointer is not null before freeing it, preventing potential crashes.

DashSync/shared/Models/Network/DSPeer.h (2)

140-149: LGTM! Clean transition from Darksend to CoinJoin message constants.

The changes replace Darksend message constants with CoinJoin message constants, which aligns with the broader update to implement CoinJoin functionality across the codebase. The new constants follow a consistent naming convention.


140-149: Additions for CoinJoin message definitions look consistent.
All new message constants follow a coherent naming pattern. They align well with existing prefixes (MSG_COINJOIN_).

DashSync/shared/Models/Transactions/Base/DSTransaction.h (3)

51-51: Ensure consistent usage documentation for the new sighash flag.
The newly introduced SIGHASH_ANYONECANPAY flag is a valuable addition for advanced transaction signing scenarios. To aid future maintainers, consider adding usage notes or relevant references (e.g., BIP143, BIP145) explaining when and why this flag is triggered.


149-149:

Details

✅ Verification successful

Request verification of updated calls to the extended sign method.
The new parameter anyoneCanPay extends signWithPrivateKeys:. Verify all call sites of this API have been updated to pass or handle anyoneCanPay.


🏁 Script executed:

#!/bin/bash
rg "signWithPrivateKeys:.*anyoneCanPay:"

Length of output: 542


All call sites properly updated

Verification shows that every invocation of signWithPrivateKeys: now includes the anyoneCanPay parameter. In particular:

  • DashSync/shared/Models/Wallet/DSAccount.m – Calls signWithPrivateKeys:privkeys anyoneCanPay:anyoneCanPay as expected.
  • DashSync/shared/Models/Transactions/Base/DSTransaction.m – Calls signWithPrivateKeys:keys anyoneCanPay:NO and the method definition correctly includes the new parameter.

No further modifications are necessary.


159-159:

Details

❓ Verification inconclusive

Check interaction between subscript index and SIGHASH options.
The subscript index is crucial when generating partial signatures. Ensure the new anyoneCanPay parameter is properly integrated with subscript logic to avoid partial signing bugs.


🏁 Script executed:

#!/bin/bash
rg "toDataWithSubscriptIndex:.*anyoneCanPay:"

Length of output: 3504


Critical: Verify Subscript–SIGHASH Interaction in Partial Signature Generation
Please ensure that the new anyoneCanPay parameter is correctly integrated with the subscript index logic across all transaction signing paths. In particular:

  • Verify that when a valid subscript index is passed (or when NSNotFound is used), the resulting data correctly reflects the intended SIGHASH behavior.
  • Confirm that all call sites (e.g., in DSAssetLockTransaction, DSAssetUnlockTransaction, DSProvider transactions, and others) consistently forward the anyoneCanPay parameter without disrupting the partial signature generation process.
  • Double-check that the updated logic does not inadvertently alter the expected SIGHASH flags when generating the signature hash.

Please review these interactions carefully during testing to rule out any potential partial signing issues.

DashSync/shared/Libraries/Logs/CompressingLogFileManager.m (3)

49-80: Consider concurrency constraints during initialization.
Within initWithFileSize: and initWithLogsDirectory:, the delayed call to compressNextLogFile might compete with other file operations. Verify that no race conditions occur if multiple threads call initialization methods simultaneously.


134-188: Validate file filtering and retention logic.
The method handleProcessorLogRotationWithSortedLogs: purges logs older than five days and sorts them by date. Confirm that files with unusual naming or date formats do not accidentally remain uncompressed.


227-508: Check buffer sizes and partial write loops for edge cases.
The main compression loop handles partial reads/writes and manages leftover input data. Verify negative or zero-length corner cases—especially if an empty file or I/O error occurs while partially compressing.

DashSync/shared/Models/Wallet/DSWallet.m (1)

858-862:

Details

❓ Verification inconclusive

Confirm coinJoinGapLimit usage throughout the address derivation.
Adding coinJoinGapLimit modifies address registration logic. Ensure the code that triggers or references this gap limit properly aligns with the new parameter.


🏁 Script executed:

#!/bin/bash
rg "coinJoinGapLimit"

Length of output: 2863


Confirm CoinJoinGapLimit Propagation and Alignment
The coinJoinGapLimit parameter is now consistently propagated through the address registration chain:

  • In DSWallet, the parameter is passed to each account via registerAddressesWithGapLimit:unusedAccountGapLimit:dashpayGapLimit:coinJoinGapLimit:internal:error:.
  • In DSAccount, it is correctly applied by setting registerGapLimit = coinJoinGapLimit.
  • In DSTransactionManager and DSChain, calls to register addresses use the predefined gap limits (e.g., SEQUENCE_GAP_LIMIT_INITIAL_COINJOIN), which correspond to the coinJoinGapLimit usage.

Please verify that these macros and parameter values align with the intended coin join address derivation logic and that no downstream logic is inadvertently bypassing or misinterpreting the coinJoinGapLimit.

DashSync/shared/Models/Transactions/Base/DSTransaction.m (4)

326-366: Validate partial transaction logic.

Returning UINT64_MAX for a partial or incorrect sync scenario (line 348) may mask potential issues. Consider adding logging or additional checks to alert you when underlying transaction data may be incomplete, instead of silently returning UINT64_MAX.


369-377: Cached direction fallback.

When cachedDirection is DSTransactionDirection_NotAccountFunds, you recalculate its direction and then cache it. This logic appears correct, but ensure subsequent path logic (such as UI updates or fee calculations) properly handles the newly cached direction.


423-434: Coinbase maturity check.

These new methods correctly account for Dash’s coinbase maturity rules. Confirm that COINBASE_MATURITY + 1 remains consistent with network parameters if upgraded in the future.


648-690: Check concurrency for signing.

Using @synchronized(self) here ensures thread safety while signing. This approach looks good. However, if multiple threads sign different transactions simultaneously, cross-class concurrency concerns could still exist. Confirm that upper-level orchestration properly manages multi-transaction concurrency.

DashSync/shared/Models/Network/DSPeer.m (3)

67-67: Import addition looks good.
Including "DSCoinJoinManager.h" is essential for handling CoinJoin messages.


848-858: Confirm that CoinJoin message handling is fully tested.
The new conditionals for MSG_COINJOIN_* types effectively route messages to the CoinJoin manager. Ensure thorough coverage in the integration tests to detect potential regressions quickly.


1067-1067: Validate the DSInvType_DSTx scenario.
Adding DSInvType_DSTx to handle special transaction broadcasts is logical. However, ensure any fallback behavior in the surrounding logic remains correct. Verify no unhandled or unintended DSInvType cases remain, especially when toggling between standard transactions and DSTx.

DashSync/shared/Models/Managers/Chain Managers/DSTransactionManager.h (2)

89-89: Verify 'mixedOnly' usage in transaction flows.
The new mixedOnly parameter expands the method’s functionality to handle exclusively mixed transactions. Ensure downstream call sites and test scenarios are updated to reflect the new argument, preventing silent failures.


101-101: Ensure 'mixedOnly' is properly integrated in protocol requests.
Similar to the sign-and-publish flow, confirm that the code path calling confirmProtocolRequest:... handles mixedOnly consistently. This prevents logical gaps when toggling the mixing requirement.

DashSync/shared/Models/Wallet/DSAccount.m (14)

64-64: Noting the new import statement.

Importing "DSCoinControl.h" suggests you're preparing for selective coin control or advanced transaction handling. Ensure this file doesn't introduce circular dependencies or unused imports.


113-114: Introducing a dedicated property for CoinJoin derivation path.

Declaring a coinJoinDerivationPath as a strong property is a clear step toward separating anonymous (CoinJoin) funds. Confirm usage across the codebase to ensure it’s strictly used for CoinJoin-related addresses.


185-186: Input validation.

NSParameterAssert(derivationPaths); again helps ensure you never initialize an account with empty derivation paths. Looks good in preventing invalid states.


210-211: Input validation.

Likewise, verifying derivationPaths for the view-only initializer is consistent. No concerns.


215-215: Empty line removed or added.

A negligible formatting adjustment. No issues noted from a functionality perspective.


246-247: Revisiting fetch request logic.

It’s unclear what changed beyond potential whitespace or comments. Ensure that any removed or added lines don’t break the fetch logic for DSTxOutputEntity.

Please confirm if the fetch request logic remains identical (e.g., same predicate) with no side effects.


350-357: Introducing coinJoinReceiveAddress.

Returns the first unused CoinJoin address, then registers it. The synchronous dispatch on networkingQueue is consistent with your concurrency approach.


359-366: Introducing coinJoinChangeAddress.

Similarly, returns the first unused CoinJoin change address and ensures it’s registered. This will help isolate mixing funds. Implementation is consistent with the receive method.


368-370: Getter for all CoinJoin receive addresses.

Lists all derived addresses for CoinJoin receiving. Straightforward addition.


372-374: Getter for used CoinJoin receive addresses.

Mirrors the typical pattern from the base wallet logic.


375-375: Minor line addition or removal.

No functionality impact observed.


556-556: Reformatting or clarifying condition in containsAddress:.

Ensures the address string is valid. Good defensive check.


563-574: New containsCoinJoinAddress: method.

A specialized check. Reuses the approach from containsAddress: but specifically for the coinJoinDerivationPath. Straightforward.


833-843: Adjusting final balance updates in updateBalance.

Tracking _balance, _spentOutputs, _invalidTransactionHashes, etc., in one place is good. The asynchronous notification dispatch is consistent with the existing approach.

DashSync/shared/Models/CoinJoin/Utils/DSMasternodeGroup.m (25)

1-16: License header and file docstring.

File creation includes a standard MIT license. All good.


18-31: Imports and constants.

Constants like MIN_PEER_DISCOVERY_INTERVAL and DEFAULT_INITIAL_BACKOFF define the fundamental timing for your group connection logic. Looks appropriate.


58-82: - initWithManager:
Initializes the group with DSCoinJoinManager, sets up structures for sessions, backoff, etc. The approach is coherent.


92-100: - stopAsync
Removes notifications and sets _isRunning to false. Make sure this effectively halts ongoing connection attempts that might be mid-flight on networkingQueue.

Double-check any scheduled dispatch_after tasks to confirm they won’t override the _isRunning = false state.


117-130: - disconnectMasternode:port:
Moves a connected peer to a closing list, updates max connections, and initiates disconnect. Clear logic for gracefully dropping a masternode.


132-154: - forPeer:port:warn:withPredicate:
Pattern for applying an arbitrary predicate to a matching peer. This is flexible and reuses the same iteration. Ensure consistent usage and watchers for concurrency or repeated calls.


156-164: - isNodePending:port:
Simple check in self.pendingPeers. Perfectly in line with the concurrency approach (synchronized blocks for reading).


166-170: connectedPeers getter.

Returns a copy of the set under lock. Good concurrency safety measure.


172-176: pendingPeers getter.

Same concurrency approach, returning a copy. Looks fine.


178-182: pendingClosingMasternodes getter.

Wraps an internal array with a copy, again consistent concurrency.


184-188: pendingSessions getter.

Same concurrency pattern. All consistent.


190-192: - triggerConnections
Simply defers to triggerConnectionsJobWithDelay:0. Concise bridging method.


246-291: - getNextPendingMasternode
Iterates pendingSessions, finds the peer with the smallest retryTime, skipping those that are shutting down. This approach is helpful for a backoff-based connection manager.


293-305: - mixingMasternodeAddressFor:
Retrieves the masternode info for a given session. Straight usage of the sessionMap dict. Straightforward.


307-322: - addPendingMasternode:clientSessionId:
Logs the new session, updates local maps, triggers a re-check, and re-sizes max connections. Looks good.


324-353: - updateMaxConnections
Recalculates _maxConnections, ensures it cannot exceed the user’s configured session limit, then calls updateMaxConnections: to adjust active connections as needed. Solid approach.


355-398: - checkMasternodesWithoutSessions
Identifies connected peers not associated with any session, then drops them. This helps keep extraneous masternodes from occupying resources.


400-407: - hostFor:
Converts UInt128 to a string. Straight reimplementation or adaptation. No issues.


461-465: - isMasternodeSessionByPeer:
Looks up if a peer is in addressMap. Straight logic.


467-471: - isNodeConnected:
Reuses forPeer:port:warn:withPredicate: to confirm connectivity. Fine.


473-481: - isNodePending:
Checks pendingPeers list for a match. Fine.


483-497: - peerConnected:
Marks the peer as fully connected, updates backoff, possibly sends DSQ request. The concurrency usage looks correct.


556-558: - peer:relayedPeers:
Stub for future expansions? Currently empty.


560-574: - peerForLocation:port:
Searches among connected, pending, or the peerManager’s pool. This ensures you unify all sources for a given location.


576-583: - handleSyncStateDidChangeNotification:
On new blocks, triggers triggerConnections. Good approach for re-checking the group connectivity after chain progress.

DashSync/shared/Models/CoinJoin/DSCoinJoinWrapper.m (33)

1-16: License header.

Standard MIT license block. Correct.


18-31: Imports, bridging macros.

Defines bridging with Rust side, bridging macros AS_OBJC and AS_RUST. Looks consistent and well-organized.


32-33: Class implementation start.

No remarks, standard @implementation line.


34-41: - initWithManagers:chainManager:
Initializes references to the manager and chain manager. Straightforward.


53-55: - isRegistered
Returns boolean on _clientManager presence. Very direct.


57-61: - updateOptions:
Passes the updated options to the Rust side. Straight concurrency approach.


63-67: - setStopOnNothingToDo:
Calls set_stop_on_nothing_to_do, presumably controlling the background mixing loop. Clear naming.


69-73: - startMixing
Requests the Rust side to start mixing. Ensure that clientManager is non-null.


75-79: - refreshUnusedKeys
Triggers a key refresh, presumably preloading next addresses for denominating. Straightforward.


81-89: - doAutomaticDenominatingWithDryRun:
Wrapper around the Rust function do_automatic_denominating. Double-check memory usage around the Balance struct.


91-97: - doMaintenance
Closely related to denominating routine, passing the up-to-date balance to the Rust side. No immediate concerns.


99-103: - initiateShutdown
Tells Rust code to shut down client manager side. Straight usage.


105-107: - isDenominatedAmount:
Pure Rust call for quick checks. Minimal overhead.


109-114: - isFullyMixed:
Validates if a particular UTXO has the required mixing rounds. Straight concurrency approach.


115-130: - processDSQueueFrom:message:
Constructs a ByteArray from the message and calls process_ds_queue. Good bridging approach. Ensure you properly free allocated memory.


149-155: - notifyNewBestBlock:
Informs the Rust manager of the best block. Straight.


157-161: - isMixingFeeTx:
Quick boolean call. Straight line.


163-166: Class method coinJoinTxTypeForTransaction:
Figures out the relevant account, defers to the next method.


168-183: Class method coinJoinTxTypeForTransaction:account:
Allocates a Rust Transaction, determines input values, calls get_coinjoin_tx_type. Freed afterward. Good memory pattern.


185-191: - unlockOutputs:
Instructs Rust to release locked UTXOs of a transaction. No issues.


193-197: - getAnonymizableBalance:skipUnconfirmed:
Returns the rust side’s computed anonymizable balance. Straight usage.


199-201: - getSmallestDenomination
Calls coinjoin_get_smallest_denomination(). No concerns.


203-215: - getStandardDenominations
Obtains an array of denominations from Rust. Carefully frees the structure. Good example of correct bridging.


217-219: - getCollateralAmount
One-line call to Rust API. Fine.


221-223: - getMaxCollateralAmount
Same single-line pattern. Fine.


225-229: - hasCollateralInputs:
Reflects the chain’s state for collateral. Good bridging.


231-233: - amountToDenomination:
Implements a direct call to the Rust function amount_to_denomination(). Straight usage.


235-240: - getRealOutpointCoinJoinRounds:
Calls Rust method to determine actual mixing rounds for a UTXO. No observed issues.


242-261: - getSessionStatuses
Retrieves array of PoolStatus from Rust. Memory is freed after conversion. This is typical bridging.


263-267: - isLockedCoin:
Checks if a UTXO is locked for mixing. Simple bridging.


269-273: - stopAndResetClientManager
Stops and resets the internal mixing state. Straight usage.


275-277: - chain
Returns the chain from _chainManager. No issues.


290-700: Rust FFI Callbacks.

Each callback acquires a lock using @synchronized(context), bridging data to/from the Rust side. Overall the memory handling (malloc/free) looks correct. Keep carefully reviewing for potential edge cases:

  • Confirm that no concurrency race occurs if the manager is deallocated while callbacks are still in progress.
DashSync/shared/Models/Wallet/DSAccount.h (15)

29-29: No concerns about the new import.
This line simply adds the DSCoinControl import, which is presumably required by new methods.


150-152: Method name looks consistent.
containsCoinJoinAddress: complements the existing containsAddress: methods. No issues found.


184-185: Extending transaction creation with coinControl.
Allowing coin selection is beneficial for advanced transaction building. This addition looks well-structured.


251-255: Validate negative return usage.
inputValue: returns a signed int64_t, and -1 is treated as an error indicator. Ensure that any call sites handle this case properly to avoid potential misinterpretations.


29-29: New import for DSCoinControl is appropriate.
This import is needed to accommodate the coinControl parameter in subsequent methods.


57-58: New coinJoinDerivationPath property
Declaring a dedicated derivation path for CoinJoin usage enhances wallet organization.


100-111: CoinJoin receive/change address properties
These new properties for CoinJoin-specific addresses mirror the existing external/internal address model.


118-118: Added coinJoinGapLimit parameter
Including a dedicated gap limit for CoinJoin paths helps refine address generation for mixing.


150-152: containsCoinJoinAddress method
This method parallels containsAddress:, aiding in quick checks for mixing addresses.


184-185: transactionForAmounts:… coinControl parameter
Overloading the transaction creation method to add coinControl support is a clean extension for specialized use cases.


198-204: Documenting signTransaction: with improved info
These doc comment tweaks ensure clarity around usage and side effects.


205-216: signTransaction with SIGHASH_ANYONECANPAY
Providing the new parameter broadens signing options and is consistent with advanced transaction capabilities.


251-252: isSpent: method
This straightforward helper bolsters clarity for UTXO spend checks.


253-254: inputValue:… method
Differentiating this from the existing transaction-based lookups can be useful for specialized scenarios.


283-285: amountsSentByTransaction
Returning an array of individual amounts offers granular insight into the transaction’s output distribution.

DashSync/shared/Models/Managers/Chain Managers/DSTransactionManager.m (13)

56-56: Import of DSCoinJoinManager looks valid.
Confirm that it's truly needed in this implementation file to avoid unnecessary coupling.


216-222: Notification dispatch on main thread.
Posting the DSTransactionManagerTransactionStatusDidChangeNotification is a good approach. Keep an eye on concurrency or potential race conditions if related states are modified simultaneously elsewhere.


343-344: Check logic for setting updateTransaction.
Confirm that marking updateTransaction = YES; here appropriately reflects the condition under which a transaction is removed from the local sets.


354-358: Concise flow control.
Setting updateTransaction = YES; and then checking it in the subsequent block is straightforward. No immediate issues identified.


56-56: Importing DSCoinJoinManager
This import is aligned with new coinControl logic and CoinJoin functionalities.


214-223: Posting TransactionStatusDidChangeNotification on main queue
Triggering the status change event on the main thread is best practice for UI updates.


613-618: Conditional coinControl assignment
Including coinControl when mixedOnly is true integrates well with DSCoinJoinManager.
Consider verifying if an empty UTXO selection might lead to user feedback on insufficient funds.


668-668: Use of the mixedOnly parameter
Forwarding the mixedOnly flag ensures the correct coinControl logic in signAndPublishTransaction.


673-673: New signAndPublishTransaction signature
Accepting mixedOnly broadens flexible transaction publishing scenarios for CoinJoin.


680-681: MixedOnly parameter in insufficientFunds handling
Passing mixedOnly to handle specialized insufficient fund logic for mixing scenarios is an apt extension.

Also applies to: 689-689


839-839: Introducing mixedOnly parameter
The extended method signature clarifies usage in advanced mixing flows.


874-874: Propagating mixedOnly
Ensuring the newly introduced argument is applied consistently across calls avoids confusion.


1791-1794: Additional check for nil chain/block
Logging a warning if either is nil helps diagnose unexpected states with chain locks.

DashSync/shared/Models/CoinJoin/DSCoinJoinManager.h (5)

1-29: License header and imports look fine.
These lines form the MIT License header and bring in relevant headers. No further concerns.


30-39: Delegate protocol structure.
All methods are clearly named, referencing session IDs and statuses. No major issues at a glance. If needed, document threading assumptions for each callback.


40-53: Check property ownership semantics.
chain is declared as assign while other object properties use strong or weak. Typically, Objective-C objects use strong or weak. Consider verifying that no retain cycle issues occur or that chain won't be deallocated unexpectedly.


54-56: Singleton initialization.
sharedInstanceForChain: is introduced. Verify concurrency safety if it's truly a singleton or if multiple calls are expected. Consider a thread-safe approach (like dispatch_once).


103-106: File termination is standard.
NS_ASSUME_NONNULL_END is present, and the file ends cleanly. No issues.

DashSync/shared/Models/CoinJoin/DSCoinJoinManager.m (4)

50-51: Atomic properties for concurrency look good.

Using atomic for hasReportedSuccess and hasReportedFailure helps ensure they are thread-safe when mutated from different queues.


178-197: Event observer is properly balanced.

You add the transaction received observer here and then remove all observers in stopAsync. This balanced approach prevents potential memory leaks and stale observers.


304-323: Concurrency handling is sound.

Dispatching to self.processingQueue while tracking hasReportedSuccess and hasReportedFailure ensures consistent and thread-safe variable updates.


1008-1030: Graceful handling of multiple pool statuses.

Your logic correctly iterates through multiple statuses, detecting the first non-error one to finalize a successful outcome. This approach is clear, and fallback behavior for error statuses seems consistent.

@Syn-McJ Syn-McJ requested a review from pankcuf March 26, 2025 08:30
Copy link
Contributor

@pankcuf pankcuf left a comment

Choose a reason for hiding this comment

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

LGTM

@Syn-McJ Syn-McJ merged commit b6a82ef into master Mar 26, 2025
4 of 9 checks passed
@Syn-McJ Syn-McJ deleted the feat/coinjoin branch March 26, 2025 08:51
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.

6 participants