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: Add RBF and CPFP Batcher wallets #21

Merged
merged 47 commits into from
Jul 25, 2024
Merged

feat: Add RBF and CPFP Batcher wallets #21

merged 47 commits into from
Jul 25, 2024

Conversation

yash1io
Copy link
Contributor

@yash1io yash1io commented Jul 15, 2024

  • Adds batcher wallet
  • Implements RBF and CPFP strategies

Summary by CodeRabbit

  • New Features

    • Introduced a sophisticated batching mechanism for Bitcoin transactions, allowing for improved efficiency and flexibility.
    • Enhanced wallet capabilities with new interfaces and methods for lifecycle management, fee strategies, and transaction batching.
    • Implemented a caching mechanism for managing transaction batches, improving transaction processing and storage efficiency.
  • Bug Fixes

    • Resolved formatting issues in the workflow configuration to enhance clarity and adherence to standards.
    • Improved error handling and validation in wallet transaction processing.
  • Tests

    • Added extensive test suites for RBF and CPFP functionalities, ensuring reliability in transaction processing and fee adjustments.
    • Enhanced wallet tests with better structure, error handling, and transaction assertions.
    • Introduced a comprehensive suite of tests for the caching mechanism, validating batch operations and request management.

Copy link
Contributor

coderabbitai bot commented Jul 15, 2024

Walkthrough

Recent updates enhance Bitcoin transaction management by introducing the BatcherWallet interface, supporting advanced batching strategies like RBF (Replace-By-Fee) and CPFP (Child Pays For Parent). Key improvements include dynamic fee handling, robust lifecycle management, and enhanced testing capabilities. These changes streamline transaction processing and error handling, ensuring reliable functionality across new features while improving the overall efficiency of the wallet system.

Changes

File Change Summary
btc/batcher.go, btc/cpfp.go, btc/rbf.go Introduced batching strategies with BatcherWallet interface, lifecycle methods, and enhanced transaction management.
btc/wallet.go Improved error handling, context management, and introduced functions for SACP validation, enhancing robustness.
.github/workflows/test.yml Updated GitHub Actions workflow with formatting corrections and added steps for Ginkgo testing.
btc/batcher_test.go, btc/wallet_test.go, btc/rbf_test.go, btc/store_test.go Implemented comprehensive tests for batch management, error handling, and transaction processing across multiple scenarios.
go.mod Updated Go toolchain version from go1.22.0 to go1.22.5 and adjusted dependencies accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant BatcherWallet
    participant Cache
    participant Indexer

    User->>BatcherWallet: Start()
    BatcherWallet->>Cache: Load pending requests
    BatcherWallet->>Indexer: Get fee rates
    BatcherWallet->>BatcherWallet: Create batch
    BatcherWallet->>Cache: Save batch
    User->>BatcherWallet: Send()
    BatcherWallet->>Indexer: Build transaction
    BatcherWallet->>Cache: Update request status
    User->>BatcherWallet: Stop()
    BatcherWallet->>Cache: Save state
Loading

Poem

In the realm of Bitcoin bright,
A BatcherWallet takes its flight. 🪙
With RBF and CPFP lore,
Transactions optimized, fees no more. 🚀
The code now dances, sleek and neat,
Our blockchain dream, nearly complete. 🌟


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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@yash1io
Copy link
Contributor Author

yash1io commented Jul 15, 2024

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Jul 15, 2024

Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 82b0025 and 3bbd67b.

Files selected for processing (8)
  • btc/batcher.go (1 hunks)
  • btc/batcher_test.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/cpfp_test.go (1 hunks)
  • btc/rbf.go (1 hunks)
  • btc/rbf_test.go (1 hunks)
  • btc/wallet.go (1 hunks)
  • go.mod (1 hunks)
Files skipped from review due to trivial changes (1)
  • go.mod
Additional context used
golangci-lint
btc/batcher_test.go

55-55: S1005: unnecessary assignment to the blank identifier

(gosimple)

btc/cpfp_test.go

160-160: ineffectual assignment to err

(ineffassign)

Additional comments not posted (43)
btc/rbf_test.go (2)

79-82: LGTM!

The test function is well-structured and covers the necessary steps to verify the functionality.


55-55: Remove unnecessary assignment to the blank identifier.

The assignment to the blank identifier is unnecessary and can be removed.

-	_, err := localnet.FundBitcoin(wallet.Address().EncodeAddress(), indexer)
+	err = localnet.FundBitcoin(wallet.Address().EncodeAddress(), indexer)

Likely invalid or redundant comment.

btc/batcher_test.go (16)

17-22: LGTM!

The function is well-structured and correctly initializes the test cache.


24-31: LGTM!

The function is well-structured and correctly reads a batch by request ID.


33-39: LGTM!

The function is well-structured and correctly reads a batch by transaction ID.


41-49: LGTM!

The function is well-structured and correctly reads pending batches.


50-62: LGTM!

The function is well-structured and correctly saves a batch.

Tools
golangci-lint

55-55: S1005: unnecessary assignment to the blank identifier

(gosimple)


64-73: LGTM!

The function is well-structured and correctly updates the statuses of batches.


76-82: LGTM!

The function is well-structured and correctly reads a request by ID.


83-91: LGTM!

The function is well-structured and correctly reads pending requests.


93-100: LGTM!

The function is well-structured and correctly saves a request.


102-113: LGTM!

The function is well-structured and correctly updates the fees of batches.


115-128: LGTM!

The function is well-structured and correctly reads the latest batch.


130-140: LGTM!

The function is well-structured and correctly reads requests by IDs.


142-164: LGTM!

The function is well-structured and correctly deletes pending batches.


166-174: LGTM!

The function is well-structured and correctly reads pending change UTXOs.


175-183: LGTM!

The function is well-structured and correctly reads pending funding UTXOs.


203-207: LGTM!

The function is well-structured and correctly initializes the mock fee estimator.

btc/cpfp_test.go (3)

82-95: LGTM!

The test function is well-structured and covers the necessary steps to verify the functionality.


97-142: LGTM!

The test function is well-structured and covers the necessary steps to verify the functionality.


39-39: Remove unnecessary assignment to the blank identifier.

The assignment to the blank identifier is unnecessary and can be removed.

-	_, err := localnet.FundBitcoin(wallet.Address().EncodeAddress(), indexer)
+	err = localnet.FundBitcoin(wallet.Address().EncodeAddress(), indexer)

Likely invalid or redundant comment.

btc/batcher.go (14)

1-17: Imports look good.

All necessary imports are present and there are no unused imports.


19-38: Constants and error variables look good.

All necessary constants and error variables are defined and there are no unnecessary ones.


40-76: Interfaces look good.

All necessary methods in the interfaces are defined and there are no unnecessary ones.


78-120: Structs look good.

All necessary fields in the structs are defined and there are no unnecessary ones.


122-143: Structs look good.

All necessary fields in the structs are defined and there are no unnecessary ones.


145-167: Function NewBatcherWallet looks good.

The function is correctly defined and handles errors properly.


169-188: Function defaultBatcherOptions looks good.

The function is correctly defined and returns default options.


190-215: Functions WithStrategy, WithPTI, and parseStrategy look good.

The functions are correctly defined and handle errors properly.


217-219: Method Address looks good.

The method is correctly defined and returns the address.


221-235: Method Send looks good.

The method is correctly defined and handles errors properly.


237-256: Method Status looks good.

The method is correctly defined and handles errors properly.


258-291: Methods Start, Stop, and Restart look good.

The methods are correctly defined and handle errors properly.


293-387: Methods run, runPTIBatcher, updateFeeRate, and createBatch look good.

The methods are correctly defined and handle errors properly.


389-462: Functions validateUpdate, selectFee, filterPendingBatches, getTransaction, and withContextTimeout look good.

The functions are correctly defined and handle errors properly.

btc/wallet.go (4)

Line range hint 1-14: Imports look good.

All necessary imports are present and there are no unused imports.


252-254: Update in buildTransaction function looks good.

The function is correctly defined and handles the new logic properly.


252-254: Update in buildTransaction function looks good.

The function is correctly defined and handles the new logic properly.


252-254: Update in buildTransaction function looks good.

The function is correctly defined and handles the new logic properly.

btc/rbf.go (4)

1-16: Imports look good.

All necessary imports are present and there are no unused imports.


18-67: Function createRBFBatch looks good.

The function is correctly defined and handles errors properly.


69-119: Function reSubmitRBFBatch looks good.

The function is correctly defined and handles errors properly.


121-510: Functions getConfirmedBatch, getMissingRequestIds, createNewRBFBatch, updateRBF, createRBFTx, getUtxosForFee, getUnconfirmedUtxos, and buildRBFTransaction look good.

The functions are correctly defined and handle errors properly.

btc/cpfp_test.go Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated
ErrBatchNotFound = errors.New("batch not found")
ErrBatcherStillRunning = errors.New("batcher is still running")
ErrBatcherNotRunning = errors.New("batcher is not running")
ErrBatchParametersNotMet = errors.New("batch parameters not met")
Copy link
Collaborator

Choose a reason for hiding this comment

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

The error is generic and does not specify what exactly went wrong. Maybe you can break the error into multiple errors and use them.

btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
btc/cpfp.go Show resolved Hide resolved
btc/cpfp.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 15dcd28 and af731fb.

Files selected for processing (4)
  • btc/batcher.go (1 hunks)
  • btc/batcher_test.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf_test.go (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • btc/batcher.go
  • btc/batcher_test.go
  • btc/rbf_test.go
Additional context used
golangci-lint
btc/cpfp.go

393-393: func reconstructCPFPBatches is unused

(unused)

Additional comments not posted (18)
btc/cpfp.go (18)

22-34: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		requests, err = w.cache.ReadPendingRequests(ctx)
-		return err
-	})
+	requests, err = w.cache.ReadPendingRequests(c)
+	if err != nil {
+		return err
+	}

58-66: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
+	if err != nil {
+		return err
+	}

74-79: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}

94-102: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}

122-127: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}

131-137: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		transaction, err = getTransaction(w.indexer, tx.TxHash().String())
-		return err
-	})
+	transaction, err = getTransaction(w.indexer, tx.TxHash().String())
+	if err != nil {
+		return err
+	}

155-160: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.SaveBatch(ctx, batch)
-	})
+	err = w.cache.SaveBatch(c, batch)
+	if err != nil {
+		return ErrSavingBatch
+	}

172-178: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
+	if err != nil {
+		return err
+	}

186-191: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}

200-206: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}

237-242: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}

245-250: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
-	})
+	err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
+	if err != nil {
+		return err
+	}

261-275: Fix the recursion depth check.

The recursion depth check might cause unintended behavior. Consider changing the condition to depth <= 0.

-	if depth < 0 {
+	if depth <= 0 {

283-289: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests)
-		return err
-	})
+	spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(c, w.indexer, spendRequests)
+	if err != nil {
+		return err
+	}

339-344: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey)
-	})
+	err = signSpendTx(c, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey)
+	if err != nil {
+		return nil, err
+	}

356-361: Avoid nested context timeouts.

The nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		sacpsIn, sacpOut, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer)
-		return err
-	})
+	sacpsIn, sacpOut, err = getTotalInAndOutSACPs(c, sacps, w.indexer)
+	if err != nil {
+		return nil, err
+	}

393-399: Implement the reconstructCPFPBatches function.

The function is currently a placeholder with a TODO comment. Implement the function to ensure proper functionality.

Do you want me to help implement this function or open a GitHub issue to track this task?

Tools
golangci-lint

393-393: func reconstructCPFPBatches is unused

(unused)


405-414: Fix the error handling.

The error handling might cause unintended behavior. Consider adding a check for ErrCPFPFeeUpdateParamsNotMet.

-		if err == ErrFeeUpdateNotNeeded && feeStats.FeeDelta > 0 {
+		if (err == ErrFeeUpdateNotNeeded || err == ErrCPFPFeeUpdateParamsNotMet) && feeStats.FeeDelta > 0 {

btc/cpfp.go Show resolved Hide resolved
btc/rbf.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between af731fb and 5bb2820.

Files selected for processing (1)
  • btc/batcher.go (1 hunks)
Additional context used
golangci-lint
btc/batcher.go

309-309: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (14)
btc/batcher.go (14)

201-220: LGTM!

The function provides sensible default options for the batcherWallet.


222-231: LGTM!

The function correctly handles strategy validation and configuration.


233-237: LGTM!

The function correctly sets the periodic time interval for the batcherWallet.


240-247: LGTM!

The function correctly validates the provided strategy.


249-251: LGTM!

The function correctly returns the address of the batcherWallet.


253-255: LGTM!

The function correctly delegates the generation of SACP to the underlying simple wallet.


257-259: LGTM!

The function correctly delegates the signing of SACP transactions to the underlying simple wallet.


313-326: LGTM!

The function correctly handles service stop and error conditions.


328-334: LGTM!

The function correctly handles service restart and error conditions.


336-349: LGTM!

The function correctly handles strategy selection and error conditions.


394-413: LGTM!

The function correctly handles fee rate updates and strategy selection.


415-429: LGTM!

The function correctly handles batch creation and strategy selection.


494-509: LGTM!

The function correctly handles fee rate validation and threshold checking.


351-392: Check the error return value of w.run.

The error return value of w.run is not checked, which may lead to unhandled errors.

  w.run(ctx)
+ if err := w.run(ctx); err != nil {
+   return err
+ }

Likely invalid or redundant comment.

btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Outdated
Comment on lines 301 to 311
// Start starts the batcher wallet service
func (w *batcherWallet) Start(ctx context.Context) error {
if w.quit != nil {
return ErrBatcherStillRunning
}
w.quit = make(chan struct{})

w.logger.Info("starting batcher wallet")
w.run(ctx)
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Check the error return value of w.run.

The error return value of w.run is not checked, which may lead to unhandled errors.

  w.run(ctx)
+ if err := w.run(ctx); err != nil {
+   return err
+ }
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
// Start starts the batcher wallet service
func (w *batcherWallet) Start(ctx context.Context) error {
if w.quit != nil {
return ErrBatcherStillRunning
}
w.quit = make(chan struct{})
w.logger.Info("starting batcher wallet")
w.run(ctx)
return nil
}
// Start starts the batcher wallet service
func (w *batcherWallet) Start(ctx context.Context) error {
if w.quit != nil {
return ErrBatcherStillRunning
}
w.quit = make(chan struct{})
w.logger.Info("starting batcher wallet")
if err := w.run(ctx); err != nil {
return err
}
return nil
}
Tools
golangci-lint

309-309: Error return value of w.run is not checked

(errcheck)

btc/batcher.go Outdated
Comment on lines 261 to 278
// Send creates a batch request , saves it in the cache and returns a tracking id
func (w *batcherWallet) Send(ctx context.Context, sends []SendRequest, spends []SpendRequest, sacps [][]byte) (string, error) {
if err := w.validateBatchRequest(ctx, w.opts.Strategy, spends, sends, sacps); err != nil {
return "", err
}

// generate random id
id := chainhash.HashH([]byte(fmt.Sprintf("%v", time.Now().UnixNano()))).String()

req := BatcherRequest{
ID: id,
Spends: spends,
Sends: sends,
SACPs: sacps,
Status: false,
}
return id, w.cache.SaveRequest(ctx, id, req)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Add logging for successful request saving.

Consider adding a log statement after successfully saving the batch request to the cache.

  return id, w.cache.SaveRequest(ctx, id, req)
+ if err == nil {
+   w.logger.Info("Batch request saved successfully", zap.String("id", id))
+ }

Committable suggestion was skipped due to low confidence.

btc/batcher.go Outdated Show resolved Hide resolved
btc/batcher.go Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 5bb2820 and 81dd489.

Files selected for processing (2)
  • btc/rbf.go (1 hunks)
  • btc/wallet_test.go (42 hunks)
Files skipped from review as they are similar to previous changes (2)
  • btc/rbf.go
  • btc/wallet_test.go

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 81dd489 and 00fa2c0.

Files selected for processing (4)
  • .github/workflows/test.yml (1 hunks)
  • btc/batcher.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • btc/rbf.go
Additional context used
golangci-lint
btc/cpfp.go

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go

309-309: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (15)
.github/workflows/test.yml (4)

10-10: LGTM!

The change to set up Go using actions/setup-go@v4 is standard and correct.


12-12: LGTM!

Specifying the Go version as ">=1.19.0" ensures compatibility with newer features.


18-18: LGTM!

Installing Ginkgo using go install is necessary for running the tests.


20-24: LGTM!

The updated test command includes Ginkgo commands for specific test modes, enhancing the testing process.

btc/cpfp.go (4)

389-400: LGTM!

The function getFeeStats is well-implemented.


22-149: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to createCPFPBatch are correctly implemented.


243-373: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to buildCPFPTx are correctly implemented.


153-241: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to updateCPFP are correctly implemented.

Verification successful

Function usage verified and correctly implemented.

The function updateCPFP is called within a switch statement in btc/batcher.go, ensuring it is invoked based on the strategy option. The context and fee rate are appropriately set up before the call.

  • btc/batcher.go: Verified correct implementation of updateCPFP.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `updateCPFP` in the codebase.

# Test: Search for the function usage. Expect: Only occurances of the new function.
rg --type go -A 5 $'updateCPFP'

Length of output: 680


Script:

#!/bin/bash
# Description: Gather more context around the call to `updateCPFP` in `btc/batcher.go`.

# Test: Search for the function usage and get more lines of context.
rg --type go -A 20 -B 10 $'updateCPFP' btc/batcher.go

Length of output: 741

btc/batcher.go (7)

431-491: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to validateBatchRequest are correctly implemented.

Verification successful

Function usage verified in the codebase.

The function validateBatchRequest is only used within the btc/batcher.go file, and its usage appears to be correctly implemented.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `validateBatchRequest` in the codebase.

# Test: Search for the function usage. Expect: Only occurances of the new function.
rg --type go -A 5 $'validateBatchRequest'

Length of output: 740


415-429: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to createBatch are correctly implemented.


341-349: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to run are correctly implemented.

Verification successful

Verified: Function usage is correct.

The run function is only called within btc/batcher.go, ensuring its usage is consistent and contained within the same file.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `run` in the codebase.

# Test: Search for the function usage. Expect: Only occurances of the new function.
rg --type go -A 5 $'run'

Length of output: 2636


395-413: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to updateFeeRate are correctly implemented.

Verification successful

Function usage verified and correct.

The function updateFeeRate is only used within the same file (btc/batcher.go) and handles errors appropriately. No further issues found.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `updateFeeRate` in the codebase.

# Test: Search for the function usage. Expect: Only occurances of the new function.
rg --type go -A 5 $'updateFeeRate'

Length of output: 718


356-392: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to runPTIBatcher are correctly implemented.

Verification successful

The function runPTIBatcher is used correctly within the codebase.

The function runPTIBatcher is defined and called within the btc/batcher.go file. The usage appears to be in the correct context.

  • File: btc/batcher.go
    • Line: w.runPTIBatcher(ctx)
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `runPTIBatcher` in the codebase.

# Test: Search for the function usage. Expect: Only occurances of the new function.
rg --type go -A 5 $'runPTIBatcher'

Length of output: 452


169-199: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to NewBatcherWallet are correctly implemented.


261-278: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to Send are correctly implemented.

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

Outside diff range, codebase verification and nitpick comments (4)
btc/cpfp.go (4)

148-149: Add logging for successful submission of CPFP batch.

Consider adding a log statement after successfully submitting the CPFP batch.

+	w.logger.Info("submitted CPFP batch", zap.String("txid", tx.TxHash().String()))

238-239: Add logging for successful submission of CPFP transaction.

Consider adding a log statement after successfully submitting the CPFP transaction.

+	w.logger.Info("submitted CPFP transaction", zap.String("txid", tx.TxHash().String()))

313-321: Add logging for buffer fee calculation.

Consider adding a log statement for the buffer fee calculation to help with debugging.

+	w.logger.Debug("buffer fee calculated", zap.Int("bufferFee", bufferFee))

358-370: Add logging for rebuilding CPFP transaction.

Consider adding a log statement for rebuilding the CPFP transaction to help with debugging.

+	w.logger.Info(
+		"rebuilding CPFP transaction",
+		zap.Int("depth", depth),
+		zap.Int("fee", fee),
+		zap.Int("feeOverhead", feeOverhead),
+		zap.Int("feeBuffer", bufferFee),
+		zap.Int("required", newFeeEstimate),
+		zap.Int("coverUtxos", len(utxos)),
+		zap.Int("TxIns", len(tx.TxIn)),
+		zap.Int("TxOuts", len(tx.TxOut)),
+		zap.String("TxData", hex.EncodeToString(txBytes)),
+	)
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 00fa2c0 and e5bf067.

Files selected for processing (4)
  • .github/workflows/test.yml (1 hunks)
  • btc/batcher.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf.go (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/test.yml
  • btc/rbf.go
Additional context used
golangci-lint
btc/cpfp.go

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go

309-309: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (11)
btc/cpfp.go (4)

389-399: LGTM!

The function correctly generates fee stats and handles errors.


403-423: LGTM!

The function correctly calculates fee stats.


425-437: LGTM!

The function correctly removes double spends from UTXOs.


Line range hint 570-592: LGTM!

The function correctly calculates the total input and output amounts for SACPs.

Tools
golangci-lint

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go (7)

169-199: LGTM!

The function correctly initializes a new batcher wallet and validates the provided options.


201-219: LGTM!

The function correctly returns the default options for a batcher wallet.


222-230: LGTM!

The function correctly sets the strategy for a batcher wallet.


233-237: LGTM!

The function correctly sets the periodic time interval for a batcher wallet.


240-247: LGTM!

The function correctly validates the provided strategy.


249-251: LGTM!

The function correctly returns the address of the batcher wallet.


253-255: LGTM!

The function correctly generates a SACP for a spend request.

btc/cpfp.go Outdated
Comment on lines 141 to 143
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.SaveBatch(ctx, batch)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.SaveBatch(ctx, batch)
-	})
+	err = w.cache.SaveBatch(c, batch)
+	if err != nil {
+		return ErrSavingBatch
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.SaveBatch(ctx, batch)
})
err = w.cache.SaveBatch(c, batch)
if err != nil {
return ErrSavingBatch
}

btc/cpfp.go Outdated
Comment on lines 82 to 85
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
utxos, err = w.indexer.GetUTXOs(c, w.address)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 231 to 233
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
-	})
+	err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
})
err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
if err != nil {
return err
}

Comment on lines +36 to +39
// Return error if no requests found
if len(requests) == 0 {
return ErrBatchParametersNotMet
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Improve error message for missing requests.

The error message ErrBatchParametersNotMet is not descriptive enough. Consider providing a more specific error message.

-	return ErrBatchParametersNotMet
+	return errors.New("no pending requests found")
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
// Return error if no requests found
if len(requests) == 0 {
return ErrBatchParametersNotMet
}
// Return error if no requests found
if len(requests) == 0 {
return errors.New("no pending requests found")
}

btc/cpfp.go Outdated
Comment on lines 108 to 110
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
err = w.indexer.SubmitTx(c, tx)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 186 to 189
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
utxos, err = w.indexer.GetUTXOs(c, w.address)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 172 to 174
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 60 to 62
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 117 to 119
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
transaction, err = getTransaction(w.indexer, tx.TxHash().String())
return err
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		transaction, err = getTransaction(w.indexer, tx.TxHash().String())
-		return err
-	})
+	transaction, err = getTransaction(w.indexer, tx.TxHash().String())
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
transaction, err = getTransaction(w.indexer, tx.TxHash().String())
return err
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
transaction, err = getTransaction(w.indexer, tx.TxHash().String())
if err != nil {
return err
}
return nil
})

btc/cpfp.go Outdated
Comment on lines 28 to 31
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
requests, err = w.cache.ReadPendingRequests(ctx)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
-		requests, err = w.cache.ReadPendingRequests(ctx)
-		return err
-	})
+	requests, err = w.cache.ReadPendingRequests(c)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
requests, err = w.cache.ReadPendingRequests(ctx)
return err
})
requests, err = w.cache.ReadPendingRequests(c)
if err != nil {
return err
}

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e5bf067 and 5c86242.

Files selected for processing (1)
  • btc/rbf.go (1 hunks)

btc/rbf.go Outdated
Comment on lines 29 to 31
if err != nil {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to read pending requests: %w", err)
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 {
return err
}
if err != nil {
return fmt.Errorf("failed to read pending requests: %w", err)
}

btc/rbf.go Outdated
Comment on lines 380 to 382
sacpsInAmount, sacpsOutAmount, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get total in and out SACPs: %w", err)
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
sacpsInAmount, sacpsOutAmount, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer)
return err
})
sacpsInAmount, sacpsOutAmount, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer)
return fmt.Errorf("failed to get total in and out SACPs: %w", err)

btc/rbf.go Outdated
Comment on lines 131 to 133
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, RBF)
return err
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to read pending batches: %w", err)
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
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, RBF)
return err
err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, RBF)
return fmt.Errorf("failed to read pending batches: %w", err)

btc/rbf.go Outdated
Comment on lines 480 to 481
if txBytes, err = GetTxRawBytes(tx); err != nil {
return nil, nil, nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get raw transaction bytes: %w", err)

Committable suggestion was skipped due to low confidence.

btc/rbf.go Outdated
Comment on lines 427 to 429
err = signSendTx(tx, utxos, signIdx+len(spendUTXOs), w.address, w.privateKey)
if err != nil {
return nil, nil, nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return nil, nil, nil, err
+ return nil, nil, nil, fmt.Errorf("failed to sign send transaction: %w", err)
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
err = signSendTx(tx, utxos, signIdx+len(spendUTXOs), w.address, w.privateKey)
if err != nil {
return nil, nil, nil, err
err = signSendTx(tx, utxos, signIdx+len(spendUTXOs), w.address, w.privateKey)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to sign send transaction: %w", err)

btc/rbf.go Outdated
Comment on lines 289 to 291
latestBatch, err = w.cache.ReadLatestBatch(ctx, RBF)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to read the latest RBF batch: %w", err)
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
latestBatch, err = w.cache.ReadLatestBatch(ctx, RBF)
return err
})
latestBatch, err = w.cache.ReadLatestBatch(ctx, RBF)
return fmt.Errorf("failed to read the latest RBF batch: %w", err)

Comment on lines +471 to +473
utxos, _, err = w.getUtxosWithFee(ctx, totalOut+int64(newFeeEstimate)-totalIn, int64(feeRate), avoidUtxos)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get UTXOs with fee: %w", err)
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
utxos, _, err = w.getUtxosWithFee(ctx, totalOut+int64(newFeeEstimate)-totalIn, int64(feeRate), avoidUtxos)
return err
})
utxos, _, err = w.getUtxosWithFee(ctx, totalOut+int64(newFeeEstimate)-totalIn, int64(feeRate), avoidUtxos)
return fmt.Errorf("failed to get UTXOs with fee: %w", err)

Comment on lines +145 to +147
tx, err = w.indexer.GetTx(ctx, batch.Tx.TxID)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get transaction: %w", err)
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
tx, err = w.indexer.GetTx(ctx, batch.Tx.TxID)
return err
})
tx, err = w.indexer.GetTx(ctx, batch.Tx.TxID)
return fmt.Errorf("failed to get transaction: %w", err)

btc/rbf.go Outdated
Comment on lines 222 to 236
tx, fundingUtxos, selfUtxos, err = w.createRBFTx(
c,
nil,
spendRequests,
sendRequests,
sacps,
nil,
avoidUtxos,
0, // will be calculated in the function
requiredFeeRate,
false,
2,
)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to create RBF transaction: %w", err)
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
tx, fundingUtxos, selfUtxos, err = w.createRBFTx(
c,
nil,
spendRequests,
sendRequests,
sacps,
nil,
avoidUtxos,
0, // will be calculated in the function
requiredFeeRate,
false,
2,
)
return err
})
tx, fundingUtxos, selfUtxos, err = w.createRBFTx(
c,
nil,
spendRequests,
sendRequests,
sacps,
nil,
avoidUtxos,
0, // will be calculated in the function
requiredFeeRate,
false,
2,
)
return fmt.Errorf("failed to create RBF transaction: %w", err)

btc/rbf.go Outdated
Comment on lines 357 to 371
if depth < 0 {
w.logger.Debug(
ErrBuildRBFDepthExceeded.Error(),
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Any("avoidUtxos", avoidUtxos),
zap.Uint("fee", fee),
zap.Int("requiredFeeRate", feeRate),
zap.Bool("checkValidity", checkValidity),
zap.Int("depth", depth),
)
return nil, nil, nil, ErrBuildRBFDepthExceeded
Copy link
Contributor

Choose a reason for hiding this comment

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

Improve logging for recursion depth exceeded.

The logging should include the error context for better debugging.

- w.logger.Debug(
-   ErrBuildRBFDepthExceeded.Error(),
+ w.logger.Debug("recursion depth exceeded",
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 depth < 0 {
w.logger.Debug(
ErrBuildRBFDepthExceeded.Error(),
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Any("avoidUtxos", avoidUtxos),
zap.Uint("fee", fee),
zap.Int("requiredFeeRate", feeRate),
zap.Bool("checkValidity", checkValidity),
zap.Int("depth", depth),
)
return nil, nil, nil, ErrBuildRBFDepthExceeded
if depth < 0 {
w.logger.Debug("recursion depth exceeded",
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Any("avoidUtxos", avoidUtxos),
zap.Uint("fee", fee),
zap.Int("requiredFeeRate", feeRate),
zap.Bool("checkValidity", checkValidity),
zap.Int("depth", depth),
)
return nil, nil, nil, ErrBuildRBFDepthExceeded

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 5c86242 and b600524.

Files selected for processing (4)
  • btc/batcher.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf.go (1 hunks)
  • btc/wallet.go (15 hunks)
Files skipped from review as they are similar to previous changes (1)
  • btc/rbf.go
Additional context used
golangci-lint
btc/cpfp.go

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go

298-298: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (14)
btc/batcher.go (6)

484-497: LGTM!

The logic for validating the fee rate delta is comprehensive and correct.


398-403: LGTM!

The function correctly calculates the fee used in the given SACPs.


Line range hint 622-634:
LGTM!

The function correctly signs the spend transaction with the given inputs and script.

Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)


Line range hint 733-813:
LGTM!

The function correctly validates spend, send, and SACP requests.

Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)


Line range hint 825-838:
LGTM!

The function correctly counts the number of Segwit and Schnorr signatures in the spend requests.

Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)


Line range hint 853-864:
LGTM!

The function correctly validates the SACP transaction.

Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)

btc/wallet.go (8)

206-211: LGTM!

The function correctly validates requests and estimates fees for sending funds.


249-249: LGTM!

The function correctly validates requests and generates a SACP transaction.


Line range hint 279-299:
LGTM!

The function correctly generates a SACP transaction with the given details.


Line range hint 372-396:
LGTM!

The function correctly calculates the total input and output amounts for the given SACPs.


398-403: LGTM!

The function correctly calculates the fee used in the given SACPs.


Line range hint 417-431:
LGTM!

The function correctly fetches the previous outputs and txouts for the given SACPs.


Line range hint 622-634:
LGTM!

The function correctly signs the spend transaction with the given inputs and script.


Line range hint 733-813:
LGTM!

The function correctly validates spend, send, and SACP requests.

Comment on lines +186 to +189
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
utxos, err = w.indexer.GetUTXOs(ctx, w.address)
return err
})
utxos, err = w.indexer.GetUTXOs(c, w.address)
if err != nil {
return err
}

Comment on lines +108 to +110
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
err = w.indexer.SubmitTx(c, tx)
if err != nil {
return err
}

func (w *batcherWallet) buildCPFPTx(c context.Context, utxos []UTXO, spendRequests []SpendRequest, sendRequests []SendRequest, sacps [][]byte, sequencesMap map[string]uint32, fee, feeOverhead, feeRate int, depth int) (*wire.MsgTx, error) {
// Check recursion depth to prevent infinite loops
// 1 depth is optimal for most cases
if depth < 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix the recursion depth check.

The recursion depth check might cause unintended behavior. Consider changing the condition to depth <= 0.

-	if depth < 0 {
+	if depth <= 0 {
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 depth < 0 {
if depth <= 0 {

btc/cpfp.go Outdated
Comment on lines 172 to 174
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
})
err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 232 to 233
return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
-	})
+	err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
+	if err != nil {
+		return err
+	}
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
return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
})
err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 158 to 161
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
return err
})
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
return err
})
batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
if err != nil {
return err
}

btc/batcher.go Outdated
w.quit = make(chan struct{})

w.logger.Info("starting batcher wallet")
w.run(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

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

Check the error return value of w.run.

The error return value of w.run is not checked, which may lead to unhandled errors.

-	w.run(ctx)
+	if err := w.run(ctx); err != nil {
+		return err
+	}
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
w.run(ctx)
w.run(ctx)
if err := w.run(ctx); err != nil {
return err
}
Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)

Comment on lines +448 to +461
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
spendsUtxos, _, spendsAmount, err = getUTXOsForSpendRequest(ctx, w.indexer, spends)
return err
})
if err != nil {
return err
}

var sacpsIn int64
var sacpOut int64
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
sacpsIn, sacpOut, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Define timeout value as a global constant.

The timeout value of 5s is used consistently across all timeout contexts. Defining this value as a global constant will improve code maintainability and readability.

-	err = withContextTimeout(ctx, 5*time.Second, func(ctx context.Context) error {
+	err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
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
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
spendsUtxos, _, spendsAmount, err = getUTXOsForSpendRequest(ctx, w.indexer, spends)
return err
})
if err != nil {
return err
}
var sacpsIn int64
var sacpOut int64
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
sacpsIn, sacpOut, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
spendsUtxos, _, spendsAmount, err = getUTXOsForSpendRequest(ctx, w.indexer, spends)
return err
})
if err != nil {
return err
}
var sacpsIn int64
var sacpOut int64
err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error {
sacpsIn, sacpOut, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})

btc/batcher.go Outdated
Comment on lines 357 to 375
if err := w.createBatch(); err != nil {
if !errors.Is(err, ErrBatchParametersNotMet) {
w.logger.Error("failed to create batch", zap.Error(err))
} else {
w.logger.Info("waiting for new batch")
}

if err := w.updateFeeRate(); err != nil {
if !errors.Is(err, ErrFeeUpdateNotNeeded) {
w.logger.Error("failed to update fee rate", zap.Error(err))
} else {
w.logger.Info("fee update skipped")
}
} else {
w.logger.Info("batch fee updated", zap.String("strategy", string(w.opts.Strategy)))
}
} else {
w.logger.Info("new batch created", zap.String("strategy", string(w.opts.Strategy)))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid potential data corruption when calling updateFeeRate.

createBatch might fail for different reasons. Calling updateFeeRate on error might lead to corruption of data.

-	if err := w.createBatch(); err != nil {
-		if !errors.Is(err, ErrBatchParametersNotMet) {
-			w.logger.Error("failed to create batch", zap.Error(err))
-		} else {
-			w.logger.Info("waiting for new batch")
-		}
-		if err := w.updateFeeRate(); err != nil {
-			if !errors.Is(err, ErrFeeUpdateNotNeeded) {
-				w.logger.Error("failed to update fee rate", zap.Error(err))
-			} else {
-				w.logger.Info("fee update skipped")
-			}
-		} else {
-			w.logger.Info("batch fee updated", zap.String("strategy", string(w.opts.Strategy)))
-		}
-	} else {
-		w.logger.Info("new batch created", zap.String("strategy", string(w.opts.Strategy)))
-	}
+	err := w.createBatch()
+	if err != nil && !errors.Is(err, ErrBatchParametersNotMet) {
+		w.logger.Error("failed to create batch", zap.Error(err))
+		return
+	}
+	if err == nil {
+		w.logger.Info("new batch created", zap.String("strategy", string(w.opts.Strategy)))
+		return
+	}
+	w.logger.Info("waiting for new batch")
+	if err := w.updateFeeRate(); err != nil {
+		if !errors.Is(err, ErrFeeUpdateNotNeeded) {
+			w.logger.Error("failed to update fee rate", zap.Error(err))
+		} else {
+			w.logger.Info("fee update skipped")
+		}
+	} else {
+		w.logger.Info("batch fee updated", zap.String("strategy", string(w.opts.Strategy)))
+	}
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 := w.createBatch(); err != nil {
if !errors.Is(err, ErrBatchParametersNotMet) {
w.logger.Error("failed to create batch", zap.Error(err))
} else {
w.logger.Info("waiting for new batch")
}
if err := w.updateFeeRate(); err != nil {
if !errors.Is(err, ErrFeeUpdateNotNeeded) {
w.logger.Error("failed to update fee rate", zap.Error(err))
} else {
w.logger.Info("fee update skipped")
}
} else {
w.logger.Info("batch fee updated", zap.String("strategy", string(w.opts.Strategy)))
}
} else {
w.logger.Info("new batch created", zap.String("strategy", string(w.opts.Strategy)))
}
err := w.createBatch()
if err != nil && !errors.Is(err, ErrBatchParametersNotMet) {
w.logger.Error("failed to create batch", zap.Error(err))
return
}
if err == nil {
w.logger.Info("new batch created", zap.String("strategy", string(w.opts.Strategy)))
return
}
w.logger.Info("waiting for new batch")
if err := w.updateFeeRate(); err != nil {
if !errors.Is(err, ErrFeeUpdateNotNeeded)) {
w.logger.Error("failed to update fee rate", zap.Error(err))
} else {
w.logger.Info("fee update skipped")
}
} else {
w.logger.Info("batch fee updated", zap.String("strategy", string(w.opts.Strategy)))
}

Comment on lines +166 to +170
func NewBatcherWallet(privateKey *secp256k1.PrivateKey, indexer IndexerClient, feeEstimator FeeEstimator, chainParams *chaincfg.Params, cache Cache, logger *zap.Logger, opts ...func(*batcherWallet) error) (BatcherWallet, error) {
address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
if err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Handle potential nil pointer dereference.

If PublicKeyAddress returns an error, address will be nil, which might cause a nil pointer dereference later.

-	address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
+	address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
+	if err != nil {
+		return nil, err
+	}
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 NewBatcherWallet(privateKey *secp256k1.PrivateKey, indexer IndexerClient, feeEstimator FeeEstimator, chainParams *chaincfg.Params, cache Cache, logger *zap.Logger, opts ...func(*batcherWallet) error) (BatcherWallet, error) {
address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
if err != nil {
return nil, err
}
func NewBatcherWallet(privateKey *secp256k1.PrivateKey, indexer IndexerClient, feeEstimator FeeEstimator, chainParams *chaincfg.Params, cache Cache, logger *zap.Logger, opts ...func(*batcherWallet) error) (BatcherWallet, error) {
address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
if err != nil {
return nil, err
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b600524 and b316bc8.

Files selected for processing (3)
  • btc/batcher.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • btc/rbf.go
Additional context used
golangci-lint
btc/cpfp.go

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go

298-298: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (23)
btc/cpfp.go (18)

28-31: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		requests, err = w.cache.ReadPendingRequests(ctx)
-		return err
-	})
+	requests, err = w.cache.ReadPendingRequests(c)
+	if err != nil {
+		return err
+	}

37-39: Improve error message for missing requests.

The error message ErrBatchParametersNotMet is not descriptive enough. Consider providing a more specific error message.

-	return ErrBatchParametersNotMet
+	return errors.New("no pending requests found")

46-49: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
+	if err != nil {
+		return err
+	}

60-62: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}

82-85: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}

108-110: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}

117-120: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		transaction, err = w.indexer.GetTx(ctx, tx.TxHash().String())
-		return err
-	})
+	transaction, err = w.indexer.GetTx(c, tx.TxHash().String())
+	if err != nil {
+		return err
+	}

141-143: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.SaveBatch(ctx, batch)
-	})
+	err = w.cache.SaveBatch(c, batch)
+	if err != nil {
+		return ErrSavingBatch
+	}

158-161: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c, w.opts.Strategy)
+	if err != nil {
+		return err
+	}

172-174: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP)
-	})
+	err = w.cache.ConfirmBatchStatuses(c, confirmedTxs, false, CPFP)
+	if err != nil {
+		return err
+	}

186-189: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}

223-225: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}

232-233: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate))
-	})
+	err = w.cache.UpdateBatchFees(c, pendingTxs, int64(requiredFeeRate))
+	if err != nil {
+		return err
+	}

247-247: Fix the recursion depth check.

The recursion depth check might cause unintended behavior. Consider changing the condition to depth <= 0.

-	if depth < 0 {
+	if depth <= 0 {

269-272: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests)
-		return err
-	})
+	spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(c, w.indexer, spendRequests)
+	if err != nil {
+		return nil, err
+	}

325-327: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey)
-	})
+	err = signSpendTx(c, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey)
+	if err != nil {
+		return err
+	}

344-347: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
-		return err
-	})
+	sacpsInAmount, sacpOutAmount, err = getSACPAmounts(c, sacps, w.indexer)
+	if err != nil {
+		return nil, err
+	}

379-385: Implement the reconstructCPFPBatches function.

The function is currently a placeholder with a TODO comment. Implement the function to ensure proper functionality.

Do you want me to help implement this function or open a GitHub issue to track this task?

Tools
golangci-lint

379-379: func reconstructCPFPBatches is unused

(unused)

btc/batcher.go (5)

167-170: Handle potential nil pointer dereference.

If PublicKeyAddress returns an error, address will be nil, which might cause a nil pointer dereference later.

-	address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
+	address, err := PublicKeyAddress(chainParams, waddrmgr.WitnessPubKey, privateKey.PubKey())
+	if err != nil {
+		return nil, err
+	}

266-267: Add logging for successful request saving.

Consider adding a log statement after successfully saving the batch request to the cache.

  return id, w.cache.SaveRequest(ctx, id, req)
+ if err == nil {
+   w.logger.Info("Batch request saved successfully", zap.String("id", id))
+ }

287-288: Add logging for successful status retrieval.

Consider adding a log statement after successfully retrieving the transaction status.

  return tx, true, nil
+ w.logger.Info("Transaction status retrieved successfully", zap.String("id", id))

298-298: Check the error return value of w.run.

The error return value of w.run is not checked, which may lead to unhandled errors.

-	w.run(ctx)
+	if err := w.run(ctx); err != nil {
+		return err
+	}
Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)


357-375: Avoid potential data corruption when calling updateFeeRate.

createBatch might fail for different reasons. Calling updateFeeRate on error might lead to corruption of data.

-	if err := w.createBatch(); err != nil {
-		if !errors.Is(err, ErrBatchParametersNotMet) {
-			w.logger.Error("failed to create batch", zap.Error(err))
-		} else {
-			w.logger.Info("waiting

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Outside diff range, codebase verification and nitpick comments (1)
btc/batcher.go (1)

3-19: Avoid unused imports.

Ensure all imported packages are used in the code to avoid unnecessary dependencies.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b316bc8 and 12456af.

Files selected for processing (1)
  • btc/batcher.go (1 hunks)
Additional context used
golangci-lint
btc/batcher.go

298-298: Error return value of w.run is not checked

(errcheck)

Additional comments not posted (32)
btc/batcher.go (32)

21-24: Define timeout value as a global constant.

The timeout value of 5s is used consistently across all timeout contexts. Defining this value as a global constant will improve code maintainability and readability.


53-56: Ensure consistency in interface definitions.

The BatcherWallet interface embeds Wallet and Lifecycle. Ensure that all methods are consistently defined and documented.


58-64: Ensure consistency in interface definitions.

The Lifecycle interface defines methods for starting, stopping, and restarting the wallet service. Ensure that all methods are consistently defined and documented.


66-97: Ensure consistency in interface definitions.

The Cache interface defines methods for managing the state of the BatcherWallet. Ensure that all methods are consistently defined and documented.


99-107: Ensure consistency in struct definitions.

The BatcherRequest struct is well-defined with necessary fields. Ensure that all fields are consistently defined and documented.


109-114: Ensure consistency in struct definitions.

The BatcherOptions struct is well-defined with necessary fields. Ensure that all fields are consistently defined and documented.


133-154: Ensure consistency in struct definitions.

The batcherWallet struct is well-defined with necessary fields. Ensure that all fields are consistently defined and documented.


166-196: Handle potential nil pointer dereference.

If PublicKeyAddress returns an error, address will be nil, which might cause a nil pointer dereference later.

+	if err != nil {
+		return nil, err
+	}

198-209: Ensure consistency in default options.

The defaultBatcherOptions function returns default options for the BatcherWallet. Ensure that all default values are consistently defined and documented.


211-219: Ensure consistency in option parsing.

The WithStrategy function parses the strategy option for the BatcherWallet. Ensure that all options are consistently defined and documented.


222-227: Ensure consistency in option parsing.

The WithPTI function parses the PTI option for the BatcherWallet. Ensure that all options are consistently defined and documented.


229-236: Ensure consistency in strategy parsing.

The parseStrategy function parses the strategy for the BatcherWallet. Ensure that all strategies are consistently defined and documented.


238-240: Ensure consistency in method definitions.

The Address method returns the wallet address. Ensure that all methods are consistently defined and documented.


242-244: Ensure consistency in method definitions.

The GenerateSACP method generates a SACP for the wallet. Ensure that all methods are consistently defined and documented.


246-248: Ensure consistency in method definitions.

The SignSACPTx method signs a SACP transaction for the wallet. Ensure that all methods are consistently defined and documented.


250-267: Add logging for successful request saving.

Consider adding a log statement after successfully saving the batch request to the cache.

+	if err == nil {
+		w.logger.Info("Batch request saved successfully", zap.String("id", id))
+	}

269-288: Add logging for successful status retrieval.

Consider adding a log statement after successfully retrieving the transaction status.

+	w.logger.Info("Transaction status retrieved successfully", zap.String("id", id))

290-300: Check the error return value of w.run.

The error return value of w.run is not checked, which may lead to unhandled errors.

-	w.run(ctx)
+	if err := w.run(ctx); err != nil {
+		return err
+	}
Tools
golangci-lint

298-298: Error return value of w.run is not checked

(errcheck)


302-318: Ensure consistency in lifecycle methods.

The Stop method gracefully stops the batcher wallet service. Ensure that all lifecycle methods are consistently defined and documented.


320-326: Ensure consistency in lifecycle methods.

The Restart method restarts the batcher wallet service. Ensure that all lifecycle methods are consistently defined and documented.


328-341: Ensure consistency in batching methods.

The run method starts the batcher based on the strategy. Ensure that all batching methods are consistently defined and documented.


343-364: Ensure consistency in batching methods.

The runPTIBatcher method triggers the batching process at regular intervals. Ensure that all batching methods are consistently defined and documented.


366-391: Avoid potential data corruption when calling updateFeeRate.

createBatch might fail for different reasons. Calling updateFeeRate on error might lead to corruption of data.

+		return
+	}

393-412: Ensure consistency in fee update methods.

The updateFeeRate method updates the fee rate based on the strategy. Ensure that all fee update methods are consistently defined and documented.


414-428: Ensure consistency in batch creation methods.

The createBatch method creates a batch based on the strategy. Ensure that all batch creation methods are consistently defined and documented.


430-491: Add logging for successful batch request validation.

Consider adding a log statement after successfully validating the batch request.

+	w.logger.Info("Batch request validated successfully")

493-508: Ensure consistency in fee validation methods.

The validateUpdate method verifies if the fee rate delta is within the threshold. Ensure that all fee validation methods are consistently defined and documented.


510-522: Ensure consistency in fee selection methods.

The selectFee method selects the fee rate based on the fee level option. Ensure that all fee selection methods are consistently defined and documented.


524-543: Ensure consistency in batch filtering methods.

The filterPendingBatches method filters pending batches based on their status. Ensure that all batch filtering methods are consistently defined and documented.


545-549: Ensure consistency in context timeout methods.

The withContextTimeout method applies a timeout to a context. Ensure that all context timeout methods are consistently defined and documented.


551-566: Ensure consistency in request unpacking methods.

The unpackBatcherRequests method unpacks batcher requests into spend requests, send requests, and SACPs. Ensure that all request unpacking methods are consistently defined and documented.


26-47: Ensure consistency in error definitions.

The error variables and functions are well-defined. Ensure that all error definitions are consistently defined and documented.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 12456af and a4c663b.

Files selected for processing (1)
  • btc/batcher.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • btc/batcher.go

@Revantark Revantark changed the title Feat/batcher feat: Add RBF and CPFP Batcher wallets Jul 24, 2024
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: 42

Outside diff range, codebase verification and nitpick comments (2)
btc/wallet_test.go (1)

1207-1207: Update the function parameter documentation.

The function generateSACP now uses faucet instead of wallet as the first parameter. Ensure the function documentation reflects this change.

- // generateSACP generates an SACP transaction with single input and output.
- // It uses wallet's address as recipient and a script as the sender.
+ // generateSACP generates an SACP transaction with single input and output.
+ // It uses faucet's address as recipient and a script as the sender.
btc/wallet.go (1)

279-279: Function signature mismatch found in generateSACP usage.

The generateSACP function has been updated to include a context parameter, but the following locations still use the old signature:

  • btc/wallet_test.go:

    • Line 1: sacp, err := generateSACP(faucet, chainParams, privateKey, wallet.Address(), 10000, 1000)
    • Line 2: sacp1, err := generateSACP(bobWallet, chainParams, bobPk, wallet.Address(), 5000, 0)
    • Line 3: sacp2, err := generateSACP(faucet, chainParams, privateKey, bobWallet.Address(), 10000, 1000)
    • Line 4: sacp1, err := generateSACP(bobWallet, chainParams, bobPk, wallet.Address(), 10000, 100)
    • Line 5: sacp, err := generateSACP(faucet, chainParams, privateKey, randAddr, 10000, 100)
    • Line 6: sacp1, err := generateSACP(faucet, chainParams, privateKey, randAddr, sendAmount, 0)
    • Line 7: sacp2, err := generateSACP(faucet, chainParams, privateKey, bobAddr, sendAmount, 1000)
    • Line 8: sacp, err := generateSACP(faucet, chainParams, privateKey, wallet.Address(), 1000, 1)
  • btc/rbf_test.go:

    • Line 1: sacp, err = generateSACP(faucet, *chainParams, privateKey, randAddr, 10000, 100)

Please update these instances to match the new function signature.

Analysis chain

LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to generateSACP match the new signature.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `generateSACP` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'generateSACP'

Length of output: 4763

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a4c663b and 57f136d.

Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
Files selected for processing (17)
  • btc/batcher.go (1 hunks)
  • btc/batcher_test.go (1 hunks)
  • btc/client.go (1 hunks)
  • btc/client_test.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/cpfp_test.go (1 hunks)
  • btc/fee_test.go (3 hunks)
  • btc/htlc.go (5 hunks)
  • btc/htlc_test.go (4 hunks)
  • btc/rbf.go (1 hunks)
  • btc/rbf_test.go (1 hunks)
  • btc/scripts_test.go (3 hunks)
  • btc/store.go (1 hunks)
  • btc/store_test.go (1 hunks)
  • btc/wallet.go (22 hunks)
  • btc/wallet_test.go (44 hunks)
  • go.mod (4 hunks)
Files skipped from review due to trivial changes (3)
  • btc/client.go
  • btc/client_test.go
  • btc/scripts_test.go
Files skipped from review as they are similar to previous changes (5)
  • btc/batcher.go
  • btc/batcher_test.go
  • btc/cpfp_test.go
  • btc/rbf_test.go
  • go.mod
Additional context used
Learnings (3)
btc/htlc_test.go (5)
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:23:25.339Z
Learning: When generating unit tests for the `HTLCWallet` interface in `btc/htlc.go`, use a mock implementation of the `Wallet` interface to test the methods.
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:23:25.339Z
Learning: When generating unit tests for the `RedeemLeaf`, `InstantRefundLeaf`, and `toLeaf` functions in `btc/htlc.go`, ensure to cover various scenarios including valid inputs, empty inputs, and error cases.
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:23:25.339Z
Learning: When generating unit tests for the `TxInputRequest` and `TxOutputRequest` structs in `btc/wallet.go`, ensure to validate the fields' values.
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:20:39.303Z
Learning: When generating unit tests for the `RedeemLeaf` function in `btc/htlc.go`, ensure to cover various scenarios including valid inputs, empty `redeemerPubkey`, and empty `secretHash`.
Learnt from: Revantark
PR: catalogfi/blockchain#20
File: btc/htlc.go:0-0
Timestamp: 2024-07-15T05:16:35.525Z
Learning: The ineffectual assignment to `err` in the `GenerateInstantRefundSACP` function in `btc/htlc.go` was fixed in commit `e0b37abcf9c6f20c2e9e762b313da4c346926a4f`.
btc/htlc.go (2)
Learnt from: Revantark
PR: catalogfi/blockchain#20
File: btc/htlc.go:0-0
Timestamp: 2024-07-15T05:16:35.525Z
Learning: The ineffectual assignment to `err` in the `GenerateInstantRefundSACP` function in `btc/htlc.go` was fixed in commit `e0b37abcf9c6f20c2e9e762b313da4c346926a4f`.
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:23:25.339Z
Learning: When generating unit tests for the `RedeemLeaf`, `InstantRefundLeaf`, and `toLeaf` functions in `btc/htlc.go`, ensure to cover various scenarios including valid inputs, empty inputs, and error cases.
btc/wallet_test.go (1)
Learnt from: yanivas
PR: catalogfi/blockchain#12
File: btc/htlc.go:19-32
Timestamp: 2024-07-03T12:23:25.339Z
Learning: When generating unit tests for the `HTLCWallet` interface in `btc/htlc.go`, use a mock implementation of the `Wallet` interface to test the methods.
golangci-lint
btc/store.go

381-381: func (*BatcherCache).saveLatestBatch is unused

(unused)

btc/cpfp.go

377-377: func reconstructCPFPBatches is unused

(unused)

btc/rbf.go

712-712: func getSelfUtxos is unused

(unused)

Additional comments not posted (77)
btc/htlc_test.go (8)

Line range hint 48-58: LGTM!

The test case correctly verifies that no errors occur during the generation of an HTLC address.


Line range hint 68-78: LGTM!

The test case correctly verifies that no errors occur during the initiation of an HTLC.


Line range hint 88-118: LGTM!

The test case correctly verifies that no errors occur during the initiation and redemption of an HTLC.


Line range hint 128-148: LGTM!

The test case correctly verifies that no errors occur during the initiation and refund of an HTLC.


Line range hint 158-198: LGTM!

The test case correctly verifies that no errors occur during the initiation and instant refund of an HTLC.


Line range hint 208-238: LGTM!

The test case correctly verifies that an instant refund fails if the SACP is not correct.


Line range hint 248-278: LGTM!

The test case correctly verifies that an instant refund succeeds even if the fee is low.


Line range hint 288-318: LGTM!

The test case correctly verifies that multiple initiates can be redeemed or refunded.

btc/store_test.go (16)

54-67: LGTM!

The test case correctly verifies the SaveBatch functionality.


68-75: LGTM!

The test case correctly verifies that a batch that already exists is not saved again.


76-94: LGTM!

The test case correctly verifies that a finalized batch is saved correctly.


99-112: LGTM!

The test case correctly verifies the ReadBatchByReqId functionality.


117-136: LGTM!

The test case correctly verifies the ReadPendingBatches functionality.


140-156: LGTM!

The test case correctly verifies the ReadLatestBatch functionality.


160-172: LGTM!

The test case correctly verifies the UpdateBatches functionality.


173-192: LGTM!

The test case correctly verifies that all pending requests are removed if a batch is confirmed.


193-202: LGTM!

The test case correctly verifies that a batch that does not exist can be created.


206-224: LGTM!

The test case correctly verifies the UpdateAndDeletePendingBatches functionality.


226-229: LGTM!

The test case correctly verifies that an error is returned if there is nothing to update.


231-239: LGTM!

The test case correctly verifies that a batch that does not exist can be created.


241-278: LGTM!

The test case correctly verifies that all pending batches and requests are deleted.


282-303: LGTM!

The test case correctly verifies the DeletePendingBatches functionality.


307-321: LGTM!

The test case correctly verifies the ReadRequests functionality.


325-347: LGTM!

The test case correctly verifies the ReadPendingRequests functionality.

btc/htlc.go (6)

Line range hint 138-158: LGTM!

The function correctly generates the SACP transaction needed for instant refunds.


247-253: LGTM!

The function correctly performs an instant refund given the counterparty signed SACP transaction.


282-284: LGTM!

The function correctly performs a refund of the HTLC if it is expired.


Line range hint 417-421: LGTM!

The function correctly creates a new instance of htlcTapLeaves.


443-445: LGTM!

The function correctly retrieves the control block for a given HTLC and leaf.


Line range hint 358-398: LGTM!

The function correctly validates the instant refund SACP transaction.

btc/store.go (14)

20-28: LGTM!

The serializableSpendRequest type is correctly defined.


30-34: LGTM!

The serializableSendRequest type is correctly defined.


36-43: LGTM!

The serializableBatcherRequest type is correctly defined.


119-125: LGTM!

The serializableBatch type is correctly defined.


45-73: LGTM!

The serializeBatcherRequest function correctly serializes a BatcherRequest to a byte slice.


75-117: LGTM!

The deserializeBatcherRequest function correctly deserializes a byte slice to a BatcherRequest.


127-141: LGTM!

The serializeBatch function correctly serializes a Batch to a byte slice.


143-163: LGTM!

The deserializeBatch function correctly deserializes a byte slice to a Batch.


172-178: LGTM!

The NewBatcherCache function correctly initializes a BatcherCache with the given database and strategy.


180-189: LGTM!

The get function correctly retrieves data from the LevelDB database and handles errors.


191-197: LGTM!

The ReadBatchByReqID function correctly reads a batch by request ID from the cache.


199-216: LGTM!

The searchBatch function correctly searches for a batch by ID in the pending and finalized batches.


218-233: LGTM!

The ReadPendingBatches function correctly reads all pending batches from the cache and handles errors.


235-244: LGTM!

The ReadLatestBatch function correctly reads the latest batch from the cache and handles errors.

btc/wallet_test.go (1)

1207-1212: Verify the mining of Bitcoin blocks.

Ensure that the localnet.MineBitcoinBlocks function correctly mines the required number of blocks.

Verification successful

Verified the mining of Bitcoin blocks.

The localnet.MineBitcoinBlocks function in localnet/localnet.go correctly mines the required number of blocks and handles errors appropriately.

  • The function retrieves the current block height.
  • It generates the specified number of blocks.
  • It checks the new block height to ensure the blocks are mined.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the mining of Bitcoin blocks.

# Test: Search for the function usage. Expect: Correct mining of blocks.
rg --type go -A 5 $'localnet.MineBitcoinBlocks'

Length of output: 4908


Script:

#!/bin/bash
# Description: Locate the implementation of the localnet.MineBitcoinBlocks function.

# Search for the function definition in Go files.
rg --type go 'func MineBitcoinBlocks' -A 10

Length of output: 645

btc/cpfp.go (9)

37-39: Improve error message for missing requests.

The error message ErrBatchParametersNotMet is not descriptive enough. Consider providing a more specific error message.

-	return ErrBatchParametersNotMet
+	return errors.New("no pending requests found")

Likely invalid or redundant comment.


108-110: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}

Likely invalid or redundant comment.


245-245: Fix the recursion depth check.

The recursion depth check might cause unintended behavior. Consider changing the condition to depth <= 0.

-	if depth < 0 {
+	if depth <= 0 {

Likely invalid or redundant comment.


178-181: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		utxos, err = w.indexer.GetUTXOs(ctx, w.address)
-		return err
-	})
+	utxos, err = w.indexer.GetUTXOs(c, w.address)
+	if err != nil {
+		return err
+	}

Likely invalid or redundant comment.


267-270: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests)
-		return err
-	})
+	spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(c, w.indexer, spendRequests)
+	if err != nil {
+		return nil, err
+	}

Likely invalid or redundant comment.


133-135: Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.SaveBatch(ctx, batch)
-	})
+	err = w.cache.SaveBatch(c, batch)
+	if err != nil {
+		return ErrSavingBatch
+	}

Likely invalid or redundant comment.


241-372: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to buildCPFPTx are correctly implemented.

Verification successful

Function usage verified successfully.

All calls to the buildCPFPTx function in the codebase match the new implementation and provide the necessary arguments.

  • btc/cpfp.go: Multiple calls to buildCPFPTx with appropriate parameters.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `buildCPFPTx` match the new implementation.

# Test: Search for the function usage. Expect: Only occurances of the new implementation.
rg --type go -A 5 $'buildCPFPTx'

Length of output: 1428


145-239: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to updateCPFP are correctly implemented.

Verification successful

Function usage verified successfully

The function updateCPFP is correctly implemented and used in the codebase.

  • btc/batcher.go: The call to updateCPFP matches the new implementation and correctly passes the required parameters.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `updateCPFP` match the new implementation.

# Test: Search for the function usage. Expect: Only occurances of the new implementation.
rg --type go -A 5 $'updateCPFP'

Length of output: 676


Script:

#!/bin/bash
# Extract more lines around the call to `updateCPFP` in `btc/batcher.go` to verify the function usage in detail.
rg --type go -A 10 -B 10 $'updateCPFP' btc/batcher.go

Length of output: 512


22-142: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to createCPFPBatch are correctly implemented.

Verification successful

The function createCPFPBatch is defined in btc/cpfp.go and is called in btc/batcher.go. We need to ensure that the function call in btc/batcher.go matches the new implementation of createCPFPBatch.


To ensure the function call to createCPFPBatch is correctly implemented, we need to inspect the full context of the function where it is called in btc/batcher.go.


Function call to createCPFPBatch is correctly implemented

The function call to createCPFPBatch in btc/batcher.go is correctly implemented within the createBatch function and matches the new implementation.

  • btc/batcher.go:
    • The createBatch function calls createCPFPBatch based on the strategy set in the wallet's options.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `createCPFPBatch` match the new implementation.

# Test: Search for the function usage. Expect: Only occurances of the new implementation.
rg --type go -A 5 $'createCPFPBatch'

Length of output: 683


Script:

#!/bin/bash
# Inspect the function call to `createCPFPBatch` in `btc/batcher.go` to verify it matches the new implementation.
rg --type go -A 10 $'createCPFPBatch' btc/batcher.go

Length of output: 422


Script:

#!/bin/bash
# Search for the function definition in `btc/batcher.go` to get the complete context of the function where `createCPFPBatch` is called.
rg --type go -A 20 $'func' btc/batcher.go

Length of output: 10921

btc/fee_test.go (3)

68-68: LGTM!

The added assertion improves the robustness of the test by explicitly checking for errors.


118-118: LGTM!

The added assertion improves the robustness of the test by explicitly checking for errors.


424-424: LGTM!

The added assertion improves the robustness of the test by explicitly checking for errors.

btc/rbf.go (11)

307-313: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to update and delete pending batches: %w", err)

Likely invalid or redundant comment.


269-271: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return w.cache.SaveBatch(ctx, batch)
+ return fmt.Errorf("failed to save RBF batch: %w", w.cache.SaveBatch(ctx, batch))

Likely invalid or redundant comment.


546-548: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get UTXOs from indexer: %w", err)

Likely invalid or redundant comment.


469-471: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get UTXOs with fee: %w", err)

Likely invalid or redundant comment.


29-31: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to read pending requests: %w", err)

Likely invalid or redundant comment.


320-323: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to validate fee rate update: %w", err)

Likely invalid or redundant comment.


68-68: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return w.reSubmitRBFBatch(c, latestBatch, pendingRequests, 0)
+ return fmt.Errorf("re-submitting existing RBF batch: %w", w.reSubmitRBFBatch(c, latestBatch, pendingRequests, 0))

Likely invalid or redundant comment.


418-419: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey)
+ return fmt.Errorf("failed to sign spend transaction: %w", signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey))

Likely invalid or redundant comment.


242-244: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return w.indexer.SubmitTx(ctx, tx)
+ return fmt.Errorf("failed to submit RBF transaction: %w", w.indexer.SubmitTx(ctx, tx))

Likely invalid or redundant comment.


202-204: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get fee suggestion: %w", err)

Likely invalid or redundant comment.


146-148: Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get transaction: %w", err)

Likely invalid or redundant comment.

btc/wallet.go (9)

73-74: LGTM!

The error variable ErrSCAPNoInputsFound is correctly defined.


76-77: LGTM!

The error variable ErrSCAPInputsNotEqualOutputs is correctly defined.


399-399: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to getFeeUsedInSACPs match the new signature.

Verification successful

Function usage matches the new signature.

The function getFeeUsedInSACPs is correctly called with the new context parameter in the codebase.

  • btc/wallet.go: sacpsFee, err := getFeeUsedInSACPs(ctx, sacps, sw.indexer)
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `getFeeUsedInSACPs` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'getFeeUsedInSACPs'

Length of output: 748


643-643: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to signSpendTx match the new signature.

Verification successful

All calls to signSpendTx match the new function signature.

The function calls in the following files correctly include the ctx parameter:

  • btc/wallet.go
  • btc/rbf.go
  • btc/cpfp.go
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `signSpendTx` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'signSpendTx'

Length of output: 1438


206-206: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to Send match the new signature.

Verification successful

All instances of the Send function match the new signature.

The function calls to Send have been updated to include the context.Context parameter as expected.

  • Verified instances in:
    • btc/wallet_test.go
    • evm/wallet_test.go
    • evm/wallet.go
    • btc/rbf_test.go
    • btc/htlc_test.go
    • btc/cpfp_test.go
    • btc/fee_test.go
    • btc/htlc.go
    • btc/rbf.go
    • btc/cpfp.go
    • btc/client.go
    • btc/batcher.go
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `Send` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'Send'

Length of output: 45817


328-328: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to spendAndSend match the new signature.

Verification successful

Function usage verification successful.

All instances of the spendAndSend function in btc/wallet.go use the new signature with the context parameter.

  • btc/wallet.go:
    • Line 1: tx, err := sw.spendAndSend(ctx, sendRequests, spendRequests, sacps, sacpsFee, fee, 0)
    • Line 2: return sw.spendAndSend(ctx, sendRequests, spendRequests, sacps, sacpFee, feeToBePaid, depth+1)
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `spendAndSend` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'spendAndSend'

Length of output: 915


417-417: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to getPrevoutsForSACPs match the new signature.

Verification successful

Verify all function calls to getPrevoutsForSACPs match the new signature.

The code changes are approved. However, ensure that all function calls to getPrevoutsForSACPs match the new signature.


Verified: All function calls to getPrevoutsForSACPs match the new signature.

The code changes are approved, and all instances of the function usage have been updated accordingly.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `getPrevoutsForSACPs` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'getPrevoutsForSACPs'

Length of output: 874


Script:

#!/bin/bash
# Description: Verify all function calls to `getPrevoutsForSACPs` match the new signature.

# Test: Search for all occurrences of the function usage. Expect: Only occurrences of the new signature.
rg --type go 'getPrevoutsForSACPs'

Length of output: 416


249-249: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to GenerateSACP match the new signature.

Verification successful

All function calls to GenerateSACP match the new signature.

The verification confirms that the function GenerateSACP is consistently used with the updated signature across the codebase.

  • btc/wallet_test.go
  • btc/htlc.go
  • btc/batcher.go
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `GenerateSACP` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'GenerateSACP'

Length of output: 2604


373-373: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to getSACPAmounts match the new signature.

Verification successful

Verification complete: All calls to getSACPAmounts match the new signature.

All instances of the function getSACPAmounts in the codebase include the ctx parameter, confirming the update is consistent.

  • btc/wallet.go
  • btc/rbf.go
  • btc/cpfp.go
  • btc/batcher.go
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `getSACPAmounts` match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go -A 5 $'getSACPAmounts'

Length of output: 1406

Comment on lines +1422 to +1428
func skipFor(mode MODE, modes ...MODE) {
for _, m := range modes {
if m == mode {
Skip("Skipping test for mode: " + string(m))
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper mode handling in skipFor.

The function skipFor should handle modes more robustly and provide meaningful messages.

-  if m == mode {
-    Skip("Skipping test for mode: " + string(m))
-  }
+  if m == mode {
+    Skip(fmt.Sprintf("Skipping test for mode: %v", mode))
+  }
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 skipFor(mode MODE, modes ...MODE) {
for _, m := range modes {
if m == mode {
Skip("Skipping test for mode: " + string(m))
}
}
}
func skipFor(mode MODE, modes ...MODE) {
for _, m := range modes {
if m == mode {
Skip(fmt.Sprintf("Skipping test for mode: %v", mode))
}
}
}

Comment on lines +1398 to +1420
func assertSuccess(wallet btc.Wallet, tx *btc.Transaction, txid string, mode MODE) {
var ok bool
var err error
switch mode {
case SIMPLE:
*tx, ok, err = wallet.Status(context.Background(), txid)
Expect(err).To(BeNil())
Expect(ok).Should(BeTrue())
Expect(tx).ShouldNot(BeNil())
case BATCHER_CPFP, BATCHER_RBF:
var ok bool
for {
fmt.Println("waiting for tx", txid)
*tx, ok, err = wallet.Status(context.Background(), txid)
Expect(err).To(BeNil())
if ok {
Expect(tx).ShouldNot(BeNil())
break
}
time.Sleep(1 * time.Second)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure robust error handling in assertSuccess.

The function assertSuccess should handle errors more robustly, especially in the loop for batcher modes.

-  for {
-    fmt.Println("waiting for tx", txid)
-    *tx, ok, err = wallet.Status(context.Background(), txid)
-    Expect(err).To(BeNil())
-    if ok {
-      Expect(tx).ShouldNot(BeNil())
-      break
-    }
-    time.Sleep(1 * time.Second)
-  }
+  ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+  defer cancel()
+  for {
+    fmt.Println("waiting for tx", txid)
+    *tx, ok, err = wallet.Status(ctx, txid)
+    if err != nil {
+      fmt.Println("Error fetching status:", err)
+      return
+    }
+    if ok {
+      Expect(tx).ShouldNot(BeNil())
+      break
+    }
+    select {
+    case <-ctx.Done():
+      fmt.Println("Timeout waiting for tx", txid)
+      return
+    default:
+      time.Sleep(1 * time.Second)
+    }
+  }
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 assertSuccess(wallet btc.Wallet, tx *btc.Transaction, txid string, mode MODE) {
var ok bool
var err error
switch mode {
case SIMPLE:
*tx, ok, err = wallet.Status(context.Background(), txid)
Expect(err).To(BeNil())
Expect(ok).Should(BeTrue())
Expect(tx).ShouldNot(BeNil())
case BATCHER_CPFP, BATCHER_RBF:
var ok bool
for {
fmt.Println("waiting for tx", txid)
*tx, ok, err = wallet.Status(context.Background(), txid)
Expect(err).To(BeNil())
if ok {
Expect(tx).ShouldNot(BeNil())
break
}
time.Sleep(1 * time.Second)
}
}
}
func assertSuccess(wallet btc.Wallet, tx *btc.Transaction, txid string, mode MODE) {
var ok bool
var err error
switch mode {
case SIMPLE:
*tx, ok, err = wallet.Status(context.Background(), txid)
Expect(err).To(BeNil())
Expect(ok).Should(BeTrue())
Expect(tx).ShouldNot(BeNil())
case BATCHER_CPFP, BATCHER_RBF:
var ok bool
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
for {
fmt.Println("waiting for tx", txid)
*tx, ok, err = wallet.Status(ctx, txid)
if err != nil {
fmt.Println("Error fetching status:", err)
return
}
if ok {
Expect(tx).ShouldNot(BeNil())
break
}
select {
case <-ctx.Done():
fmt.Println("Timeout waiting for tx", txid)
return
default:
time.Sleep(1 * time.Second)
}
}
}
}

btc/rbf.go Outdated
Comment on lines 41 to 43
latestBatch, err = w.cache.ReadLatestBatch(ctx)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to read latest batch: %w", err)
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
latestBatch, err = w.cache.ReadLatestBatch(ctx)
return err
})
latestBatch, err = w.cache.ReadLatestBatch(ctx)
return fmt.Errorf("failed to read latest batch: %w", err)

Comment on lines +378 to +380
sacpsInAmount, sacpsOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get SACP amounts: %w", err)
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
sacpsInAmount, sacpsOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
sacpsInAmount, sacpsOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return fmt.Errorf("failed to get SACP amounts: %w", err)

btc/rbf.go Outdated
Comment on lines 104 to 106
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.DeletePendingBatches(ctx)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return w.cache.DeletePendingBatches(ctx)
+ return fmt.Errorf("failed to delete pending batch: %w", w.cache.DeletePendingBatches(ctx))
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.DeletePendingBatches(ctx)
})
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return fmt.Errorf("failed to delete pending batch: %w", w.cache.DeletePendingBatches(ctx))
})

btc/cpfp.go Outdated
Comment on lines 60 to 62
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.UpdateBatches(ctx, confirmedTxs...)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.cache.UpdateBatches(ctx, confirmedTxs...)
-	})
+	err = w.cache.UpdateBatches(c, confirmedTxs...)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.cache.UpdateBatches(ctx, confirmedTxs...)
})
err = w.cache.UpdateBatches(c, confirmedTxs...)
if err != nil {
return err
}

Comment on lines +215 to +217
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		return w.indexer.SubmitTx(ctx, tx)
-	})
+	err = w.indexer.SubmitTx(c, tx)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
return w.indexer.SubmitTx(ctx, tx)
})
err = w.indexer.SubmitTx(c, tx)
if err != nil {
return err
}

Comment on lines +342 to +345
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
-		return err
-	})
+	sacpsInAmount, sacpOutAmount, err = getSACPAmounts(c, sacps, w.indexer)
+	if err != nil {
+		return nil, err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})
sacpsInAmount, sacpOutAmount, err = getSACPAmounts(c, sacps, w.indexer)
if err != nil {
return nil, err
}

btc/cpfp.go Outdated
Comment on lines 222 to 231
// Update the fee of all batches that got bumped
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}

return w.cache.UpdateBatches(ctx, newBatches...)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		newBatches := []Batch{}
-		for _, batch := range pendingBatches {
-			batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
-			newBatches = append(newBatches, batch)
-		}
-		return w.cache.UpdateBatches(ctx, newBatches...)
-	})
+	newBatches := []Batch{}
+	for _, batch := range pendingBatches {
+		batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
+		newBatches = append(newBatches, batch)
+	}
+	err = w.cache.UpdateBatches(c, newBatches...)
+	if err != nil {
+		return err
+	}
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
// Update the fee of all batches that got bumped
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}
return w.cache.UpdateBatches(ctx, newBatches...)
})
// Update the fee of all batches that got bumped
newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}
err = w.cache.UpdateBatches(c, newBatches...)
if err != nil {
return err
}

btc/cpfp.go Outdated
Comment on lines 46 to 49
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts might cause unintended delays. Consider refactoring to reduce nesting.

-	err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-		batches, err = w.cache.ReadPendingBatches(ctx)
-		return err
-	})
+	batches, err = w.cache.ReadPendingBatches(c)
+	if err != nil {
+		return err
+	}
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
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
batches, err = w.cache.ReadPendingBatches(ctx)
return err
})
batches, err = w.cache.ReadPendingBatches(c)
if err != nil {
return err
}

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 57f136d and e12ef8c.

Files selected for processing (3)
  • btc/batcher.go (1 hunks)
  • btc/cpfp.go (1 hunks)
  • btc/rbf.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • btc/batcher.go
Additional context used
golangci-lint
btc/cpfp.go

363-363: func reconstructCPFPBatches is unused

(unused)

Additional comments not posted (6)
btc/cpfp.go (6)

409-420: LGTM!

The function removeDoubleSpends appears to be implemented correctly.


101-106: Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-   return w.indexer.SubmitTx(ctx, tx)
- })
- if err != nil {
-   return err
- }
+ err = w.indexer.SubmitTx(c, tx)
+ if err != nil {
+   return fmt.Errorf("failed to submit CPFP transaction: %w", err)
+ }

Likely invalid or redundant comment.


253-259: Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-   spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests)
-   return err
- })
- if err != nil {
-   return nil, err
- }
+ spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(c, w.indexer, spendRequests)
+ if err != nil {
+   return nil, fmt.Errorf("failed to get UTXOs for spend request: %w", err)
+ }

Likely invalid or redundant comment.


41-45: Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- batches, err := w.cache.ReadPendingBatches(c)
- if err != nil {
-   w.logger.Error("failed to read pending batches", zap.Error(err))
-   return err
- }
+ batches, err := w.cache.ReadPendingBatches(c)
+ if err != nil {
+   return fmt.Errorf("failed to read pending batches: %w", err)
+ }

Likely invalid or redundant comment.


140-144: Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- batches, err := w.cache.ReadPendingBatches(c)
- if err != nil {
-   w.logger.Error("failed to read pending batches", zap.Error(err))
-   return err
- }
+ batches, err = w.cache.ReadPendingBatches(c)
+ if err != nil {
+   return fmt.Errorf("failed to read pending batches: %w", err)
+ }

Likely invalid or redundant comment.


126-130: Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- err = w.cache.SaveBatch(c, batch)
- if err != nil {
-   w.logger.Error("failed to save CPFP batch", zap.Error(err))
-   return ErrSavingBatch
- }
+ err = w.cache.SaveBatch(c, batch)
+ if err != nil {
+   return fmt.Errorf("failed to save CPFP batch: %w", err)
+ }

Likely invalid or redundant comment.

Comment on lines +363 to +369
func reconstructCPFPBatches([]Batch, Batch, btcutil.Address) error {
// TODO: Verify that the trailing batch can trace back to the funding UTXOs from the wallet address
// This is essential to ensure that all the pending transactions are moved to the estimated
// fee rate and the trailing batch is the only one that needs to be bumped
// Current implementation assumes that the trailing batch is the last batch in the list
// It maintains only one thread of CPFP transactions
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Implement the reconstructCPFPBatches function.

The function is currently a placeholder with a TODO comment. Implement the function to ensure proper functionality.

Do you want me to help implement this function or open a GitHub issue to track this task?

Tools
golangci-lint

363-363: func reconstructCPFPBatches is unused

(unused)

Comment on lines +449 to +451
// if !utxo.Status.Confirmed {
// ucUtxos = append(ucUtxos, utxo)
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error wrapping.

When returning errors, consider wrapping them to provide more context.

- return err
+ return fmt.Errorf("failed to get raw transaction bytes: %w", err)

Committable suggestion was skipped due to low confidence.

Comment on lines +22 to +23
func (w *batcherWallet) createCPFPBatch(c context.Context) error {

Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- requests, err := w.cache.ReadPendingRequests(c)
- if err != nil {
-   w.logger.Error("failed to read pending requests", zap.Error(err))
-   return err
- }
+ requests, err := w.cache.ReadPendingRequests(c)
+ if err != nil {
+   return fmt.Errorf("failed to read pending requests: %w", err)
+ }

Committable suggestion was skipped due to low confidence.

Comment on lines +328 to +341
err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
return err
})

// Estimate the new fee
newFeeEstimate := (int(trueSize) * (feeRate)) + feeOverhead + bufferFee - int(sacpsInAmount-sacpOutAmount)

// If the new fee estimate exceeds the current fee, rebuild the CPFP transaction
if newFeeEstimate > fee+feeOverhead {
var txBytes []byte
if txBytes, err = GetTxRawBytes(tx); err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Improve logging for recursion depth exceeded.

The logging should include the error context for better debugging.

- w.logger.Debug(
-   ErrBuildCPFPDepthExceeded.Error(),
+ w.logger.Debug("recursion depth exceeded",

Committable suggestion was skipped due to low confidence.

Comment on lines +389 to +401
totalSize := int(0)
feeDelta := int(0)

for _, batch := range batches {
size := batch.Tx.Weight / blockchain.WitnessScaleFactor
feeRate := int(batch.Tx.Fee) / size
if feeRate > maxFeeRate {
maxFeeRate = feeRate
}
if reqFeeRate > feeRate {
feeDelta += (reqFeeRate - feeRate) * size
}
totalSize += size
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid redundant variable declaration.

The variable totalSize is declared but not used. Consider removing it.

- totalSize := int(0)
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
totalSize := int(0)
feeDelta := int(0)
for _, batch := range batches {
size := batch.Tx.Weight / blockchain.WitnessScaleFactor
feeRate := int(batch.Tx.Fee) / size
if feeRate > maxFeeRate {
maxFeeRate = feeRate
}
if reqFeeRate > feeRate {
feeDelta += (reqFeeRate - feeRate) * size
}
totalSize += size
feeDelta := int(0)
for _, batch := range batches {
size := batch.Tx.Weight / blockchain.WitnessScaleFactor
feeRate := int(batch.Tx.Fee) / size
if feeRate > maxFeeRate {
maxFeeRate = feeRate
}
if reqFeeRate > feeRate {
feeDelta += (reqFeeRate - feeRate) * size
}

Comment on lines +231 to +245
if depth < 0 {
w.logger.Debug(
ErrBuildCPFPDepthExceeded.Error(),
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Int("fee", fee),
zap.Int("feeOverhead", feeOverhead),
zap.Int("feeRate", feeRate),
zap.Int("depth", depth),
)
return nil, ErrBuildCPFPDepthExceeded
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix the recursion depth check.

The recursion depth check might cause unintended behavior. Consider changing the condition to depth <= 0.

- if depth < 0 {
+ if depth <= 0 {
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 depth < 0 {
w.logger.Debug(
ErrBuildCPFPDepthExceeded.Error(),
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Int("fee", fee),
zap.Int("feeOverhead", feeOverhead),
zap.Int("feeRate", feeRate),
zap.Int("depth", depth),
)
return nil, ErrBuildCPFPDepthExceeded
}
if depth <= 0 {
w.logger.Debug(
ErrBuildCPFPDepthExceeded.Error(),
zap.Any("utxos", utxos),
zap.Any("spendRequests", spendRequests),
zap.Any("sendRequests", sendRequests),
zap.Any("sacps", sacps),
zap.Any("sequencesMap", sequencesMap),
zap.Int("fee", fee),
zap.Int("feeOverhead", feeOverhead),
zap.Int("feeRate", feeRate),
zap.Int("depth", depth),
)
return nil, ErrBuildCPFPDepthExceeded
}

Comment on lines +209 to +220
// Update the fee of all batches that got bumped

newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}
err = w.cache.UpdateBatches(c, newBatches...)
if err != nil {
w.logger.Error("failed to update CPFP batches", zap.Error(err))
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- err = w.cache.UpdateBatches(c, newBatches...)
- if err != nil {
-   w.logger.Error("failed to update CPFP batches", zap.Error(err))
-   return err
- }
+ err = w.cache.UpdateBatches(c, newBatches...)
+ if err != nil {
+   return fmt.Errorf("failed to update CPFP batches: %w", err)
+ }
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
// Update the fee of all batches that got bumped
newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}
err = w.cache.UpdateBatches(c, newBatches...)
if err != nil {
w.logger.Error("failed to update CPFP batches", zap.Error(err))
return err
}
// Update the fee of all batches that got bumped
newBatches := []Batch{}
for _, batch := range pendingBatches {
batch.Tx.Fee = int64(requiredFeeRate) * int64(batch.Tx.Weight) / blockchain.WitnessScaleFactor
newBatches = append(newBatches, batch)
}
err = w.cache.UpdateBatches(c, newBatches...)
if err != nil {
return fmt.Errorf("failed to update CPFP batches: %w", err)
}

Comment on lines +350 to +352
zap.Int("TxIns", len(tx.TxIn)),
zap.Int("TxOuts", len(tx.TxOut)),
zap.String("TxData", hex.EncodeToString(txBytes)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error {
-   sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer)
-   return err
- })
- if err != nil {
-   return nil, err
- }
+ sacpsInAmount, sacpOutAmount, err = getSACPAmounts(c, sacps, w.indexer)
+ if err != nil {
+   return nil, fmt.Errorf("failed to get SACP amounts: %w", err)
+ }
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
zap.Int("TxIns", len(tx.TxIn)),
zap.Int("TxOuts", len(tx.TxOut)),
zap.String("TxData", hex.EncodeToString(txBytes)),
zap.Int("TxIns", len(tx.TxIn)),
zap.Int("TxOuts", len(tx.TxOut)),
zap.String("TxData", hex.EncodeToString(txBytes)),
sacpsInAmount, sacpOutAmount, err = getSACPAmounts(c, sacps, w.indexer)
if err != nil {
return nil, fmt.Errorf("failed to get SACP amounts: %w", err)
}

Comment on lines +33 to +39
latestBatch, err := w.cache.ReadLatestBatch(c)
if err != nil {
// If no batch is found, create a new RBF batch.
if err == ErrStoreNotFound {
return w.createNewRBFBatch(c, pendingRequests, 0, 0)
}
return fmt.Errorf("failed to read latest batch: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- latestBatch, err := w.cache.Read

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +22 to +25
pendingRequests, err := w.cache.ReadPendingRequests(c)
if err != nil {
return fmt.Errorf("failed to read pending requests: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid nested context timeouts.

Nested context timeouts can cause unintended delays. Consider refactoring to reduce nesting.

- pendingRequests, err := w.cache.ReadPendingRequests(c)
- if err != nil {
-   return fmt.Errorf("failed to read pending requests: %w", err)
- }
+ pendingRequests, err = w.cache.ReadPendingRequests(c)
+ if err != nil {
+   return fmt.Errorf("failed to read pending requests: %w", err)
+ }

Committable suggestion was skipped due to low confidence.

@Revantark Revantark merged commit fe23a4a into master Jul 25, 2024
1 check passed
@Revantark Revantark deleted the feat/batcher branch July 25, 2024 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants