Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: support for Bitcoin RBF (Replace-By-Fee) and CPFP (Child-Pays-for-Parent) #3306

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from

Conversation

ws4charlie
Copy link
Contributor

@ws4charlie ws4charlie commented Dec 16, 2024

Description

The goals:

  1. Implement BIP-125, Replace-By-Fee so that every outbound is replaceable when stuck in mempool.
  2. Use the Child-Pays-for-Parent (CPFP) to bump tx fees and unblock stuck outbounds.

The general idea:

  1. Enable RBF flag in every Bitcoin outbound.
  2. Have zetacore feed latest fee rate (every 10 mins) to pending CCTXs in the newly created method
    CheckAndUpdateCctxGasRateBTC.
  3. Spwan a new go routine WatchMempoolTxs in zetaclient to monitor pending outbound txs, so we know how long the txs have been sitting in the Bitcoin mempool.
  4. If the pending period of the outbounds exceeds a pre-defined threshold (30 mins and 3 blocks), zetaclient will mark the outbound status as stuck and trigger tx replacement using RBF and CPFP.
  5. After tx replacement, the outbound status will be set back to normal.
  6. After tx replacement, if the outbound still doesn't move forward for another threshold period of time, RBF will triggered again with even higher fee rate until reaching a gasRateCap = 100
  7. zetaclient will always use most recent fee rate (feed by zetacore) to initiate new outbound transactions. The reason is that using an outdated GasPrice in CCTX struct is usually the root cause (not the Bitcoin network traffic) of stuck transactions, the low-fee problem needs to be solved at the first place to reduce the possibility of stuck txs.

Some concepts and parameters:

  1. LastPendingOutbound:
    Bitcoin outbounds are sequentially chained transactions by nonce. Given N pending txs [TX1, TX2, TX3, TX4] in the mempool, zetaclient only need to watch and bump the fee of TX4 to unblock all of them. According to Bitcoin CPFP strategy, the chained pending txs are treated as a package by miners. Bumping TX4 will increase the average fee rate of the whole txs package and make it more attractive to miners.
  2. minCPFPFeeBumpPercent:
    It is set to 20% as an exercise parameter designed to balance effectiveness in replacing stuck tx while avoiding excessive sensitivity to fee market fluctuations. For example, given a paidRate == 10, RBF will not happen until the market rate goes up to liveRate==12.
  3. gasRateCap:
    It is the maximum average fee rate for fee bumping. 100 sat/vB is a chosen heuristic based on Bitcoin mempool statistics to avoid excessive (or accidental) fees.
  4. reservedRBFFees:
    It is the amount of BTC reserved in the outbound transaction for fee bumping. It is set to 0.01 BTC by default, which can bmp 10 transactions (1KB each) by 100 sat/vB. Most of the time, we have just 1 or 2 stuck transactions in the mempool and the signers will automatically stop signing new transactions by design, so the number 0.01 BTC is good enough.

How Has This Been Tested?

  • Tested CCTX in localnet
  • Tested in development environment
  • Go unit tests
  • Go integration tests
  • Tested via GitHub Actions

Summary by CodeRabbit

Based on the comprehensive summary, here are the release notes:

Release Notes

  • New Features

    • Added support for Bitcoin Replace-By-Fee (RBF) functionality
    • Enhanced Bitcoin transaction handling with improved fee bumping and mempool management
    • Introduced new methods for monitoring and processing Bitcoin outbound transactions
  • Improvements

    • Refactored Bitcoin signer and observer components for better modularity
    • Added more robust error handling in Bitcoin transaction processing
    • Improved logging and tracking of cross-chain transactions
  • Testing

    • Expanded test coverage for Bitcoin transaction signing and RBF scenarios
    • Added comprehensive unit tests for Bitcoin RPC and signer functionality
  • Bug Fixes

    • Resolved issues with transaction fee estimation
    • Improved handling of stuck transactions in the Bitcoin mempool
  • Chores

    • Updated naming conventions for cross-chain transaction scheduling methods
    • Refactored code to improve readability and maintainability

@ws4charlie ws4charlie added zetaclient Issues related to ZetaClient zetacore Issues related to ZetaCore chain:bitcoin Bitcoin chain related labels Dec 16, 2024
Copy link
Contributor

coderabbitai bot commented Dec 16, 2024

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request introduces comprehensive support for Bitcoin Replace-By-Fee (RBF) functionality across the ZetaChain node implementation. The changes span multiple packages and modules, focusing on enhancing Bitcoin transaction handling, fee management, and end-to-end testing capabilities. The implementation includes new methods for fee bumping, transaction signing, mempool monitoring, and robust error handling for RBF scenarios.

Changes

File Change Summary
changelog.md Added "Unreleased" section documenting Bitcoin RBF support
cmd/zetae2e/local/local.go Commented out Bitcoin RBF withdrawal test
contrib/localnet/docker-compose.yml Updated Bitcoin Core Docker image version
e2e/ files Added new E2E tests and helper functions for Bitcoin RBF
zetaclient/chains/bitcoin/ Extensive additions for RBF implementation, including observer, signer, and RPC modules
go.mod Updated dependency visibility

Sequence Diagram

sequenceDiagram
    participant Observer
    participant Signer
    participant RPCClient
    participant Mempool
    participant ZetaCore

    Observer->>Mempool: Monitor Stuck Transaction
    Mempool-->>Observer: Identify Stuck Transaction
    Observer->>Signer: Request Fee Bump
    Signer->>RPCClient: Fetch Current Fee Rates
    RPCClient-->>Signer: Return Fee Rates
    Signer->>Mempool: Broadcast Replacement Transaction
    Mempool-->>ZetaCore: Update Transaction Status
Loading

Possibly Related PRs

Suggested Labels

bitcoin, replace-by-fee, transaction-management, e2e-tests

Suggested Reviewers

  • kingpinXD
  • fbac
  • skosito
  • brewmaster012
  • lumtis
  • swift1337

The implementation demonstrates a robust approach to implementing Replace-By-Fee functionality, with comprehensive test coverage and careful consideration of various edge cases in Bitcoin transaction management.


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. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

Documentation and Community

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

@ws4charlie ws4charlie changed the title WIP: (DON'T review, code will change a lot) bitcoin transaction replace by fee feat: WIP (DON'T review, code will change a lot) bitcoin transaction replace by fee Dec 16, 2024
Copy link

gitguardian bot commented Dec 31, 2024

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
14567965 Triggered Generic Password 7cd37e9 cmd/zetaclientd/start.go View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link

github-actions bot commented Dec 31, 2024

!!!WARNING!!!
nosec detected in the following files: zetaclient/chains/bitcoin/observer/db.go, zetaclient/chains/bitcoin/observer/gas_price.go, zetaclient/chains/bitcoin/observer/mempool.go, zetaclient/chains/bitcoin/signer/outbound_data.go, zetaclient/chains/bitcoin/signer/sign.go, zetaclient/chains/bitcoin/fee.go, zetaclient/chains/bitcoin/rpc/rpc.go

Be very careful about using #nosec in code. It can be a quick way to suppress security warnings and move forward with development, it should be employed with caution. Suppressing warnings with #nosec can hide potentially serious vulnerabilities. Only use #nosec when you're absolutely certain that the security issue is either a false positive or has been mitigated in another way.

Only suppress a single rule (or a specific set of rules) within a section of code, while continuing to scan for other problems. To do this, you can list the rule(s) to be suppressed within the #nosec annotation, e.g: /* #nosec G401 */ or //#nosec G201 G202 G203
Broad #nosec annotations should be avoided, as they can hide other vulnerabilities. The CI will block you from merging this PR until you remove #nosec annotations that do not target specific rules.

Pay extra attention to the way #nosec is being used in the files listed above.

@github-actions github-actions bot added the nosec label Dec 31, 2024
@lumtis
Copy link
Member

lumtis commented Jan 6, 2025

Context #3279 (comment)

Copy link

codecov bot commented Jan 10, 2025

Codecov Report

Attention: Patch coverage is 59.25926% with 473 lines in your changes missing coverage. Please review.

Project coverage is 62.70%. Comparing base (47c9444) to head (e03ba4b).

Files with missing lines Patch % Lines
zetaclient/chains/bitcoin/observer/outbound.go 18.91% 88 Missing and 2 partials ⚠️
zetaclient/chains/bitcoin/signer/sign.go 48.14% 78 Missing and 6 partials ⚠️
zetaclient/chains/bitcoin/rpc/rpc.go 20.83% 75 Missing and 1 partial ⚠️
zetaclient/chains/bitcoin/observer/gas_price.go 0.00% 72 Missing ⚠️
zetaclient/chains/bitcoin/observer/utxos.go 64.28% 43 Missing and 7 partials ⚠️
zetaclient/chains/bitcoin/signer/signer.go 48.14% 41 Missing and 1 partial ⚠️
zetaclient/orchestrator/orchestrator.go 0.00% 21 Missing ⚠️
zetaclient/chains/bitcoin/observer/mempool.go 86.40% 14 Missing ⚠️
zetaclient/chains/bitcoin/observer/db.go 78.57% 7 Missing and 2 partials ⚠️
zetaclient/chains/bitcoin/signer/sign_rbf.go 89.28% 5 Missing and 1 partial ⚠️
... and 4 more
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #3306      +/-   ##
===========================================
+ Coverage    61.88%   62.70%   +0.81%     
===========================================
  Files          444      453       +9     
  Lines        31492    31968     +476     
===========================================
+ Hits         19490    20045     +555     
+ Misses       11129    11033      -96     
- Partials       873      890      +17     
Files with missing lines Coverage Δ
pkg/math/integer.go 100.00% <100.00%> (ø)
x/observer/types/crosschain_flags.go 100.00% <ø> (ø)
zetaclient/chains/bitcoin/signer/fee_bumper.go 100.00% <100.00%> (ø)
zetaclient/chains/bitcoin/signer/outbound_data.go 100.00% <100.00%> (ø)
zetaclient/common/env.go 88.88% <ø> (ø)
zetaclient/testutils/testdata.go 87.02% <100.00%> (+0.36%) ⬆️
zetaclient/testutils/testdata_naming.go 80.85% <100.00%> (+0.85%) ⬆️
zetaclient/orchestrator/bootstrap.go 58.55% <75.00%> (+0.25%) ⬆️
zetaclient/chains/bitcoin/fee.go 42.23% <87.50%> (+3.21%) ⬆️
x/crosschain/keeper/abci.go 80.95% <92.30%> (+3.67%) ⬆️
... and 11 more

@ws4charlie ws4charlie changed the title feat: WIP (DON'T review, code will change a lot) bitcoin transaction replace by fee feat: support for Bitcoin RBF (Replace-By-Fee) and CPFP (Child-Pays-for-Parent) Jan 10, 2025
@ws4charlie ws4charlie marked this pull request as ready for review January 10, 2025 06:06
@ws4charlie ws4charlie requested a review from a team as a code owner January 10, 2025 06:06
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: 29

🧹 Nitpick comments (56)
zetaclient/chains/bitcoin/signer/sign_test.go (3)

24-46: Consider extracting setup into helper functions.

The test setup could be more maintainable by extracting the TSS and receiver address setup into helper functions.

+func setupTestSigner(t *testing.T) *signer.Signer {
+    return signer.NewSigner(
+        chains.BitcoinMainnet,
+        mocks.NewBTCRPCClient(t),
+        mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet),
+        base.DefaultLogger(),
+    )
+}
+
+func setupTestAddresses(t *testing.T, s *signer.Signer) (btcutil.Address, []byte, btcutil.Address, []byte) {
+    tssAddr, err := s.TSS().PubKey().AddressBTC(chains.BitcoinMainnet.ChainId)
+    require.NoError(t, err)
+    tssScript, err := txscript.PayToAddrScript(tssAddr)
+    require.NoError(t, err)
+
+    receiver := "bc1qaxf82vyzy8y80v000e7t64gpten7gawewzu42y"
+    to, err := chains.DecodeBtcAddress(receiver, chains.BitcoinMainnet.ChainId)
+    require.NoError(t, err)
+    toScript, err := txscript.PayToAddrScript(to)
+    require.NoError(t, err)
+
+    return tssAddr, tssScript, to, toScript
+}

47-171: Enhance test table structure for better maintainability.

Consider these improvements to the test table:

  1. Use constants for repeated values.
  2. Group related test cases using subtests.
  3. Add test case documentation.
+const (
+    defaultAmount    = 0.2
+    defaultNonceMark = 10000
+    defaultFees     = 2000
+)
+
+// testCase represents a test case for AddWithdrawTxOutputs
+type testCase struct {
+    name      string
+    tx        *wire.MsgTx
+    to        btcutil.Address
+    total     float64
+    amount    float64
+    nonceMark int64
+    fees      int64
+    cancelTx  bool
+    fail      bool
+    message   string
+    txout     []*wire.TxOut
+}
+
+// successCases returns test cases for successful scenarios
+func successCases(to btcutil.Address, tssScript, toScript []byte) []testCase {
+    return []testCase{
+        {
+            name: "should add outputs successfully",
+            // ... existing test case
+        },
+        // ... other success cases
+    }
+}

173-188: Enable parallel test execution for better performance.

Consider running the test cases in parallel since they are independent.

 for _, tt := range tests {
     t.Run(tt.name, func(t *testing.T) {
+        t.Parallel()
         err := signer.AddWithdrawTxOutputs(tt.tx, tt.to, tt.total, tt.amount, tt.nonceMark, tt.fees, tt.cancelTx)
pkg/math/integer.go (2)

5-7: Enhance function documentation for better clarity.

While the examples are helpful, the documentation could be more comprehensive. Consider adding:

  • Parameter descriptions including valid ranges
  • Return value description
  • Edge case behavior documentation
  • Named variables in examples for better readability
-// IncreaseIntByPercent is a function that increases integer by a percentage.
-// Example1: IncreaseIntByPercent(10, 15, true) = 10 * 1.15 = 12
-// Example2: IncreaseIntByPercent(10, 15, false) = 10 + 10 * 0.15 = 11
+// IncreaseIntByPercent increases an integer value by a specified percentage.
+// Parameters:
+//   - value: The base integer value to increase
+//   - percent: The percentage to increase by (0-MaxUint32)
+//   - round: If true, rounds the increase to nearest integer; if false, truncates
+// Returns:
+//   The increased value after applying the percentage
+// Examples:
+//   baseValue := int64(10)
+//   withRounding := IncreaseIntByPercent(baseValue, 15, true)    // Returns 12 (10 * 1.15 rounded)
+//   withoutRounding := IncreaseIntByPercent(baseValue, 15, false) // Returns 11 (10 + 10 * 0.15 truncated)

12-15: Well-implemented optimization for multiples of 100.

Good use of integer arithmetic for better performance when handling multiples of 100. Consider enhancing the comment to explain the performance benefit.

-		// optimization: a simple multiplication
+		// Optimization: Using integer multiplication for multiples of 100
+		// avoids floating-point operations for better performance
zetaclient/chains/bitcoin/signer/signer.go (8)

158-158: Correct the error message for clarity

The error message lacks the word "to," making it grammatically incorrect. Updating it enhances readability and professionalism.

Apply this diff to correct the error message:

-logger.Error().Err(err).Msgf("failed get bitcoin network info")
+logger.Error().Err(err).Msgf("failed to get bitcoin network info")

181-181: Use past tense in success log messages

The log message should use "succeeded" instead of "succeed" to accurately reflect the completion of the action.

Apply this diff to correct the log message:

-logger.Info().Str(logs.FieldTx, signedTx.TxID()).Msg("SignRBFTx succeed")
+logger.Info().Str(logs.FieldTx, signedTx.TxID()).Msg("SignRBFTx succeeded")

196-196: Use past tense in success log messages

Similarly, update the log message to use "succeeded" for grammatical correctness.

Apply this diff to correct the log message:

-logger.Info().Str(logs.FieldTx, signedTx.TxID()).Msg("SignWithdrawTx succeed")
+logger.Info().Str(logs.FieldTx, signedTx.TxID()).Msg("SignWithdrawTx succeeded")

223-223: Fix typo in documentation comment

There is a typo in the comment. Correcting it improves code documentation quality.

Apply this diff to fix the typo:

-// try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error
+// try broadcasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error

143-146: Handle potential errors when retrieving the signer address

Currently, if an error occurs while getting the signer address, it's silently ignored. To prevent unforeseen issues, handle the error explicitly.

Apply this diff to handle the error:

 signerAddress, err := zetacoreClient.GetKeys().GetAddress()
-if err == nil {
+if err != nil {
+    logger.Error().Err(err).Msg("Failed to get signer address")
+} else {
     lf["signer"] = signerAddress.String()
 }

225-235: Attempt initial broadcast without delay

To reduce latency, consider attempting to broadcast the transaction immediately before entering the retry loop with backoff.

Apply this diff to modify the broadcasting logic:

 backOff := broadcastBackoff
+// Attempt initial broadcast without delay
+err := signer.Broadcast(tx)
+if err == nil {
+    logger.Info().Fields(lf).Msgf("broadcasted Bitcoin outbound successfully")
+    // Proceed with successful flow
+    // Save transaction, add tracker, etc.
+    // ...
+    return
+}
+logger.Warn().Err(err).Fields(lf).Msg("broadcasting Bitcoin outbound, retrying with backoff")
 // Retry broadcasting with backoff
 for i := 0; i < broadcastRetries; i++ {
     time.Sleep(backOff)

225-235: Adjust retry counter for accurate logging

The retry counter i starts at zero, which may be misleading in logs. Start counting retries from one for better clarity.

Apply this diff to adjust the retry counter:

 for i := 0; i < broadcastRetries; i++ {
     time.Sleep(backOff)

     // broadcast tx
     err := signer.Broadcast(tx)
     if err != nil {
-        logger.Warn().Err(err).Fields(lf).Msgf("broadcasting Bitcoin outbound, retry %d", i)
+        logger.Warn().Err(err).Fields(lf).Msgf("broadcasting Bitcoin outbound, retry %d", i+1)
         backOff *= 2
         continue
     }

250-253: Log when outbound inclusion fails

Currently, if the outbound transaction isn't included, there's no log indicating the failure. Adding a log enhances observability.

Apply this diff to log the failure:

 _, included := ob.TryIncludeOutbound(ctx, cctx, txHash)
 if included {
     logger.Info().Fields(lf).Msgf("included newly broadcasted Bitcoin outbound")
+} else {
+    logger.Warn().Fields(lf).Msgf("failed to include newly broadcasted Bitcoin outbound")
 }
e2e/e2etests/test_bitcoin_withdraw_rbf.go (1)

20-21: Correct the typo and clarify the comment for better understanding.

The comment contains a typo and is unclear. "Chainging" should be "Changing", and the sentence structure needs adjustment for clarity.

Please apply the following change to improve the comment:

-// Chainging the 'minTxConfirmations' to 1 to not include Bitcoin a pending tx.
+// Changing the 'minTxConfirmations' to 1 to include pending Bitcoin transactions.
zetaclient/chains/bitcoin/signer/sign_rbf.go (1)

58-58: Ensure consistent error handling by using errors.Wrapf.

For consistency and better error stack traces, consider using errors.Wrapf instead of fmt.Errorf, as other parts of the code utilize the errors package for wrapping errors.

Update the error handling as follows:

-return nil, fmt.Errorf("invalid fee rate %s", params.GasPriorityFee)
+return nil, errors.Wrapf(err, "invalid fee rate %s", params.GasPriorityFee)
zetaclient/chains/bitcoin/observer/gas_price.go (3)

16-47: Add unit tests for the WatchGasPrice function to improve reliability.

The WatchGasPrice function introduces critical functionality that is currently not covered by tests. Adding unit tests will ensure its correctness and prevent future regressions.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 16-21: zetaclient/chains/bitcoin/observer/gas_price.go#L16-L21
Added lines #L16 - L21 were not covered by tests


[warning] 24-36: zetaclient/chains/bitcoin/observer/gas_price.go#L24-L36
Added lines #L24 - L36 were not covered by tests


[warning] 38-45: zetaclient/chains/bitcoin/observer/gas_price.go#L38-L45
Added lines #L38 - L45 were not covered by tests


51-89: Increase test coverage for the PostGasPrice function.

The PostGasPrice function is essential for accurate gas price reporting but lacks test coverage. Implementing tests will enhance confidence in its operation and handle edge cases effectively.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 51-70: zetaclient/chains/bitcoin/observer/gas_price.go#L51-L70
Added lines #L51 - L70 were not covered by tests


[warning] 74-77: zetaclient/chains/bitcoin/observer/gas_price.go#L74-L77
Added lines #L74 - L77 were not covered by tests


[warning] 80-87: zetaclient/chains/bitcoin/observer/gas_price.go#L80-L87
Added lines #L80 - L87 were not covered by tests


[warning] 89-89: zetaclient/chains/bitcoin/observer/gas_price.go#L89
Added line #L89 was not covered by tests


93-106: Handle unsupported network types more gracefully.

In the specialHandleFeeRate function, consider handling additional network types or providing a clearer error message without the leading space. This will improve the function's robustness and clarity.

Apply this diff to adjust the error message:

 return 0, fmt.Errorf(" unsupported bitcoin network type %d", ob.Chain().NetworkType)
+return 0, fmt.Errorf("unsupported bitcoin network type %d", ob.Chain().NetworkType)
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 93-104: zetaclient/chains/bitcoin/observer/gas_price.go#L93-L104
Added lines #L93 - L104 were not covered by tests

x/crosschain/keeper/abci.go (1)

63-64: Improve test coverage for new code paths

The newly added lines at 63-64, where updateFunc is assigned when found, are not covered by unit tests. Enhancing test coverage for this conditional logic is important to ensure that the correct gas price updater functions are selected and executed for different chain types. This will increase code reliability and help prevent future regressions.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 63-64: x/crosschain/keeper/abci.go#L63-L64
Added lines #L63 - L64 were not covered by tests

zetaclient/chains/bitcoin/observer/mempool.go (2)

55-70: Add unit tests for WatchMempoolTxs functionality

The WatchMempoolTxs method introduces critical functionality for monitoring pending outbound transactions in the Bitcoin mempool. It is essential to have unit tests covering this method to ensure its reliability and correctness.

Consider adding unit tests that simulate various scenarios, such as transactions becoming stuck, to verify that the method behaves as expected.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 55-61: zetaclient/chains/bitcoin/observer/mempool.go#L55-L61
Added lines #L55 - L61 were not covered by tests


[warning] 64-70: zetaclient/chains/bitcoin/observer/mempool.go#L64-L70
Added lines #L64 - L70 were not covered by tests


207-221: Consolidate configuration for PendingTxFeeBumpWaitBlocks

The functions GetStuckTxChecker and GetFeeBumpWaitBlocks handle chain-specific logic based on the chainID. Consider refactoring these configurations into a centralized location or configuration file for easier maintenance and scalability.

zetaclient/chains/bitcoin/observer/observer.go (2)

172-174: Add tests for the WatchMempoolTxs background worker

The addition of the WatchMempoolTxs background worker is crucial for monitoring mempool transactions. It is important to include tests that validate its integration and interaction with other components.

Implement unit tests or integration tests to ensure the new worker operates correctly under various conditions.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 172-174: zetaclient/chains/bitcoin/observer/observer.go#L172-L174
Added lines #L172 - L174 were not covered by tests


254-273: Ensure thread-safe updates in SetLastStuckOutbound

In SetLastStuckOutbound, the method updates lastStuckTx while holding a lock. However, the logging statements inside the lock could potentially introduce latency.

Minimize the locked section to only the assignment, and perform logging outside the lock to improve concurrency.

-	ob.Mu().Lock()
-	defer ob.Mu().Unlock()
-	// logging inside lock
-	ob.lastStuckTx = stuckTx
+	ob.Mu().Lock()
+	ob.lastStuckTx = stuckTx
+	ob.Mu().Unlock()
+	// logging outside lock
zetaclient/chains/bitcoin/rpc/rpc.go (1)

175-177: Refine the upper bound check for fee rate validation

The current check compares *feeResult.FeeRate to maxBTCSupply, which represents the total supply of Bitcoin (21000000.0). Fee rates are typically much smaller values and unlikely to approach this limit. Using maxBTCSupply as an upper bound may not be appropriate and could mask unrealistic high fee rates. Consider defining a more realistic upper limit based on expected maximum fee rates to ensure accurate validation without false negatives.

zetaclient/chains/bitcoin/rpc/rpc_rbf_live_test.go (1)

99-102: Remove commented-out code to improve code clarity

The code between lines 99 and 102 is commented out, which may lead to confusion and reduce code readability. Remove the unused code to maintain a clean codebase.

Apply this diff to remove the commented code:

  // STEP 2
- // build and send tx2 (child of tx1)
- // nonceMark += 1
- // txHash2 := buildAndSendRBFTx(t, client, privKey, txHash1, sender, to, amount, nonceMark, feeRate, bumpFeeReserved)
- // fmt.Printf("sent tx2: %s\n", txHash2)
x/observer/types/crosschain_flags.go (1)

8-10: Consider documenting the rationale for the 10-minute interval.

While the RetryInterval of 10 minutes seems reasonable, it would be beneficial to document why this specific duration was chosen, especially in the context of Bitcoin transaction fee dynamics.

e2e/utils/bitcoin.go (2)

13-32: Enhance error messages for better debugging.

Consider adding more descriptive error messages to the assertions to help identify which specific condition failed:

-    require.Negative(t, txResult.Confirmations)
+    require.Negative(t, txResult.Confirmations, "transaction should have negative confirmations")

-    require.Error(t, err)
-    require.Nil(t, entry)
+    require.Error(t, err, "transaction should not be in mempool")
+    require.Nil(t, entry, "mempool entry should be nil")

-    require.Error(t, err)
-    require.Nil(t, rawTx)
+    require.Error(t, err, "transaction should not exist in blockchain")
+    require.Nil(t, rawTx, "raw transaction should be nil")

34-48: Add return value documentation and enhance error messages.

The function would benefit from:

  1. Documentation of the return value
  2. More descriptive error messages in assertions
-// MustHaveMinedTx ensures the given tx has been mined
+// MustHaveMinedTx ensures the given tx has been mined and returns the detailed transaction information.
+// It panics if the transaction is not mined or cannot be retrieved.
 func MustHaveMinedTx(ctx context.Context, client *rpcclient.Client, txHash *chainhash.Hash) *btcjson.TxRawResult {
     t := TestingFromContext(ctx)
 
     // positive confirmations
     txResult, err := client.GetTransaction(txHash)
-    require.NoError(t, err)
-    require.Positive(t, txResult.Confirmations)
+    require.NoError(t, err, "failed to get transaction")
+    require.Positive(t, txResult.Confirmations, "transaction should have positive confirmations")
 
     // tx exists in blockchain
     rawResult, err := client.GetRawTransactionVerbose(txHash)
-    require.NoError(t, err)
+    require.NoError(t, err, "failed to get raw transaction")
zetaclient/chains/bitcoin/rpc/rpc_test.go (2)

14-59: Extract magic numbers as named constants.

Consider defining constants for commonly used values to improve maintainability:

+const (
+    normalFeeRate     = 0.0001
+    negativeFeeRate   = -0.0001
+    maxSupplyFeeRate  = 21000000
+    expectedNormalRate = 10
+    expectedRegnetRate = 1
+)

 func Test_GetEstimatedFeeRate(t *testing.T) {
     tests := []struct {

61-91: Simplify switch statement using if-else.

The switch statement with a single condition could be simplified:

-           switch {
-           case tt.rpcError:
+           if tt.rpcError {
                client.On("EstimateSmartFee", mock.Anything, mock.Anything).Return(nil, errors.New("error"))
-           case tt.resultError:
+           } else if tt.resultError {
                client.On("EstimateSmartFee", mock.Anything, mock.Anything).Return(&btcjson.EstimateSmartFeeResult{
                    Errors: []string{"error"},
                }, nil)
-           default:
+           } else {
                client.On("EstimateSmartFee", mock.Anything, mock.Anything).
                    Maybe().
                    Return(&btcjson.EstimateSmartFeeResult{
                        Errors:  nil,
                        FeeRate: &tt.rate,
                    }, nil)
-           }
+           }
e2e/e2etests/test_bitcoin_deposit_and_withdraw_with_dust.go (1)

16-22: Improve documentation for the WaitGroup usage.

The documentation should explain why synchronization is needed:

-// wgDeposit is a wait group for deposit runner to finish
+// wgDepositRunner coordinates the completion of Bitcoin deposit runners across E2E tests.
+// It ensures that all deposit-related operations are completed before the test suite ends,
+// preventing potential race conditions or resource leaks.
 var wgDepositRunner sync.WaitGroup

 func init() {
-    // there is one single deposit runner for Bitcoin E2E tests
+    // Initialize with count 1 as there is exactly one deposit runner for Bitcoin E2E tests
     wgDepositRunner.Add(1)
 }
zetaclient/chains/bitcoin/observer/db.go (1)

42-43: Improve security comment documentation.

The "#nosec G115" comment should include a brief explanation of why this case is safe to ignore.

-  // #nosec G115 always positive
+  // #nosec G115 blockNumber from Bitcoin RPC is guaranteed to be positive
zetaclient/chains/bitcoin/observer/db_test.go (2)

15-35: Add edge cases to SaveBroadcastedTx tests.

Consider adding test cases for:

  • Empty transaction hash
  • Zero nonce
  • Database connection failures

90-116: Add negative test case for LoadBroadcastedTxMap.

Consider adding a test case for database read failures to ensure proper error handling.

zetaclient/chains/bitcoin/signer/sign_rbf_test.go (2)

21-28: Add documentation for the test transaction reference.

Consider adding a comment explaining why this specific transaction was chosen as a test case and what aspects it validates.


173-228: Consider extracting test setup logic.

The test setup logic, particularly the mock configuration, could be moved to a separate helper function to improve readability.

+func setupTestMocks(s *testSuite, tt *testCase) {
+    // mock cctx rate
+    tt.cctx.GetCurrentOutboundParam().GasPriorityFee = tt.cctxRate
+
+    // mock RPC live fee rate setup
+    setupFeeMocks(s, tt)
+
+    // mock RPC transactions setup
+    setupTransactionMocks(s, tt)
+}
+
 func Test_SignRBFTx(t *testing.T) {
     // ... existing setup code ...
     for _, tt := range tests {
         t.Run(tt.name, func(t *testing.T) {
             s := newTestSuite(t, tt.chain)
-            // mock setup code
+            setupTestMocks(s, &tt)
zetaclient/chains/bitcoin/signer/outbound_data_test.go (2)

95-141: Consider adding more specific error messages for better debugging.

While the error cases are well-covered, the error messages could be more specific to help with debugging.

Apply this diff to enhance error messages:

-			errMsg:       "cctx is nil",
+			errMsg:       "invalid input: cctx is nil",

-			errMsg:   "can only send gas token to a Bitcoin network",
+			errMsg:   "invalid coin type: can only send gas token to a Bitcoin network",

-			errMsg:   "cannot convert gas price",
+			errMsg:   "invalid gas price format: cannot convert to numeric value",

-			errMsg:   "cannot decode receiver address",
+			errMsg:   "invalid receiver address format: cannot decode Bitcoin address",

-			errMsg:   "unsupported receiver address",
+			errMsg:   "unsupported receiver address type: expected P2PKH or P2WPKH",

142-194: Consider adding test cases for boundary conditions.

The test cases for restricted CCTX and dust amount are good, but consider adding tests for boundary conditions.

Add test cases for:

  1. Amount exactly equal to dust threshold
  2. Maximum allowed amount
  3. Edge cases for gas prices (0, maximum allowed)
zetaclient/chains/interfaces/interfaces.go (1)

167-167: Consider adding documentation for the new method.

The new GetMempoolEntry method is well-placed, but would benefit from documentation explaining its purpose in the context of RBF functionality.

Add documentation above the method:

+	// GetMempoolEntry retrieves detailed information about a transaction in the mempool.
+	// This is used for monitoring transaction status and implementing RBF (Replace-By-Fee) functionality.
	GetMempoolEntry(txHash string) (*btcjson.GetMempoolEntryResult, error)
zetaclient/chains/bitcoin/fee.go (2)

22-32: Consider using iota for sequential constants.

The transaction size-related constants could benefit from using iota for better maintainability and to prevent manual value assignments.

const (
-       bytesPerInput        = 41          // each input is 41 bytes
-       bytesPerOutputP2TR   = 43          // each P2TR output is 43 bytes
-       bytesPerOutputP2WSH  = 43          // each P2WSH output is 43 bytes
-       bytesPerOutputP2WPKH = 31          // each P2WPKH output is 31 bytes
-       bytesPerOutputP2SH   = 32          // each P2SH output is 32 bytes
-       bytesPerOutputP2PKH  = 34          // each P2PKH output is 34 bytes
+       bytesPerInput        = 41
+       bytesPerOutputP2TR   = iota + 43   // 43 bytes
+       bytesPerOutputP2WSH               // 43 bytes
+       bytesPerOutputP2WPKH = iota + 31  // 31 bytes
+       bytesPerOutputP2SH                // 32 bytes
+       bytesPerOutputP2PKH               // 34 bytes

49-49: Improve comment clarity.

The comment could be more descriptive about the purpose of this variable in the context of gas limits.

-       // This will be the suggested gas limit used for zetacore
+       // Suggested gas limit (177vB) used by zetacore for withdrawer transactions
e2e/utils/zetacore.go (1)

32-48: Add retry mechanism for resilience.

The function makes a single attempt to query the CCTX data. Consider adding a retry mechanism with backoff for better reliability in e2e tests.

+func withRetry(ctx context.Context, maxAttempts int, fn func() error) error {
+    var err error
+    for i := 0; i < maxAttempts; i++ {
+        if err = fn(); err == nil {
+            return nil
+        }
+        time.Sleep(time.Second * time.Duration(i+1))
+    }
+    return err
+}

 func GetCctxByInboundHash(
     ctx context.Context,
     inboundHash string,
     client crosschaintypes.QueryClient,
 ) *crosschaintypes.CrossChainTx {
     t := TestingFromContext(ctx)
-    // query cctx by inbound hash
-    in := &crosschaintypes.QueryInboundHashToCctxDataRequest{InboundHash: inboundHash}
-    res, err := client.InTxHashToCctxData(ctx, in)
+    var res *crosschaintypes.QueryInboundHashToCctxDataResponse
+    err := withRetry(ctx, 3, func() error {
+        var queryErr error
+        in := &crosschaintypes.QueryInboundHashToCctxDataRequest{InboundHash: inboundHash}
+        res, queryErr = client.InTxHashToCctxData(ctx, in)
+        return queryErr
+    })
zetaclient/chains/bitcoin/signer/fee_bumper_test.go (2)

21-105: Add test cases for edge cases.

The test function could benefit from additional test cases covering edge cases such as zero values and maximum values for fees and rates.

+        {
+            chain:    chains.BitcoinMainnet,
+            name:     "should handle maximum values",
+            client:   mocks.NewBTCRPCClient(t),
+            tx:       btcutil.NewTx(wire.NewMsgTx(wire.TxVersion)),
+            cctxRate: math.MaxInt64,
+            liveRate: float64(math.MaxInt64) / btcutil.SatoshiPerBitcoin,
+            errMsg:   "rate exceeds maximum allowed value",
+        },

249-326: Consider adding parallel test execution.

The test cases are independent and could benefit from parallel execution using t.Parallel().

 func Test_FetchFeeBumpInfo(t *testing.T) {
+    t.Parallel()
     liveRate := 0.00012
     mockClient := mocks.NewBTCRPCClient(t)
zetaclient/chains/bitcoin/observer/mempool_test.go (3)

423-443: Add detailed documentation for helper functions.

The helper functions would benefit from comprehensive documentation explaining:

  • The purpose and usage of each parameter
  • The expected behavior of the returned functions
  • Example usage in test cases

Add documentation blocks like this:

// makePendingTxFinder creates a mock implementation of PendingTxFinder for testing.
// Parameters:
//   - tx: The transaction to return, or nil to simulate no pending transaction
//   - nonce: The nonce to return with the transaction
//   - errMsg: If non-empty, the function will return an error with this message
// Returns a function that implements the PendingTxFinder interface.
func makePendingTxFinder(tx *btcutil.Tx, nonce uint64, errMsg string) observer.PendingTxFinder {

34-34: Fix typo in function name.

The function name contains a typo: Test_FefreshLastStuckOutbound should be Test_RefreshLastStuckOutbound.

-func Test_FefreshLastStuckOutbound(t *testing.T) {
+func Test_RefreshLastStuckOutbound(t *testing.T) {

108-349: Enhance test coverage with additional assertions.

The Test_GetLastPendingOutbound function could benefit from additional assertions to validate:

  • The transaction weight and size
  • The correctness of input and output scripts
  • Error message content for failure cases

Add assertions like this to the test cases:

// For successful cases
require.NotZero(t, lastTx.MsgTx().SerializeSize())
require.Greater(t, len(lastTx.MsgTx().TxIn), 0)
require.Greater(t, len(lastTx.MsgTx().TxOut), 0)

// For error cases
require.ErrorContains(t, err, "expected error message")
zetaclient/chains/bitcoin/rpc/rpc_live_test.go (1)

57-65: Well-structured testnet4 configuration.

The addition of testnet4 support is well-implemented with clear configuration parameters. Consider adding a comment explaining why testnet4 uses testnet3 network name.

Add a comment explaining the network name:

// testnet4 uses testnet3 network name because it shares the same network parameters
// and address format with testnet3
Params: "testnet3",
cmd/zetae2e/local/local.go (1)

320-320: Document reason for commented test.

The RBF test case is commented out without explanation. Add a comment explaining why this test is disabled and any conditions for re-enabling it.

// TODO(RBF-123): Temporarily disabled due to <reason>
// Re-enable when <condition> is met
//e2etests.TestBitcoinWithdrawRBFName,
changelog.md (2)

9-13: Consider removing empty sections.

The sections "Tests", "Refactor", and "Fixes" are currently empty. Consider removing them until there are actual entries to add, as empty sections don't provide value and can make the changelog harder to scan.

-### Tests
-
-## Refactor
-
-### Fixes

7-7: Enhance PR reference formatting.

Consider adding a brief description of the RBF feature for better context. The current format only mentions the PR number.

-* [3306](https://github.com/zeta-chain/node/pull/3306) - add support for Bitcoin RBF (Replace-By-Fee)
+* [3306](https://github.com/zeta-chain/node/pull/3306) - Add support for Bitcoin RBF (Replace-By-Fee) to enable stuck transaction replacement using fee bumping
x/crosschain/keeper/abci_test.go (3)

5-5: Consider removing duplicate chain imports.

The file imports both chains and zetachains from the same package. Consider using a single import to maintain clarity.

-import (
    "github.com/zeta-chain/node/pkg/chains"
    zetachains "github.com/zeta-chain/node/pkg/chains"
+import (
    "github.com/zeta-chain/node/pkg/chains"

Also applies to: 14-14


461-622: Consider adding edge cases to Bitcoin gas rate tests.

While the test coverage is good, consider adding these edge cases:

  1. Maximum gas rate boundary conditions
  2. Zero gas rate handling
  3. Negative gas rate scenarios
  4. Race conditions in gas rate updates

624-676: Consider documenting chain support status.

The test clearly defines which chains are supported for gas price updates. Consider adding comments to explain why certain chains are not supported and any future plans for support.

zetaclient/chains/bitcoin/observer/inbound_test.go (1)

170-170: Consider adding address validation checks.

While converting the address to string is correct, consider adding validation to ensure the address format is valid before conversion.

-FromAddress: sample.BtcAddressP2WPKH(t, &chaincfg.MainNetParams).String(),
+addr := sample.BtcAddressP2WPKH(t, &chaincfg.MainNetParams)
+require.NotNil(t, addr)
+FromAddress: addr.String(),
e2e/e2etests/e2etests.go (1)

721-729: Consider enhancing test documentation.

While the test registration is correct, consider adding more detailed documentation about:

  1. Expected RBF behavior
  2. Fee calculation strategy
  3. Success/failure conditions
  4. Required network conditions
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 47c9444 and e03ba4b.

📒 Files selected for processing (58)
  • changelog.md (1 hunks)
  • cmd/zetae2e/local/local.go (1 hunks)
  • contrib/localnet/docker-compose.yml (1 hunks)
  • e2e/e2etests/e2etests.go (2 hunks)
  • e2e/e2etests/helpers.go (3 hunks)
  • e2e/e2etests/test_bitcoin_deposit_and_withdraw_with_dust.go (2 hunks)
  • e2e/e2etests/test_bitcoin_withdraw_rbf.go (1 hunks)
  • e2e/utils/bitcoin.go (1 hunks)
  • e2e/utils/zetacore.go (3 hunks)
  • go.mod (1 hunks)
  • pkg/math/integer.go (1 hunks)
  • pkg/math/integer_test.go (1 hunks)
  • testutil/sample/crypto.go (2 hunks)
  • x/crosschain/keeper/abci.go (3 hunks)
  • x/crosschain/keeper/abci_test.go (5 hunks)
  • x/crosschain/module.go (1 hunks)
  • x/crosschain/types/cctx_test.go (1 hunks)
  • x/crosschain/types/revert_options_test.go (1 hunks)
  • x/observer/types/crosschain_flags.go (1 hunks)
  • zetaclient/chains/bitcoin/fee.go (7 hunks)
  • zetaclient/chains/bitcoin/fee_test.go (11 hunks)
  • zetaclient/chains/bitcoin/observer/db.go (1 hunks)
  • zetaclient/chains/bitcoin/observer/db_test.go (1 hunks)
  • zetaclient/chains/bitcoin/observer/event_test.go (5 hunks)
  • zetaclient/chains/bitcoin/observer/gas_price.go (1 hunks)
  • zetaclient/chains/bitcoin/observer/inbound_test.go (2 hunks)
  • zetaclient/chains/bitcoin/observer/mempool.go (1 hunks)
  • zetaclient/chains/bitcoin/observer/mempool_test.go (1 hunks)
  • zetaclient/chains/bitcoin/observer/observer.go (6 hunks)
  • zetaclient/chains/bitcoin/observer/observer_test.go (7 hunks)
  • zetaclient/chains/bitcoin/observer/outbound.go (7 hunks)
  • zetaclient/chains/bitcoin/observer/utxos.go (1 hunks)
  • zetaclient/chains/bitcoin/rpc/rpc.go (4 hunks)
  • zetaclient/chains/bitcoin/rpc/rpc_live_test.go (6 hunks)
  • zetaclient/chains/bitcoin/rpc/rpc_rbf_live_test.go (1 hunks)
  • zetaclient/chains/bitcoin/rpc/rpc_test.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/fee_bumper.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/fee_bumper_test.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/outbound_data.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/outbound_data_test.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/sign.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/sign_rbf.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/sign_rbf_test.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/sign_test.go (1 hunks)
  • zetaclient/chains/bitcoin/signer/signer.go (5 hunks)
  • zetaclient/chains/bitcoin/signer/signer_test.go (10 hunks)
  • zetaclient/chains/interfaces/interfaces.go (1 hunks)
  • zetaclient/common/constant.go (1 hunks)
  • zetaclient/common/env.go (1 hunks)
  • zetaclient/logs/fields.go (1 hunks)
  • zetaclient/orchestrator/bootstrap.go (1 hunks)
  • zetaclient/orchestrator/orchestrator.go (14 hunks)
  • zetaclient/testdata/btc/chain_8332_msgtx_030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0.json (1 hunks)
  • zetaclient/testdata/btc/chain_8332_tx_030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0.json (1 hunks)
  • zetaclient/testutils/mocks/btc_rpc.go (1 hunks)
  • zetaclient/testutils/mocks/zetacore_client_opts.go (1 hunks)
  • zetaclient/testutils/testdata.go (1 hunks)
  • zetaclient/testutils/testdata_naming.go (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • zetaclient/testdata/btc/chain_8332_tx_030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0.json
  • zetaclient/orchestrator/orchestrator.go
  • go.mod
  • contrib/localnet/docker-compose.yml
👮 Files not reviewed due to content moderation or server errors (4)
  • zetaclient/chains/bitcoin/signer/signer_test.go
  • zetaclient/chains/bitcoin/observer/event_test.go
  • zetaclient/orchestrator/bootstrap.go
  • zetaclient/testutils/mocks/btc_rpc.go
🧰 Additional context used
📓 Path-based instructions (52)
zetaclient/logs/fields.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/common/constant.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/crosschain/module.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

pkg/math/integer_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/testutils/testdata.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/interfaces/interfaces.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

pkg/math/integer.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/e2etests/test_bitcoin_deposit_and_withdraw_with_dust.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/crosschain/types/revert_options_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/observer/types/crosschain_flags.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/db_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

testutil/sample/crypto.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/utils/bitcoin.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/event_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/common/env.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/e2etests/test_bitcoin_withdraw_rbf.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/e2etests/e2etests.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/gas_price.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/testutils/mocks/btc_rpc.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/fee_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/e2etests/helpers.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/outbound_data_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

e2e/utils/zetacore.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/inbound_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/crosschain/types/cctx_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

cmd/zetae2e/local/local.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/sign_rbf.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/outbound_data.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/utxos.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/testutils/testdata_naming.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/sign_rbf_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/sign.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/db.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/crosschain/keeper/abci.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/mempool.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/signer.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/rpc/rpc_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/orchestrator/bootstrap.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/fee_bumper.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/testutils/mocks/zetacore_client_opts.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/rpc/rpc_live_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/rpc/rpc_rbf_live_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/fee_bumper_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/mempool_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

x/crosschain/keeper/abci_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/fee.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/signer_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/observer.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/signer/sign_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/observer_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/observer/outbound.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/bitcoin/rpc/rpc.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

📓 Learnings (1)
zetaclient/chains/bitcoin/observer/event_test.go (1)
Learnt from: ws4charlie
PR: zeta-chain/node#2987
File: pkg/memo/fields_v0_test.go:270-320
Timestamp: 2024-11-12T13:20:12.658Z
Learning: In the `FieldsV0` struct of the `memo` package, `RevertAddress` may be left empty when `CallOnRevert` is set to true.
🪛 GitHub Check: codecov/patch
zetaclient/chains/bitcoin/observer/gas_price.go

[warning] 16-21: zetaclient/chains/bitcoin/observer/gas_price.go#L16-L21
Added lines #L16 - L21 were not covered by tests


[warning] 24-36: zetaclient/chains/bitcoin/observer/gas_price.go#L24-L36
Added lines #L24 - L36 were not covered by tests


[warning] 38-45: zetaclient/chains/bitcoin/observer/gas_price.go#L38-L45
Added lines #L38 - L45 were not covered by tests


[warning] 51-70: zetaclient/chains/bitcoin/observer/gas_price.go#L51-L70
Added lines #L51 - L70 were not covered by tests


[warning] 74-77: zetaclient/chains/bitcoin/observer/gas_price.go#L74-L77
Added lines #L74 - L77 were not covered by tests


[warning] 80-87: zetaclient/chains/bitcoin/observer/gas_price.go#L80-L87
Added lines #L80 - L87 were not covered by tests


[warning] 89-89: zetaclient/chains/bitcoin/observer/gas_price.go#L89
Added line #L89 was not covered by tests


[warning] 93-104: zetaclient/chains/bitcoin/observer/gas_price.go#L93-L104
Added lines #L93 - L104 were not covered by tests

zetaclient/chains/bitcoin/observer/db.go

[warning] 20-23: zetaclient/chains/bitcoin/observer/db.go#L20-L23
Added lines #L20 - L23 were not covered by tests


[warning] 59-61: zetaclient/chains/bitcoin/observer/db.go#L59-L61
Added lines #L59 - L61 were not covered by tests

x/crosschain/keeper/abci.go

[warning] 63-64: x/crosschain/keeper/abci.go#L63-L64
Added lines #L63 - L64 were not covered by tests

zetaclient/chains/bitcoin/observer/mempool.go

[warning] 55-61: zetaclient/chains/bitcoin/observer/mempool.go#L55-L61
Added lines #L55 - L61 were not covered by tests


[warning] 64-70: zetaclient/chains/bitcoin/observer/mempool.go#L64-L70
Added lines #L64 - L70 were not covered by tests

zetaclient/chains/bitcoin/fee.go

[warning] 241-241: zetaclient/chains/bitcoin/fee.go#L241
Added line #L241 was not covered by tests


[warning] 281-281: zetaclient/chains/bitcoin/fee.go#L281
Added line #L281 was not covered by tests

zetaclient/chains/bitcoin/observer/observer.go

[warning] 172-174: zetaclient/chains/bitcoin/observer/observer.go#L172-L174
Added lines #L172 - L174 were not covered by tests

zetaclient/chains/bitcoin/observer/outbound.go

[warning] 38-38: zetaclient/chains/bitcoin/observer/outbound.go#L38
Added line #L38 was not covered by tests


[warning] 51-51: zetaclient/chains/bitcoin/observer/outbound.go#L51
Added line #L51 was not covered by tests


[warning] 58-58: zetaclient/chains/bitcoin/observer/outbound.go#L58
Added line #L58 was not covered by tests


[warning] 63-63: zetaclient/chains/bitcoin/observer/outbound.go#L63
Added line #L63 was not covered by tests


[warning] 65-65: zetaclient/chains/bitcoin/observer/outbound.go#L65
Added line #L65 was not covered by tests


[warning] 70-70: zetaclient/chains/bitcoin/observer/outbound.go#L70
Added line #L70 was not covered by tests


[warning] 77-82: zetaclient/chains/bitcoin/observer/outbound.go#L77-L82
Added lines #L77 - L82 were not covered by tests


[warning] 85-98: zetaclient/chains/bitcoin/observer/outbound.go#L85-L98
Added lines #L85 - L98 were not covered by tests


[warning] 100-102: zetaclient/chains/bitcoin/observer/outbound.go#L100-L102
Added lines #L100 - L102 were not covered by tests


[warning] 111-114: zetaclient/chains/bitcoin/observer/outbound.go#L111-L114
Added lines #L111 - L114 were not covered by tests


[warning] 119-119: zetaclient/chains/bitcoin/observer/outbound.go#L119
Added line #L119 was not covered by tests


[warning] 136-143: zetaclient/chains/bitcoin/observer/outbound.go#L136-L143
Added lines #L136 - L143 were not covered by tests


[warning] 145-145: zetaclient/chains/bitcoin/observer/outbound.go#L145
Added line #L145 was not covered by tests


[warning] 149-149: zetaclient/chains/bitcoin/observer/outbound.go#L149
Added line #L149 was not covered by tests

🔇 Additional comments (38)
zetaclient/chains/bitcoin/signer/sign_test.go (1)

1-22: LGTM! Well-organized imports.

The imports are logically grouped and all are being used in the test file.

zetaclient/chains/bitcoin/signer/outbound_data.go (3)

91-91: Verify units when adding minimum relay fee to fee rate

Ensure that the units of satPerByte and feeRate are consistent before addition. Both should be in satoshis/vByte to maintain correctness in fee calculations.

Please confirm that rpc.FeeRateToSatPerByte(minRelayFee) returns a value in satoshis/vByte and that adding it to feeRate is appropriate.


93-98: Ensure compliance checks are enforced downstream

While the compliance check flags restrictedCCTX, it's essential to verify that subsequent processing respects this flag. Ensure that restricted transactions are not inadvertently processed further.

Review the transaction pipeline to confirm that transactions with cancelTx set to true are appropriately handled and excluded from processing.


28-28: ⚠️ Potential issue

Use integer type for monetary amount to prevent precision errors

Using float64 for the amount can lead to precision and rounding errors in financial calculations, which is unacceptable in transaction processing. It is advisable to represent monetary amounts in the smallest currency unit—in this case, satoshis—using an integer type like uint64.

Apply the following change to the OutboundData struct:

-    amount float64
+    amount uint64 // amount in satoshis
⛔ Skipped due to learnings
Learnt from: ws4charlie
PR: zeta-chain/node#2899
File: zetaclient/chains/bitcoin/observer/inbound.go:37-38
Timestamp: 2024-11-12T13:20:12.658Z
Learning: In `BTCInboundEvent`, it's acceptable to use `float64` for monetary values (`Value` and `DepositorFee`) because precision is ensured through conversion to integer when building the vote message.
zetaclient/chains/bitcoin/signer/signer.go (1)

238-238: Verify the success of saving broadcasted transactions

Ensure that SaveBroadcastedTx operates as expected and consider handling any potential errors, even if the current implementation does not return an error.

Please confirm whether SaveBroadcastedTx can fail or return errors. If it can, handle errors appropriately:

 err := ob.SaveBroadcastedTx(txHash, nonce)
-if err != nil {
-    logger.Error().Err(err).Fields(lf).Msg("Failed to save broadcasted transaction")
-}
zetaclient/chains/bitcoin/signer/fee_bumper.go (2)

93-165: Well-structured fee bumping logic in BumpTxFee method

The BumpTxFee method is well-designed and follows best practices for implementing Child Pays for Parent (CPFP) fee bumping in Bitcoin transactions. The method carefully calculates the necessary additional fees, adheres to Bitcoin protocol requirements, and includes appropriate safeguards to prevent excessive fees and ensure transaction replacement effectiveness.


170-170: ⚠️ Potential issue

Possible typo in function name IsBitcoinRegnet

At line 170, the function IsBitcoinRegnet is used to determine if the chain ID corresponds to the Bitcoin regression test network. The standard term for Bitcoin's regression test network is "regtest". Please verify if the function should be IsBitcoinRegtest instead of IsBitcoinRegnet to adhere to standard Bitcoin nomenclature and avoid potential confusion.

zetaclient/chains/bitcoin/observer/utxos.go (1)

107-202: Efficient UTXO selection in SelectUTXOs method

The SelectUTXOs method effectively selects UTXOs to cover the transaction amount while considering consolidation of smaller UTXOs. The use of deterministic sorting and careful handling of nonce-mark UTXOs enhances the reliability of UTXO management. The logic appears sound, and the method balances optimal UTXO selection with performance considerations.

zetaclient/chains/bitcoin/signer/sign.go (2)

83-96: Verify the transaction size limits and fee calculations

The conditional checks and adjustments for txSize between lines 83-96 ensure that the transaction size is within acceptable bounds. However, ensure that the variables txData.txSize and txSize are consistently and correctly used. Additionally, confirm that the fee calculation aligns with the latest fee structures and network policies.


247-251: Ensure valid construction of ECDSA signatures

In lines 247-251, the code reconstructs the signature using btcec.ModNScalar. It is important to validate that R and S are correctly derived from the signature bytes to prevent invalid signatures.

Consider adding checks to ensure R and S are valid scalars within the acceptable range.

zetaclient/chains/bitcoin/observer/mempool.go (1)

80-128: Robust error handling in RefreshLastStuckOutbound

The RefreshLastStuckOutbound function contains complex logic for updating the state of stuck transactions. Ensure that all possible error paths are adequately handled and that the observer's state remains consistent in case of failures.

Review the error handling mechanisms to confirm that they prevent partial updates or inconsistent states.

zetaclient/chains/bitcoin/observer/outbound.go (2)

77-120: Add unit tests for new outbound processing functions

The ProcessOutboundTrackers and TryIncludeOutbound methods are key additions that handle outbound transaction processing. Currently, there is no test coverage for these methods, which may lead to unanticipated bugs or regressions. Develop comprehensive unit tests covering various scenarios, including normal operation, error conditions, and edge cases, to ensure these methods function correctly and reliably.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 77-82: zetaclient/chains/bitcoin/observer/outbound.go#L77-L82
Added lines #L77 - L82 were not covered by tests


[warning] 85-98: zetaclient/chains/bitcoin/observer/outbound.go#L85-L98
Added lines #L85 - L98 were not covered by tests


[warning] 100-102: zetaclient/chains/bitcoin/observer/outbound.go#L100-L102
Added lines #L100 - L102 were not covered by tests


[warning] 111-114: zetaclient/chains/bitcoin/observer/outbound.go#L111-L114
Added lines #L111 - L114 were not covered by tests


[warning] 119-119: zetaclient/chains/bitcoin/observer/outbound.go#L119
Added line #L119 was not covered by tests


285-292: Confirm regnet transaction stuck detection logic

In IsTxStuckInMempoolRegnet, the condition if pendingTime > pendingTimeAllowed && memplEntry.Height == lastBlock relies on the assumption that block mining is frozen in Regnet for end-to-end testing. Verify that this assumption holds in your testing environment. If block mining resumes or the environment changes, the condition may fail to accurately detect stuck transactions. Adjust the logic to align with the actual behavior of Regnet to maintain accurate detection.

zetaclient/logs/fields.go (1)

12-12: LGTM! Well-structured constant addition.

The new FieldOutboundID constant follows the established naming patterns and integrates well with the existing logging infrastructure.

zetaclient/common/constant.go (1)

17-19: LGTM! Well-documented constant addition.

The MempoolStuckTxCheckInterval constant is appropriately placed and documented, with a reasonable 30-second interval for mempool monitoring.

zetaclient/common/env.go (1)

17-19: LGTM! Consistent environment variable addition.

The EnvBtcRPCTestnet4 constant maintains consistency with existing BTC RPC network environment variables in both naming and documentation.

x/observer/types/crosschain_flags.go (1)

8-8: Verify removal of EpochLength field.

The removal of the EpochLength field represents a significant change from block-based to time-based intervals. Please ensure all dependent code has been updated accordingly.

✅ Verification successful

Transition from block-based to time-based intervals verified successfully.

The removal of EpochLength is part of a well-implemented architectural change from block-based to time-based intervals. The codebase has been properly updated to use RetryInterval with appropriate time-based checks in the gas price update mechanism.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to EpochLength
rg -l "EpochLength" --type go

Length of output: 489


Script:

#!/bin/bash
# Show actual usage of EpochLength with context, excluding test files
rg "EpochLength" --type go -g '!*_test.go' -B 2 -A 2

# Also check for any struct definitions or interface requirements
ast-grep --pattern 'type $_ struct {
  $$$
  EpochLength $_
  $$$
}'

Length of output: 6993


Script:

#!/bin/bash
# Check for recent changes in gas price increase related files
rg "RetryInterval" --type go -B 2 -A 2

# Look for any block height based checks that might need updating
ast-grep --pattern 'if $_.BlockHeight() $$ {
  $$$
}'

Length of output: 10800

zetaclient/testutils/mocks/zetacore_client_opts.go (1)

37-46: LGTM! Well-structured mock setup method.

The implementation follows established patterns in the codebase and properly handles both success and error cases while maintaining the chainable interface.

e2e/e2etests/test_bitcoin_deposit_and_withdraw_with_dust.go (1)

29-33: LGTM! Proper cleanup with deferred WaitGroup completion.

The deferred cleanup ensures proper synchronization while maintaining the existing stop functionality.

x/crosschain/types/revert_options_test.go (1)

52-52: LGTM! Test update maintains consistency.

The change correctly handles the Bitcoin address string conversion.

zetaclient/testutils/testdata_naming.go (1)

67-70: LGTM! Consistent with existing naming patterns.

The function follows the established naming convention and maintains consistency with other file naming functions in the module.

testutil/sample/crypto.go (2)

69-78: Improved type safety with stronger return type.

The change from returning a string to returning *btcutil.AddressWitnessPubKeyHash provides better type safety and direct access to address-specific methods.


80-85: LGTM! Well-structured script generation function.

The function properly generates P2WPKH scripts with appropriate error handling.

x/crosschain/module.go (1)

175-175: Verify the impact of removing gas price update callback.

The change from using keeper.CheckAndUpdateCctxGasPrice to nil might affect how gas prices are updated. Please ensure this change aligns with the new RBF implementation.

✅ Verification successful

Passing nil callback is correct and safe.

The change aligns with the architecture where each chain type (EVM, Bitcoin) has its specific gas price update mechanism, and nil is explicitly handled for ZetaChain itself.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other uses of CheckAndUpdateCctxGasPrice to ensure they're properly handled
rg -A 5 "CheckAndUpdateCctxGasPrice"

# Look for any new gas price update mechanisms
ast-grep --pattern 'func $_(ctx sdk.Context, chains []$_, $_) {
  $$$
}'

Length of output: 4409

zetaclient/chains/bitcoin/signer/sign_rbf_test.go (1)

82-94: LGTM! Well-structured test cases.

The test cases cover essential scenarios including:

  • Successful RBF transaction signing
  • Missing fee rate handling
  • Fee bumper creation errors
  • High fee rate scenarios
zetaclient/chains/bitcoin/signer/outbound_data_test.go (2)

17-66: LGTM! Well-structured test case with comprehensive assertions.

The test case effectively validates the successful creation of outbound data with proper fee calculations and parameter validations.


67-94: LGTM! Good test coverage for gas rate updates.

The test case properly verifies that the current gas rate takes precedence over the old rate, which is crucial for the RBF functionality.

x/crosschain/types/cctx_test.go (1)

143-143: LGTM! Consistent string representation of Bitcoin addresses.

Using the String() method ensures consistent string representation of Bitcoin addresses across the codebase.

zetaclient/chains/bitcoin/observer/observer_test.go (3)

243-274: LGTM! Well-structured test with clear steps.

The test effectively validates the lifecycle of a stuck outbound transaction with clear steps:

  1. Initial state verification
  2. Setting stuck outbound
  3. Updating stuck outbound
  4. Clearing stuck outbound

312-317: LGTM! Chain-specific TSS signer setup.

The conditional setup of TSS signer based on chain type improves test accuracy.


319-326: LGTM! Flexible database setup.

The database setup now supports both in-memory and file-based databases, improving test flexibility.

zetaclient/chains/bitcoin/fee.go (1)

61-61: ⚠️ Potential issue

Validate input parameters.

The function accepts unsigned integers but returns a signed integer. Consider adding validation for large input values to prevent potential overflow.

 func WiredTxSize(numInputs uint64, numOutputs uint64) int64 {
+    // Validate input parameters to prevent overflow
+    if numInputs > math.MaxInt64 || numOutputs > math.MaxInt64 {
+        return -1
+    }
     // Version 4 bytes + LockTime 4 bytes + Serialized varint size for the
     // number of transaction inputs and outputs.

Also applies to: 65-65

zetaclient/chains/bitcoin/signer/fee_bumper_test.go (1)

107-247: LGTM! Comprehensive test coverage.

The test cases cover various scenarios including successful fee bumping, reserved fee handling, and error conditions.

zetaclient/chains/bitcoin/fee_test.go (1)

187-191: Good addition of edge case test.

The new test case for handling no UTXOs is a valuable addition that ensures the system behaves correctly when there are no unspent transaction outputs.

zetaclient/chains/bitcoin/rpc/rpc_live_test.go (1)

115-139: Good test organization.

The separation of tests into logical groups (Test_BitcoinLive and Test_BitcoinFeeLive) improves maintainability and clarity.

zetaclient/testdata/btc/chain_8332_msgtx_030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0.json (1)

1-95: Transaction structure correctly supports RBF.

The transaction is well-formed with:

  • Proper witness data for each input
  • Maximum sequence numbers (4294967295) enabling RBF
  • Correctly structured outputs with values and scripts
x/crosschain/keeper/abci_test.go (1)

92-106: LGTM: Test coverage expanded for Bitcoin chain.

The test coverage has been appropriately expanded to include Bitcoin chain test cases, with proper assertions for chain-specific indices.

e2e/e2etests/e2etests.go (1)

93-93: LGTM: Test constant follows naming convention.

The new test constant follows the established naming pattern for Bitcoin-related tests.

zetaclient/chains/bitcoin/signer/sign_test.go Show resolved Hide resolved
Comment on lines 16 to 22
default:
increase := float64(value) * float64(percent) / 100
if round {
return value + int64(math.Round(increase))
}
return value + int64(increase)
}
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

Add input validation and overflow protection.

The implementation correctly handles the percentage calculation, but consider adding:

  1. Input validation for negative values
  2. Overflow protection for large numbers
 func IncreaseIntByPercent(value int64, percent uint32, round bool) int64 {
+	// Handle negative values
+	if value < 0 {
+		return -IncreaseIntByPercent(-value, percent, round)
+	}
+
+	// Protect against overflow
+	if value > math.MaxInt64/2 {
+		// Handle large numbers carefully
+		ratio := 1.0 + float64(percent)/100.0
+		if ratio > float64(math.MaxInt64)/float64(value) {
+			return math.MaxInt64
+		}
+	}
+
 	switch {

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

Comment on lines 10 to 29
func Test_IncreaseIntByPercent(t *testing.T) {
for i, tt := range []struct {
value int64
percent uint32
round bool
expected int64
}{
{value: 10, percent: 0, round: false, expected: 10},
{value: 10, percent: 15, round: false, expected: 11},
{value: 10, percent: 15, round: true, expected: 12},
{value: 10, percent: 14, round: false, expected: 11},
{value: 10, percent: 14, round: true, expected: 11},
{value: 10, percent: 200, round: false, expected: 30},
{value: 10, percent: 200, round: true, expected: 30},
} {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
result := IncreaseIntByPercent(tt.value, tt.percent, tt.round)
assert.Equal(t, tt.expected, result)
})
}
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

Enhance test coverage with additional edge cases.

While the current test cases cover basic functionality, consider adding:

  1. Edge cases for negative values
  2. Boundary tests for large numbers near int64 limits
  3. Maximum uint32 percentage tests
  4. More descriptive test names instead of numeric indices
 func Test_IncreaseIntByPercent(t *testing.T) {
 	for i, tt := range []struct {
 		value    int64
 		percent  uint32
 		round    bool
 		expected int64
+		name     string
 	}{
-		{value: 10, percent: 0, round: false, expected: 10},
+		{
+			name: "zero_percent_no_change",
+			value: 10, percent: 0, round: false, expected: 10,
+		},
+		// ... existing cases with descriptive names ...
+		{
+			name: "negative_value",
+			value: -10, percent: 15, round: true, expected: -12,
+		},
+		{
+			name: "large_value_no_overflow",
+			value: math.MaxInt64/2, percent: 50, round: false,
+			expected: math.MaxInt64/2 + math.MaxInt64/4,
+		},
+		{
+			name: "max_percentage",
+			value: 10, percent: math.MaxUint32, round: true,
+			expected: math.MaxInt64, // or appropriate expected value
+		},
 	} {
-		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+		t.Run(tt.name, func(t *testing.T) {

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

amount: amount,
feeRate: feeRate,
// #nosec G115 always in range
txSize: int64(params.CallOptions.GasLimit),
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

Validate GasLimit before type conversion to prevent overflow

Casting params.CallOptions.GasLimit from uint64 to int64 without validation can cause overflow errors if the value exceeds the maximum value of int64. Ensure that GasLimit is within the acceptable range before performing the conversion.

Include a validation check:

if params.CallOptions.GasLimit > math.MaxInt64 {
    return nil, fmt.Errorf("GasLimit %d exceeds int64 maximum value", params.CallOptions.GasLimit)
}
txSize := int64(params.CallOptions.GasLimit)

Remember to import the math package:

import (
    "math"
)

Comment on lines +67 to +69
if err != nil || feeRate < 0 {
return nil, fmt.Errorf("cannot convert gas price %s", params.GasPrice)
}
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

Handle zero or negative fee rates appropriately

A feeRate of zero or negative value is invalid for transaction processing and should be explicitly checked and rejected to prevent transaction failures or unexpected behaviors.

Update the condition to include zero:

-    if err != nil || feeRate < 0 {
+    if err != nil || feeRate <= 0 {

Adjust the error message for clarity:

-        return nil, fmt.Errorf("cannot convert gas price %s", params.GasPrice)
+        return nil, fmt.Errorf("invalid gas price %s", params.GasPrice)
📝 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
if err != nil || feeRate < 0 {
return nil, fmt.Errorf("cannot convert gas price %s", params.GasPrice)
}
if err != nil || feeRate <= 0 {
return nil, fmt.Errorf("invalid gas price %s", params.GasPrice)
}

Comment on lines +69 to +76
func EstimateOutboundSize(numInputs int64, payees []btcutil.Address) (int64, error) {
if numInputs <= 0 {
return 0, nil
}
// #nosec G115 always positive
numOutputs := 2 + uint64(len(payees))
bytesWiredTx := WiredTxSize(numInputs, numOutputs)
// #nosec G115 checked positive
bytesWiredTx := WiredTxSize(uint64(numInputs), numOutputs)
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

Consider error handling for negative inputs.

While the function now accepts negative inputs and returns early, it might be better to return an error to provide more context about the invalid input.

-func EstimateOutboundSize(numInputs int64, payees []btcutil.Address) (int64, error) {
-    if numInputs <= 0 {
-        return 0, nil
-    }
+func EstimateOutboundSize(numInputs int64, payees []btcutil.Address) (int64, error) {
+    if numInputs <= 0 {
+        return 0, fmt.Errorf("invalid number of inputs: %d", numInputs)
+    }
📝 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
func EstimateOutboundSize(numInputs int64, payees []btcutil.Address) (int64, error) {
if numInputs <= 0 {
return 0, nil
}
// #nosec G115 always positive
numOutputs := 2 + uint64(len(payees))
bytesWiredTx := WiredTxSize(numInputs, numOutputs)
// #nosec G115 checked positive
bytesWiredTx := WiredTxSize(uint64(numInputs), numOutputs)
func EstimateOutboundSize(numInputs int64, payees []btcutil.Address) (int64, error) {
if numInputs <= 0 {
return 0, fmt.Errorf("invalid number of inputs: %d", numInputs)
}
// #nosec G115 always positive
numOutputs := 2 + uint64(len(payees))
// #nosec G115 checked positive
bytesWiredTx := WiredTxSize(uint64(numInputs), numOutputs)

@@ -246,7 +238,7 @@

// GetRecentFeeRate gets the highest fee rate from recent blocks
// Note: this method should be used for testnet ONLY
func GetRecentFeeRate(rpcClient interfaces.BTCRPCClient, netParams *chaincfg.Params) (uint64, error) {
func GetRecentFeeRate(rpcClient interfaces.BTCRPCClient, netParams *chaincfg.Params) (int64, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Add comprehensive unit test coverage for GetRecentFeeRate

The function requires unit tests covering:

  • Mainnet rejection validation
  • RPC error scenarios (GetBlockCount, GetBlockHash, GetBlockVerboseTx)
  • Fee rate calculation logic
  • Edge cases with zero or low fee transactions

While a live test exists in the RPC package, it only covers the happy path and requires a testnet connection. Consider using a mock BTCRPCClient interface to create proper unit tests that can run in CI/CD pipelines.

🔗 Analysis chain

Add test coverage for GetRecentFeeRate.

The static analysis indicates that the function lacks test coverage. Consider adding test cases for both success and error scenarios.

Also applies to: 281-281

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing test coverage
rg -l "func.*GetRecentFeeRate" --type go | xargs rg "Test.*GetRecentFeeRate"

Length of output: 369


Script:

#!/bin/bash
# Check the implementation details of both functions
echo "=== Implementation in bitcoin package ==="
ast-grep --pattern 'func GetRecentFeeRate($_) {
  $$$
}'

echo -e "\n=== Implementation in rpc package ==="
ast-grep --pattern 'func LiveTest_GetRecentFeeRate($_) {
  $$$
}'

echo -e "\n=== Looking for unit tests ==="
rg "func Test.*GetRecentFeeRate" --type go

Length of output: 1290


Script:

#!/bin/bash
# Get the implementation details of GetRecentFeeRate
echo "=== GetRecentFeeRate Implementation ==="
rg -A 20 "func GetRecentFeeRate" zetaclient/chains/bitcoin/fee.go

Length of output: 880

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 241-241: zetaclient/chains/bitcoin/fee.go#L241
Added line #L241 was not covered by tests

Comment on lines +209 to +257
// WaitOutboundTracker wait for outbound tracker to be filled with 'hashCount' hashes
func WaitOutboundTracker(
ctx context.Context,
client crosschaintypes.QueryClient,
chainID int64,
nonce uint64,
hashCount int,
logger infoLogger,
timeout time.Duration,
) []string {
if timeout == 0 {
timeout = DefaultCctxTimeout
}

t := TestingFromContext(ctx)
startTime := time.Now()
in := &crosschaintypes.QueryAllOutboundTrackerByChainRequest{Chain: chainID}

for {
require.False(
t,
time.Since(startTime) > timeout,
fmt.Sprintf("waiting outbound tracker timeout, chainID: %d, nonce: %d", chainID, nonce),
)
time.Sleep(5 * time.Second)

outboundTracker, err := client.OutboundTrackerAllByChain(ctx, in)
require.NoError(t, err)

// loop through all outbound trackers
for i, tracker := range outboundTracker.OutboundTracker {
if tracker.Nonce == nonce {
logger.Info("Tracker[%d]:\n", i)
logger.Info(" ChainId: %d\n", tracker.ChainId)
logger.Info(" Nonce: %d\n", tracker.Nonce)
logger.Info(" HashList:\n")

hashes := []string{}
for j, hash := range tracker.HashList {
hashes = append(hashes, hash.TxHash)
logger.Info(" hash[%d]: %s\n", j, hash.TxHash)
}
if len(hashes) >= hashCount {
return hashes
}
}
}
}
}
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

Improve error handling and logging.

The function could benefit from more structured error handling and detailed logging.

 func WaitOutboundTracker(
     ctx context.Context,
     client crosschaintypes.QueryClient,
     chainID int64,
     nonce uint64,
     hashCount int,
     logger infoLogger,
     timeout time.Duration,
 ) []string {
+    if hashCount <= 0 {
+        panic("hashCount must be positive")
+    }
     if timeout == 0 {
         timeout = DefaultCctxTimeout
     }

     t := TestingFromContext(ctx)
     startTime := time.Now()
     in := &crosschaintypes.QueryAllOutboundTrackerByChainRequest{Chain: chainID}

+    logger.Info("Starting outbound tracker wait",
+        "chainID", chainID,
+        "nonce", nonce,
+        "expectedHashes", hashCount,
+        "timeout", timeout)

     for {
         require.False(
             t,
             time.Since(startTime) > timeout,
             fmt.Sprintf("waiting outbound tracker timeout, chainID: %d, nonce: %d", chainID, nonce),
         )
📝 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
// WaitOutboundTracker wait for outbound tracker to be filled with 'hashCount' hashes
func WaitOutboundTracker(
ctx context.Context,
client crosschaintypes.QueryClient,
chainID int64,
nonce uint64,
hashCount int,
logger infoLogger,
timeout time.Duration,
) []string {
if timeout == 0 {
timeout = DefaultCctxTimeout
}
t := TestingFromContext(ctx)
startTime := time.Now()
in := &crosschaintypes.QueryAllOutboundTrackerByChainRequest{Chain: chainID}
for {
require.False(
t,
time.Since(startTime) > timeout,
fmt.Sprintf("waiting outbound tracker timeout, chainID: %d, nonce: %d", chainID, nonce),
)
time.Sleep(5 * time.Second)
outboundTracker, err := client.OutboundTrackerAllByChain(ctx, in)
require.NoError(t, err)
// loop through all outbound trackers
for i, tracker := range outboundTracker.OutboundTracker {
if tracker.Nonce == nonce {
logger.Info("Tracker[%d]:\n", i)
logger.Info(" ChainId: %d\n", tracker.ChainId)
logger.Info(" Nonce: %d\n", tracker.Nonce)
logger.Info(" HashList:\n")
hashes := []string{}
for j, hash := range tracker.HashList {
hashes = append(hashes, hash.TxHash)
logger.Info(" hash[%d]: %s\n", j, hash.TxHash)
}
if len(hashes) >= hashCount {
return hashes
}
}
}
}
}
// WaitOutboundTracker wait for outbound tracker to be filled with 'hashCount' hashes
func WaitOutboundTracker(
ctx context.Context,
client crosschaintypes.QueryClient,
chainID int64,
nonce uint64,
hashCount int,
logger infoLogger,
timeout time.Duration,
) []string {
if hashCount <= 0 {
panic("hashCount must be positive")
}
if timeout == 0 {
timeout = DefaultCctxTimeout
}
t := TestingFromContext(ctx)
startTime := time.Now()
in := &crosschaintypes.QueryAllOutboundTrackerByChainRequest{Chain: chainID}
logger.Info("Starting outbound tracker wait",
"chainID", chainID,
"nonce", nonce,
"expectedHashes", hashCount,
"timeout", timeout)
for {
require.False(
t,
time.Since(startTime) > timeout,
fmt.Sprintf("waiting outbound tracker timeout, chainID: %d, nonce: %d", chainID, nonce),
)
time.Sleep(5 * time.Second)
outboundTracker, err := client.OutboundTrackerAllByChain(ctx, in)
require.NoError(t, err)
// loop through all outbound trackers
for i, tracker := range outboundTracker.OutboundTracker {
if tracker.Nonce == nonce {
logger.Info("Tracker[%d]:\n", i)
logger.Info(" ChainId: %d\n", tracker.ChainId)
logger.Info(" Nonce: %d\n", tracker.Nonce)
logger.Info(" HashList:\n")
hashes := []string{}
for j, hash := range tracker.HashList {
hashes = append(hashes, hash.TxHash)
logger.Info(" hash[%d]: %s\n", j, hash.TxHash)
}
if len(hashes) >= hashCount {
return hashes
}
}
}
}
}

Comment on lines +120 to +126
// LoadBTCTransaction loads archived Bitcoin transaction from file
func LoadBTCTransaction(t *testing.T, dir string, chainID int64, txHash string) *btcjson.GetTransactionResult {
name := path.Join(dir, TestDataPathBTC, FileNameBTCTransaction(chainID, txHash))
tx := &btcjson.GetTransactionResult{}
LoadObjectFromJSONFile(t, tx, name)
return tx
}
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

Add validation for input parameters.

The function should validate the input parameters before attempting to load the transaction.

 func LoadBTCTransaction(t *testing.T, dir string, chainID int64, txHash string) *btcjson.GetTransactionResult {
+    require.NotEmpty(t, dir, "directory path cannot be empty")
+    require.NotEmpty(t, txHash, "transaction hash cannot be empty")
+    require.Greater(t, chainID, int64(0), "chain ID must be positive")
+
     name := path.Join(dir, TestDataPathBTC, FileNameBTCTransaction(chainID, txHash))
     tx := &btcjson.GetTransactionResult{}
     LoadObjectFromJSONFile(t, tx, name)
     return tx
 }
📝 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
// LoadBTCTransaction loads archived Bitcoin transaction from file
func LoadBTCTransaction(t *testing.T, dir string, chainID int64, txHash string) *btcjson.GetTransactionResult {
name := path.Join(dir, TestDataPathBTC, FileNameBTCTransaction(chainID, txHash))
tx := &btcjson.GetTransactionResult{}
LoadObjectFromJSONFile(t, tx, name)
return tx
}
// LoadBTCTransaction loads archived Bitcoin transaction from file
func LoadBTCTransaction(t *testing.T, dir string, chainID int64, txHash string) *btcjson.GetTransactionResult {
require.NotEmpty(t, dir, "directory path cannot be empty")
require.NotEmpty(t, txHash, "transaction hash cannot be empty")
require.Greater(t, chainID, int64(0), "chain ID must be positive")
name := path.Join(dir, TestDataPathBTC, FileNameBTCTransaction(chainID, txHash))
tx := &btcjson.GetTransactionResult{}
LoadObjectFromJSONFile(t, tx, name)
return tx
}

Comment on lines +328 to +344
func Test_CopyMsgTxNoWitness(t *testing.T) {
chain := chains.BitcoinMainnet
txid := "030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0"
msgTx := testutils.LoadBTCMsgTx(t, TestDataDir, chain.ChainId, txid)

// make a non-witness copy
copyTx := signer.CopyMsgTxNoWitness(msgTx)

// make another copy and clear witness data manually
newTx := msgTx.Copy()
for idx := range newTx.TxIn {
newTx.TxIn[idx].Witness = wire.TxWitness{}
}

// check
require.Equal(t, newTx, copyTx)
}
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

Add test case for nil input.

The test should include a case for handling nil input to ensure proper error handling.

 func Test_CopyMsgTxNoWitness(t *testing.T) {
+    t.Run("should handle nil input", func(t *testing.T) {
+        require.Panics(t, func() {
+            signer.CopyMsgTxNoWitness(nil)
+        }, "should panic on nil input")
+    })

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

Copy link
Member

@lumtis lumtis left a comment

Choose a reason for hiding this comment

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

First review, haven't check in details the change in ZetaClient for now.

We need smaller PRs in the future.

This one could have been break down in a few PRs

@@ -317,6 +317,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
e2etests.TestBitcoinWithdrawP2WSHName,
e2etests.TestBitcoinWithdrawMultipleName,
e2etests.TestBitcoinWithdrawRestrictedName,
//e2etests.TestBitcoinWithdrawRBFName, // leave it as the last BTC test
Copy link
Member

Choose a reason for hiding this comment

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

Why is it disabled for now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

only RBF test requires setting minTxConfirmations = 1 to fake and simulate a pending outbound in mempool. All other tests are supposed to be ran under minTxConfirmations = 0, which is the case for mainnet/testnet.

// wgDeposit is a wait group for deposit runner to finish
var wgDepositRunner sync.WaitGroup

func init() {
Copy link
Member

Choose a reason for hiding this comment

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

Let's not use init in e2e package why do we need this waitgroup?

Copy link
Contributor Author

@ws4charlie ws4charlie Jan 13, 2025

Choose a reason for hiding this comment

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

The TestBitcoinWithdrawRBFName needs Bitcoin block generation to stop, so it has to run as the last Bitcoin E2E test after all other tests have completed (so height stop growing). This is to allow the broadcasted outbound tx to be pending in the mempool for a while. Otherwise, all mempool txs will be cleared on every new block and there is no chance to replace the pending tx.

e2e/e2etests/test_bitcoin_withdraw_rbf.go Outdated Show resolved Hide resolved
e2e/utils/zetacore.go Outdated Show resolved Hide resolved
@@ -0,0 +1,23 @@
package math
Copy link
Member

Choose a reason for hiding this comment

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

Can we add a package comment explaining why this package is needed?

x/crosschain/keeper/abci.go Outdated Show resolved Hide resolved
x/crosschain/keeper/abci.go Outdated Show resolved Hide resolved
return math.ZeroUint(), math.ZeroUint(), nil
}

// GetCctxGasPriceUpdater returns the function to update gas price according to chain type
Copy link
Member

Choose a reason for hiding this comment

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

Need more details what does this function represent

}

// GetCctxGasPriceUpdater returns the function to update gas price according to chain type
func GetCctxGasPriceUpdater(chainID int64, additionalChains []zetachains.Chain) (CheckAndUpdateCctxGasPriceFunc, bool) {
Copy link
Member

Choose a reason for hiding this comment

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

Why creating this getter function instead of a CheckAndUpdateCctxGasPrice that dispatch to the correct function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good idea. I can bring the method CheckAndUpdateCCTXGasPrice back and wrap some common code (like below sanity check code) and dispatch it to CheckAndUpdateCCTXGasPriceEVM and CheckAndUpdateCCTXGasRateBTC

Comment on lines +196 to +216
) (math.Uint, math.Uint, error) {
// skip if gas price or gas limit is not set
if cctx.GetCurrentOutboundParam().GasPrice == "" || cctx.GetCurrentOutboundParam().CallOptions.GasLimit == 0 {
return math.ZeroUint(), math.ZeroUint(), nil
}

// skip if retry interval is not reached
lastUpdated := time.Unix(cctx.CctxStatus.LastUpdateTimestamp, 0)
if ctx.BlockTime().Before(lastUpdated.Add(flags.RetryInterval)) {
return math.ZeroUint(), math.ZeroUint(), nil
}

// compute gas price increase
chainID := cctx.GetCurrentOutboundParam().ReceiverChainId
medianGasPrice, _, isFound := k.GetMedianGasValues(ctx, chainID)
if !isFound {
return math.ZeroUint(), math.ZeroUint(), cosmoserrors.Wrap(
types.ErrUnableToGetGasPrice,
fmt.Sprintf("cannot get gas price for chain %d", chainID),
)
}
Copy link
Member

Choose a reason for hiding this comment

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

Can't this be put in common between BTC and EVM?

Copy link
Contributor

@swift1337 swift1337 left a comment

Choose a reason for hiding this comment

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

Given recent incidents & Orchestrator V2, revamp, I think this PR requires 2 prerequisites before thorough review:

  1. Merging changes from develop as it has many conflicts
  2. Implementing a custom rpc mentioned in zetaclient stops connecting to external chain RPCs after receiving HTTP error codes.  #3328

I started work on (2). Will also take a closer look on this PR later today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking:cli chain:bitcoin Bitcoin chain related nosec zetaclient Issues related to ZetaClient zetacore Issues related to ZetaCore
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants