Skip to content

Faddat/broadcast via p2p#45

Open
faddat wants to merge 6 commits intomainfrom
faddat/broadcast-via-p2p
Open

Faddat/broadcast via p2p#45
faddat wants to merge 6 commits intomainfrom
faddat/broadcast-via-p2p

Conversation

@faddat
Copy link
Collaborator

@faddat faddat commented Mar 4, 2025

Summary by CodeRabbit

  • New Features

    • Launched a robust peer-to-peer broadcasting system for propagating transactions with built-in fallback support.
    • Added enhanced support for HTTP interactions, key management, and flexible configuration options, including hybrid transaction modes and custom gas settings.
    • Enabled parallel processing of transactions for improved throughput.
  • Enhancements

    • Improved validation and logging for sender address checks to ensure reliable transaction processing.
    • Optimized peer discovery with extended timeouts and refined retry mechanisms for more stable connections.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2025

Warning

Rate limit exceeded

@faddat has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 5922a63 and 4aecb37.

📒 Files selected for processing (1)
  • modes/registry/registry.go (16 hunks)

Walkthrough

This pull request introduces a comprehensive P2P broadcasting system and refines transaction and peer handling across multiple modules. New files and types establish P2P broadcasters and clients for handling transactions over a network. Enhancements include additional validation in transaction building, updated client context retrieval, and improved error handling. Utility functions for HTTP contexts, keyring management, and node connectivity are added. Peer discovery and registry modules now feature adjusted timeouts, retry logic, and expanded configuration options to support hybrid and multisend operations.

Changes

File(s) Change Summary
broadcast/p2p_broadcast.go, p2p/broadcaster.go Introduced a P2P broadcasting system with new types (P2PBroadcaster, Broadcaster, Peer, TxInfo, NetAddress, BroadcastResult) and functions/methods for initialization, transaction broadcasting, shutdown, and peer discovery.
broadcast/transaction.go Added validation for from_address in transaction operations, updated client context retrieval to P2PGetClientContext, and introduced logging for node usage.
broadcast/utils.go Added new utility functions: GetHTTPClientContext, GetKeyringFromBackend, IsNodeReachable, and GetNodeInfo along with necessary imports to support HTTP transactions and node status checking.
lib/chainregistry/cli.go, lib/peerdiscovery/discovery.go Increased peer discovery timeouts (from 45s to 2min in cli; from 5s to 10s in discovery) and introduced a retry mechanism (MaxRetries constant) with improved error handling in node connection checks.
modes/registry/registry.go Added several constants (e.g., MsgHybrid, MaximumTokenAmount, etc.) and new functions (createSkipBalanceCheckMarker, floodWithSends, floodWithIbcTransfers, getRandomInt, floodWithMultipleSends) to enhance multisend and IBC transfer logic, as well as improve logging and balance checks.
p2p/client.go Introduced a new P2P client with the Client and p2pPeer types, supporting peer management and transaction broadcasting through functions like NewClient, Start, Stop, BroadcastTx, and message processing methods.
types/types.go Updated configuration structs by adding new fields (Hybrid, NumOutReceivers, SkipBalanceCheck) to Config and modifying GasConfig fields (renaming Mid/Max to Medium/High, adding Max and alias Mid) for enhanced configuration options.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Broadcaster
    participant Client
    participant Peer

    User->>Broadcaster: Call BroadcastTx(txBytes)
    Broadcaster->>Broadcaster: Validate & generate tx hash
    Broadcaster->>Client: Delegate tx broadcast
    Client->>Client: Start peer connection if needed
    Client->>Peer: Send transaction message
    Peer-->>Client: Acknowledge receipt
    Client-->>Broadcaster: Return broadcast result
Loading

Possibly related PRs

  • faddat/seqnum price #44: Introduces similar enhancements to transaction processing and P2P broadcasting functionalities in BroadcastTxP2P and broadcast/transaction.go, aligning closely with the changes in this PR.

Poem

In a network forest, I hop with cheer,
Spreading transactions far and near.
🌐 P2P paths now brightly gleam,
Code hops smoothly, like a dream.
With retries and logs, our tale is told,
A rabbit's joy in code so bold!
(_/)<3 Happy coding!


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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 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: 6

🧹 Nitpick comments (20)
lib/chainregistry/cli.go (1)

105-105: Increased peer discovery timeout is a reasonable enhancement.

Extending the timeout from 45 seconds to 2 minutes gives the system more time to discover additional peers before timing out, which can be particularly helpful in networks with many nodes or slower connectivity.

Consider making this timeout configurable rather than hardcoded, allowing users to adjust it based on their network conditions. You could add a configuration option or environment variable.

lib/peerdiscovery/discovery.go (1)

179-209: Well-implemented retry logic for node connections.

The retry mechanism is properly implemented with exponential backoff (increasing delay between retries), clear logging, and proper connection cleanup.

Consider extracting the retry logic into a reusable utility function that could be used in other parts of the codebase that need similar retry functionality:

// retryWithBackoff attempts an operation with exponential backoff retries
func retryWithBackoff(operation func() error, maxRetries int, operationName string) error {
    var err error
    
    for retry := 0; retry < maxRetries; retry++ {
        // If this is a retry, wait with exponential backoff
        if retry > 0 {
            delay := time.Duration(retry) * time.Second
            fmt.Printf("Retry %d/%d for %s in %v\n", retry, maxRetries, operationName, delay)
            time.Sleep(delay)
        }
        
        // Attempt the operation
        if err = operation(); err == nil {
            return nil // Success
        }
        
        fmt.Printf("Attempt %d: %s failed: %v\n", retry+1, operationName, err)
    }
    
    // If we get here, all retries failed
    return fmt.Errorf("failed after %d attempts: %w", maxRetries, err)
}
broadcast/transaction.go (1)

1007-1014: Added logging for transaction node selection improves observability.

The new log statements make it clear which node is being used for a given transaction, which is helpful for debugging and monitoring.

Consider adding more detailed logging of parameters that affect node selection to make it easier to debug unexpected behavior:

-	fmt.Printf("📝 Transaction for account %s using node %s\n",
-		fromAddress, txParams.NodeURL)
+	fmt.Printf("📝 Transaction for account %s using node %s (selected from %d available nodes)\n",
+		fromAddress, txParams.NodeURL, len(txParams.Config.Nodes.RPC))
broadcast/utils.go (3)

148-168: Consider making broadcast mode configurable.
Currently, GetHTTPClientContext sets the broadcast mode to "sync", noting that it will be overridden. Make the broadcast mode an explicit method parameter or read it from config to avoid confusion.


170-200: Keyring creation logic looks sound.
Switching on different backends (test, file, os, memory) is straightforward. If you want multi-chain support, consider a chain-specific keyring name instead of the hard-coded "cosmos".


202-237: Robust node health checks.
IsNodeReachable cleverly checks /health, but no further validation is performed on the response body. Consider more in-depth checks or reusing the approach from GetNodeInfo if deeper details are needed.

p2p/client.go (5)

39-80: Initialization flow for NewClient is coherent.
Generating a unique node ID, logging setup, and channel creation is straightforward. You might consider injecting the logger and default P2P port to allow for different logging frameworks or addresses.


81-97: Graceful Start method.
The client sets isRunning and launches goroutines for both transaction processing and peer connections. Ensure you handle potential goroutine errors, e.g., goroutine panics, for production readiness.


118-145: BroadcastTx logic is currently minimal.
It sets up a response channel and enqueues the transaction to txChan. To avoid timeouts, consider increasing the queue buffer or ensuring the consumer drains quickly.


191-214: processMessages concurrency is handled with a select on context.
This is a good pattern to ensure you exit cleanly when the client is stopped. Just be mindful that larger transaction volumes may need more advanced queue management.


216-237: Helper functions for generating IDs.
Using crypto/rand is good for randomness. The fallback for peer ID generation on error is acceptable for a prototype, but logs or an error might be better in production code.

broadcast/p2p_broadcast.go (7)

42-67: Global concurrency pattern for broadcaster.
The p2pBroadcasterOnce usage with a global instance is convenient for a singleton. Just be aware that singletons can limit testability if multiple concurrent networks are needed.


121-185: BroadcastTxP2P fallback to RPC is a nice feature.
If no peers are connected, it gracefully calls BroadcastTxSync. This ensures reliability. Evaluate how you plan to handle partial peer connectivity in the future.


234-265: Local getSeedNodesForChain with hardcoded seeds.
This is fine for initial usage. As the comment states, a dynamic registry or external config might be more flexible.


267-285: NewP2PBroadcaster returns an initialized instance in the background.
It mirrors the global approach but is decoupled from the singleton logic. This is consistent, but you might unify them or clarify usage for consistency.


287-311: Initialize method sets up the broadcaster.
Lock usage is correct, but check if the background goroutine in the constructor or FindPeers might duplicate work.


360-389: FindPeers simulates discovery.
Logs the seed nodes you would connect to. The imitation is a good stepping stone, but be sure to unify it with your other peer management calls.


417-453: P2PGetClientContext tries to connect to a node, logging warnings on failure.
This is a sensible approach. If you want offline or partial connectivity logic, consider distinguishing fatal vs non-fatal connection errors more clearly.

p2p/broadcaster.go (1)

90-101: Consider waiting for in-flight operations during shutdown.

Currently, the Shutdown method stops the client immediately without waiting for any ongoing peer connections or broadcasts to complete. If a graceful shutdown is desired, consider joining or signaling any in-flight operations before clearing the client reference.

modes/registry/registry.go (1)

2011-2055: Check for timeouts in continuous transaction loops.

While flooding multiple sends, the loop processes up to numTransactions. If external factors cause slow broadcasts or unresponsive nodes, consider adding periodic context-cancellation checks or more robust retry logic to avoid unexpected long hangs.

🧰 Tools
🪛 GitHub Check: test (1.23.x, macos-latest)

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Check: test (1.23.x, ubuntu-latest)

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Actions: Test

[error] 2036-2036: fmt.Printf format %q reads arg #4, but call has 3 args

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 917e71f and 5922a63.

📒 Files selected for processing (9)
  • broadcast/p2p_broadcast.go (1 hunks)
  • broadcast/transaction.go (3 hunks)
  • broadcast/utils.go (3 hunks)
  • lib/chainregistry/cli.go (1 hunks)
  • lib/peerdiscovery/discovery.go (4 hunks)
  • modes/registry/registry.go (16 hunks)
  • p2p/broadcaster.go (1 hunks)
  • p2p/client.go (1 hunks)
  • types/types.go (2 hunks)
🧰 Additional context used
🪛 GitHub Check: test (1.23.x, macos-latest)
modes/registry/registry.go

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Check: test (1.23.x, ubuntu-latest)
modes/registry/registry.go

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Actions: Test
modes/registry/registry.go

[error] 2036-2036: fmt.Printf format %q reads arg #4, but call has 3 args

🔇 Additional comments (26)
types/types.go (1)

137-141: Support for hybrid mode and enhanced multisend controls are good additions.

The new configuration options for multisend functionality provide more flexibility in transaction handling. The Hybrid flag allows a mix of sends and multisends, while NumOutReceivers gives control over the number of recipients in multisend transactions.

lib/peerdiscovery/discovery.go (3)

17-21: Added retry mechanism improves peer discovery robustness.

Increasing the DefaultTimeout and adding the MaxRetries constant enhances the robustness of peer discovery by allowing for temporary connection issues.


63-70: Well-implemented tracking of initial registry endpoints.

The code now properly normalizes and tracks the initial registry endpoints, which will help with prioritizing endpoints in the results.


105-129: Improved endpoint prioritization logic.

The new code separates discovered endpoints into registry and non-registry sources, prioritizing non-registry endpoints in the results. This is beneficial as it gives preference to newly discovered peers while still maintaining the original registry endpoints as fallbacks.

broadcast/transaction.go (5)

176-186: Added input validation for from_address improves transaction safety.

The additional validation ensures that the sender address is both present and valid before attempting to build a transaction, preventing potential errors later in the transaction lifecycle.


194-197: Explicit setting of from address in client context is good practice.

This change ensures that the client context has the correct sender address, which is important for proper transaction building and signing.


646-646: Consistent use of P2PGetClientContext throughout the codebase.

The function has been changed to use P2PGetClientContext here as well, maintaining consistency with the earlier changes.


1023-1023: Consistent use of P2PGetClientContext ensures compatibility with P2P broadcasting.

Using the same context retrieval method here ensures that the transaction is broadcasted using the P2P system consistently.


189-189:

Details

❓ Verification inconclusive

Changed client context retrieval method may require broader changes.

The function has been changed from GetClientContext to P2PGetClientContext, which suggests a switch to P2P broadcasting functionality. Ensure that all callers are updated and that the new function properly handles all the same use cases.

Check for any occurrences of GetClientContext that might need to be updated:


🏁 Script executed:

#!/bin/bash
# Search for all instances of GetClientContext that might need to be updated
rg "GetClientContext" --type go

Length of output: 1148


Attention: P2P Client Context Update Verification

The search results confirm that the update to use P2PGetClientContext in broadcast/transaction.go is consistent with similar changes in broadcast/p2p_broadcast.go and modes/registry/registry.go. The remaining use of GetClientContext in broadcast/utils.go appears to be intentional for HTTP-specific cases. Please verify that this separation between P2P and HTTP client context retrieval is deliberate and that no functionality was inadvertently affected.

  • Confirm that HTTP-related callers still correctly use GetClientContext in broadcast/utils.go.
  • Ensure that the P2P-specific paths now using P2PGetClientContext fully cover the intended use cases.
broadcast/utils.go (3)

5-12: Imports for new HTTP-based features look appropriate.
They enable network requests (net/http), streaming I/O (io), OS interactions (os), string operations, and timeouts, which are needed for the newly introduced HTTP context and node reachability checks.


21-21: Keyring import is correctly added.
This import is used for managing keys and appears consistent with the new keyring-related functionality in this file.


239-306: Comprehensive node status retrieval.
GetNodeInfo thoroughly requests /status and parses JSON to extract node info. This is a helpful complement to IsNodeReachable. Just keep an eye on possible schema changes on the node side that might break the map-based parsing.

p2p/client.go (4)

14-37: Concurrency structures and fields in Client look well-defined.
The use of mutexes (peersMtx, txRespMtx) and channels for broadcasting indicates good concurrency safety. Beware of potential race conditions if external goroutines modify these fields without locks.


99-117: Stop ensures graceful shutdown.
Cancelling the context, closing channels, and resetting state is appropriate. This method is a good complement to Start. If more resources are open, ensure they’re also cleaned.


147-168: connectToPeers effectively simulates peer connections.
The current placeholder approach for TCP connections is understandable for a first version. Just ensure to expand it when real networking is implemented.


170-189: connectToPeer is aligned with connectToPeers approach.
Again, placeholders for real networking are fine to keep the logic straightforward.

broadcast/p2p_broadcast.go (8)

23-40: P2PBroadcaster, Peer, and TxInfo structures provide clear separation of concerns.
P2PBroadcaster tracks peers and transactions, while Peer focuses on connection state, and TxInfo handles transaction broadcast details. Good design.


69-91: GetP2PBroadcaster enforces a lazy initialization.
Kicking off initialize in a goroutine is an interesting approach. Mind that early calls to the broadcaster might expect an already connected state.


93-120: Broadcaster initialization.
The simulation of seed peer connections is a good starting point. Just ensure robust error handling or fallback logic once real P2P is implemented.


187-200: RunCommandWithOutput fosters external interactions.
Capturing CombinedOutput() is good for debugging. Keep an eye on security implications if passing untrusted args in production.


313-327: Shutdown logic is minimal but clean.
Unsets initialized after printing a shutdown message. For real networking, consider graceful peer disconnection.


328-358: BroadcastTx method rechecks initialization.
This is a good safeguard. Consider the effect of repeated calls under heavy load—some concurrency tests would be valuable.


455-473: Config struct and GetDefaultConfig are straightforward.
They provide typical fields for chain interactions, including gas settings. This approach is good for simple local usage.


475-509: MapAccountToNode fosters a sticky assignment.
The use of account address bytes to pick a node index is a creative approach. Watch for concurrency issues in accountToNodeMap if frequently updated from multiple goroutines.

p2p/broadcaster.go (1)

153-180: Revisit concurrency in peer discovery.

After spawning separate goroutines to connect to each seed address, the channel is closed immediately, which signals the original goroutine to return. If you want to wait until peer connections actually succeed or fail, consider synchronizing on the goroutines that attempt these connections (for instance, using a sync.WaitGroup) before closing the done channel.

modes/registry/registry.go (1)

657-660: Confirm skip-balance-check logic.

When config.SkipBalanceCheck is true, the code bypasses all balance verification and adjustment. This might lead to unbalanced accounts if prior attempts to fix balances failed. Verify that skipping is indeed desired under those conditions.

Comment on lines +196 to 200
Medium int64 `toml:"medium"` // Renamed from Mid -> Medium
High int64 `toml:"high"` // Renamed from Max -> High
Max int64 `toml:"max"` // New maximum gas setting
Mid int64 `toml:"mid"` // Alias for Medium
Precision int64 `toml:"precision"`
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Confusing gas configuration parameter naming.

The renaming from Mid to Medium and Max to High while also introducing a new Max field and keeping Mid as an alias could lead to confusion. It's unclear which field should be used in different situations.

Consider one of these approaches:

  1. Remove the Mid alias entirely and update all code to use Medium
  2. Mark Mid as deprecated with a comment indicating to use Medium instead
  3. Document the relationship between High and Max clearly
-	Medium      int64  `toml:"medium"` // Renamed from Mid -> Medium
-	High        int64  `toml:"high"`   // Renamed from Max -> High
-	Max         int64  `toml:"max"`    // New maximum gas setting
-	Mid         int64  `toml:"mid"`    // Alias for Medium
+	Medium      int64  `toml:"medium"` // Medium gas setting
+	High        int64  `toml:"high"`   // High gas setting
+	Max         int64  `toml:"max"`    // Maximum gas setting (higher than High)
+	Mid         int64  `toml:"mid"`    // Deprecated: Use Medium instead
📝 Committable suggestion

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

Suggested change
Medium int64 `toml:"medium"` // Renamed from Mid -> Medium
High int64 `toml:"high"` // Renamed from Max -> High
Max int64 `toml:"max"` // New maximum gas setting
Mid int64 `toml:"mid"` // Alias for Medium
Precision int64 `toml:"precision"`
Medium int64 `toml:"medium"` // Medium gas setting
High int64 `toml:"high"` // High gas setting
Max int64 `toml:"max"` // Maximum gas setting (higher than High)
Mid int64 `toml:"mid"` // Deprecated: Use Medium instead
Precision int64 `toml:"precision"`

NumMultisend int `toml:"num_multisend"` // Number of transactions to include in a multisend
NumOutReceivers int `toml:"num_out_receivers"` // Number of receivers for multisend transactions
SkipBalanceCheck bool `toml:"skip_balance_check"` // Whether to skip balance checking and adjustment
MsgParams MsgParams `toml:"msg_params"`
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Explicit balance check skipping may lead to transaction failures.

The SkipBalanceCheck option could result in transactions being built that will fail due to insufficient funds. Ensure there's clear documentation about when this flag should be used.

Before making a decision about whether to use this flag, consider running this script to see how balance checks are currently implemented:


🏁 Script executed:

#!/bin/bash
# Search for balance checking code to understand implementation
echo "Looking for balance check implementation..."
rg "balance" --type go -A 3 -B 3
echo "Looking for places where SkipBalanceCheck would be used..."
rg "SkipBalanceCheck" --type go -A 3 -B 3

Length of output: 54117


Action: Clarify and Document SkipBalanceCheck Usage

The SkipBalanceCheck flag disables balance verification and adjustment, which can allow transactions to be constructed even when accounts lack sufficient funds—potentially leading to failures at runtime. Our investigation confirms that the flag is used in both the configuration (in types/types.go) and during runtime in modes/registry/registry.go (triggered either by explicit config or via the .skip_balance_check marker file).

Suggestions:

  • Enhance Inline Comments: Update the in-code comment for the SkipBalanceCheck field (currently “Whether to skip balance checking and adjustment”) to explain the risks and specific conditions under which skipping balance checks is acceptable.
  • External Documentation: Add or expand documentation (e.g., in the README) detailing:
    • When and why to use this flag (for instance, as a fallback only when balance adjustments repeatedly fail).
    • The potential impact on transaction reliability if enabled inadvertently.
    • Recommended best practices for troubleshooting balance check issues.
  • Runtime Warnings (Optional): Consider implementing additional runtime logging or warnings when the flag is active to ensure users are aware of the disabled verification.

Please address these improvements to help users avoid inadvertently triggering transaction failures.

Comment on lines +202 to +232
// FindRandomRecipient finds a random recipient from a keyring
func FindRandomRecipient(keyringBackend, excludeAddress string) (string, error) {
// List accounts in keyring
output, err := RunCommandWithOutput("", "meteorite", "keys", "list", "--keyring-backend", keyringBackend)
if err != nil {
return "", err
}

// Parse output to find addresses
addresses := []string{}
lines := strings.Split(output, "\n")

for _, line := range lines {
if strings.Contains(line, "address:") {
parts := strings.Split(line, "address: ")
if len(parts) > 1 {
addr := strings.TrimSpace(parts[1])
if addr != excludeAddress {
addresses = append(addresses, addr)
}
}
}
}

if len(addresses) == 0 {
return "", errors.New("no other addresses found in keyring")
}

// Pick a random address
return addresses[rand.Intn(len(addresses))], nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

FindRandomRecipient is strictly reliant on CLI output.
Parsing key addresses from meteorite keys list works, but might be brittle if output formats change. Consider a stable library interface for the key store if available.

Comment on lines +390 to +415
// GetSeedNodesForChain returns seed nodes for a specific chain
func GetSeedNodesForChain(chainID string) []string {
switch chainID {
case "cosmoshub-4":
return []string{
"e1d7ff02b78044795371bff4c36b240262d8479c@65.108.2.41:26656",
"ade4d8bc8cbe014af6ebdf3cb7b1e9ad36f412c0@seeds.polkachu.com:14956",
"20e1000e88125698264454a884812746c2eb4807@seeds.lavenderfive.com:14956",
}
case "osmosis-1":
return []string{
"f94c92c75ec370b23d7408e32c28e6a3b138dd57@65.108.2.41:26656",
"5a37f1f701b3634add5a2034c4d0cc0c95f48a3f@seeds.polkachu.com:12556",
"3255e3620984c891204251d9eeb3e981745913b2@seeds.lavenderfive.com:12556",
}
case "stargaze-1":
return []string{
"d95a7770a5f43570303d3d538538ca03f2a3c2c7@65.108.2.41:26656",
"6c2377646af8c2d99a26ff2256bd1f93382b46ad@seeds.polkachu.com:13756",
"def2c8a5c85d2f528e4311dcadc8080b91bf5a69@seeds.lavenderfive.com:13756",
}
default:
// Default to returning empty list, the application should have a way to look up seed nodes
return []string{}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

GetSeedNodesForChain is largely duplicated from getSeedNodesForChain.
Having two similar functions suggests some refactoring is needed to avoid maintenance overhead. Possibly unify them in one function.

-// getSeedNodesForChain (private) and GetSeedNodesForChain (public) appear to duplicate logic
-// Consider removing one of them or internally reusing one from the other.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +103 to +139
// BroadcastTx broadcasts a transaction through the P2P network
func (b *Broadcaster) BroadcastTx(txBytes []byte) (*BroadcastResult, error) {
b.mtx.Lock()
initialized := b.isInitialized
b.mtx.Unlock()

if !initialized {
if err := b.Initialize(); err != nil {
return nil, fmt.Errorf("failed to initialize P2P broadcaster: %w", err)
}
}

if b.client == nil {
return nil, errors.New("P2P client is not initialized")
}

// Create a hash of the transaction for tracking
hash := sha256.Sum256(txBytes)
txHash := hex.EncodeToString(hash[:])

// Log the transaction broadcast
b.logger.Printf("Broadcasting transaction with hash %s", txHash)

// Broadcast the transaction
err := b.client.BroadcastTx(txBytes)
if err != nil {
return nil, fmt.Errorf("failed to broadcast transaction: %w", err)
}

// Return a synthetic success result
return &BroadcastResult{
Code: 0,
Log: "Transaction broadcast through P2P network",
TxHash: txHash,
Height: -1, // unknown height
}, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Return meaningful broadcasting feedback.

The BroadcastTx method always returns a synthetic success result (Code: 0, Height: -1). If you need to track or confirm success, consider fetching a real response from the network to differentiate between successful broadcasts and failures.

// Process the response
if broadcastErr != nil {
failedTxs++
fmt.Printf("[POS-%d] Transaction FAILED: seq=%d broadcast=%s error=%q\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the printf argument mismatch.

The format string uses four placeholders (%d, %d, %s, %q) but only provides three arguments, causing a runtime error. Include the missing argument (e.g., elapsed) or remove the extra placeholder. For example:

- fmt.Printf("[POS-%d] Transaction FAILED: seq=%d broadcast=%s error=%q\n", position, sequence, broadcastErr)
+ fmt.Printf("[POS-%d] Transaction FAILED: seq=%d broadcast=%s error=%q\n",
+     position, sequence, elapsed, broadcastErr)
📝 Committable suggestion

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

Suggested change
fmt.Printf("[POS-%d] Transaction FAILED: seq=%d broadcast=%s error=%q\n",
fmt.Printf("[POS-%d] Transaction FAILED: seq=%d broadcast=%s error=%q\n",
position, sequence, elapsed, broadcastErr)
🧰 Tools
🪛 GitHub Check: test (1.23.x, macos-latest)

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Check: test (1.23.x, ubuntu-latest)

[failure] 2036-2036:
fmt.Printf format %q reads arg #4, but call has 3 args

🪛 GitHub Actions: Test

[error] 2036-2036: fmt.Printf format %q reads arg #4, but call has 3 args

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.

1 participant