Skip to content

Tron: broadcast fails with NOT_ENOUGH_EFFECTIVE_CONNECTION; status lookup also logs noisy deserialization error (#4175)#4179

Merged
johnnyluo merged 2 commits into
mainfrom
agent/4175-tron--broadcast-fails-with-not-enough-ef
Apr 24, 2026
Merged

Tron: broadcast fails with NOT_ENOUGH_EFFECTIVE_CONNECTION; status lookup also logs noisy deserialization error (#4175)#4179
johnnyluo merged 2 commits into
mainfrom
agent/4175-tron--broadcast-fails-with-not-enough-ef

Conversation

@Vaulty-bot
Copy link
Copy Markdown
Collaborator

@Vaulty-bot Vaulty-bot commented Apr 23, 2026

Fixes #4175

Changes

  • TronApiImpl.broadcastTransaction now retries up to 3 times (MAX_BROADCAST_RETRIES) with exponential backoff (delay(1000L shl attempt)) when the Tron network returns NOT_ENOUGH_EFFECTIVE_CONNECTION; previously it was a single attempt with no retry logic.
  • TronApiImpl.getTransactionStatus adds .takeIf { it.txId != null } to filter out malformed/incomplete responses, returning null instead of a partially-deserialized object.
  • TronTransactionStatusResponse.txId in TronResponseJson.kt changed from non-nullable String to String? = null, preventing deserialization crashes when the field is absent in the API response.

Checklist

  • Lint clean
  • Build verified (S1)
  • Self-reviewed against requirements (S3)
  • No secrets committed
  • Conventional commit messages

Summary by CodeRabbit

  • Bug Fixes
    • Improved Tron transaction broadcasting reliability with automatic retry logic on network instability, including exponential backoff delays before attempting again.
    • Enhanced handling of incomplete transaction status responses to prevent errors when transaction data is partially unavailable.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

The TronApi module adds automatic retry logic with exponential backoff when NOT_ENOUGH_EFFECTIVE_CONNECTION is encountered during transaction broadcast, throwing a network-stability exception after retries exhaust. Additionally, TronTransactionStatusResponse.txId is now nullable to allow clean deserialization of empty JSON responses during status polling.

Changes

Cohort / File(s) Summary
Broadcast retry mechanism
data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt
Added retry loop in broadcastTransaction (up to MAX_BROADCAST_RETRIES) with exponential-ish backoff when NOT_ENOUGH_EFFECTIVE_CONNECTION is detected; throws network-stability exception if all retries fail. Modified getTsStatus to return null when deserialized response lacks a non-null txId.
Transaction status model
data/src/main/kotlin/com/vultisig/wallet/data/api/models/TronResponseJson.kt
Changed TronTransactionStatusResponse.txId type from String to String? = null, enabling successful deserialization of empty JSON bodies {} without triggering exceptions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A flutter of retries, hops through the night,
When nodes say "not ready," we're handling it right,
Exponential backoff, a patient refrain,
Empty responses? No longer a pain,
The Tron network stumbles—we bounce back with might! 🌙

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the two main changes: TRON broadcast retry logic for NOT_ENOUGH_EFFECTIVE_CONNECTION and status lookup deserialization error fixes.
Linked Issues check ✅ Passed The PR implements all must-do requirements: retry logic with exponential backoff for NOT_ENOUGH_EFFECTIVE_CONNECTION [#4175], nullable txId field to prevent deserialization failures [#4175], and null-check in getTransactionStatus [#4175].
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #4175: retry mechanism, nullable field, and status filtering. No unrelated broadcast/signing logic or other error codes were modified.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/4175-tron--broadcast-fails-with-not-enough-ef

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt (1)

67-87: Retry logic — a few smaller points worth considering.

  1. Interface/impl return type drift. The interface declares broadcastTransaction(tx: String): String? (line 39) but the implementation declares String (line 66). Kotlin accepts this covariant override, but now no caller can observe a null result, and the nullability on the interface is misleading. Consider tightening the interface to String as well.

  2. Raw Exception. Per coding guidelines, prefer a typed exception over throw Exception(...). A sealed class or dedicated IOException/domain exception also lets callers distinguish "retries exhausted" from "hard failure" (useful since getTransactionStatus / retry-pending flows may want different UX).

  3. Backoff cap. 1000L shl attempt is fine for MAX_BROADCAST_RETRIES = 3 (waits 1s, then 2s), but if anyone later bumps the constant, shl on a Long will overflow around attempt 63 and the delays will grow unexpectedly. A coerceAtMost(MAX_BACKOFF_MS) guard is cheap insurance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt` around lines 67
- 87, The implementation of broadcastTransaction contains three issues: the
interface declares broadcastTransaction(tx: String): String? while the
implementation returns non-null String (tighten the interface to String to match
the impl), it throws raw Exception(...) (replace with a typed exception or
sealed domain error, e.g., BroadcastFailure or IOException so callers can
distinguish retry-exhausted vs hard failure), and the exponential backoff uses
1000L shl attempt which can overflow (wrap the delay calculation with a cap like
delayMs = (1000L shl attempt).coerceAtMost(MAX_BACKOFF_MS) and then
delay(delayMs)); update references in the same function and constants
MAX_BROADCAST_RETRIES, NOT_ENOUGH_EFFECTIVE_CONNECTION_ERROR_CODE,
DUP_TRANSACTION_ERROR_CODE, and any callers such as getTransactionStatus to
handle the new exception type and tightened return nullability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt`:
- Around line 84-86: The two hardcoded throw strings in TronApi.kt must be
replaced with typed exceptions so localization happens at the UI layer: create a
sealed exception (e.g. sealed class TronBroadcastException : Exception()) with
variants like BroadcastFailed(val code: Int) and NetworkUnstable, then change
the throws inside the broadcast method (the places currently throwing "Error
broadcasting transaction: ${response.code}" and "Tron network is unstable.
Please try again shortly.") to throw BroadcastFailed(response.code) and
NetworkUnstable respectively; finally ensure callers (ViewModel/UseCase) catch
TronBroadcastException and map each variant to the appropriate string resource
(e.g. R.string.tron_broadcast_failed, R.string.tron_broadcast_network_unstable)
before presenting to the user.

---

Nitpick comments:
In `@data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt`:
- Around line 67-87: The implementation of broadcastTransaction contains three
issues: the interface declares broadcastTransaction(tx: String): String? while
the implementation returns non-null String (tighten the interface to String to
match the impl), it throws raw Exception(...) (replace with a typed exception or
sealed domain error, e.g., BroadcastFailure or IOException so callers can
distinguish retry-exhausted vs hard failure), and the exponential backoff uses
1000L shl attempt which can overflow (wrap the delay calculation with a cap like
delayMs = (1000L shl attempt).coerceAtMost(MAX_BACKOFF_MS) and then
delay(delayMs)); update references in the same function and constants
MAX_BROADCAST_RETRIES, NOT_ENOUGH_EFFECTIVE_CONNECTION_ERROR_CODE,
DUP_TRANSACTION_ERROR_CODE, and any callers such as getTransactionStatus to
handle the new exception type and tightened return nullability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e8dc6e2-63c5-4976-812b-312c8e1f1319

📥 Commits

Reviewing files that changed from the base of the PR and between 29961b0 and b4fdb24.

📒 Files selected for processing (2)
  • data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt
  • data/src/main/kotlin/com/vultisig/wallet/data/api/models/TronResponseJson.kt

Comment thread data/src/main/kotlin/com/vultisig/wallet/data/api/TronApi.kt
Copy link
Copy Markdown
Contributor

@johnnyluo johnnyluo left a comment

Choose a reason for hiding this comment

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

LGTM

@johnnyluo johnnyluo added this pull request to the merge queue Apr 23, 2026
Merged via the queue into main with commit 4988707 Apr 24, 2026
2 checks passed
@johnnyluo johnnyluo deleted the agent/4175-tron--broadcast-fails-with-not-enough-ef branch April 24, 2026 00:05
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.

Tron: broadcast fails with NOT_ENOUGH_EFFECTIVE_CONNECTION; status lookup also logs noisy deserialization error

2 participants