Skip to content

chain: port over SubmitPackage from btcwallet - #11

Merged
bhandras merged 1 commit into
mainfrom
submitpackage
Nov 19, 2025
Merged

chain: port over SubmitPackage from btcwallet#11
bhandras merged 1 commit into
mainfrom
submitpackage

Conversation

@bhandras

Copy link
Copy Markdown
Member

No description provided.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @bhandras, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates the SubmitPackage RPC call, previously found in btcwallet, into the current project's chain package. This enables the atomic broadcasting of a set of parent transactions along with a child transaction to a bitcoind node. The change involves creating a new BitcoindRPCClient wrapper and updating module dependencies to support this new functionality, as well as exposing this client through the harness.

Highlights

  • New SubmitPackage Functionality: Introduced a SubmitPackage method within a new BitcoindRPCClient to atomically broadcast parent and child transaction packages to the Bitcoin network.
  • Dependency Updates: Updated various Go module dependencies, including btcd, btcwallet, and neutrino, to newer versions to support the new functionality and maintain compatibility.
  • Harness Integration: Modified the harness package to provide access to the new BitcoindRPCClient, enabling its use in testing or other harness-related operations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request ports the SubmitPackage functionality from btcwallet to provide a temporary implementation for submitting transaction packages. The changes include adding a new BitcoindRPCClient in the chain package, updating dependencies, and exposing the new client through the test harness.

My review focuses on the new chain/bitcoind_client.go file. I've identified some dead code (unused constants and a struct field) and a discrepancy between a function's comment and its implementation regarding error handling. These seem to be artifacts from the porting process and should be cleaned up to improve code clarity and correctness.

Comment thread chain/bitcoind_client.go
Comment on lines +53 to +54
// If the active backend cannot relay packages, ErrUnimplemented is
// returned.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The function comment states that ErrUnimplemented is returned if the backend cannot relay packages. However, the implementation does not check for this case (e.g., by checking for btcjson.ErrRPCMethodNotFound from the RPC response) and therefore does not return chain.ErrUnimplemented. This discrepancy between documentation and implementation can lead to incorrect error handling by callers. Given this is a temporary port, removing the comment is the simplest fix to align documentation with behavior.

Comment thread chain/bitcoind_client.go Outdated
Comment on lines +17 to +24
const (
// defaultSubmitPackageMaxTries is the default maximum number of tries
// for submitpackage RPC calls.
defaultSubmitPackageMaxTries = 60
// defaultSubmitPackageRetryWait is the default wait time between
// submitpackage RPC call retries.
defaultSubmitPackageRetryWait = 1 * time.Second
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The constants defaultSubmitPackageMaxTries and defaultSubmitPackageRetryWait are defined but not used. This appears to be dead code copied over during porting. To avoid confusion, it should be removed.

Comment thread chain/bitcoind_client.go
@claude

claude Bot commented Nov 19, 2025

Copy link
Copy Markdown

PR Review: Port SubmitPackage from btcwallet

Thanks for this contribution! This is a clean port that adds important package relay functionality. Here's my detailed review:

✅ Positive Aspects

  1. Clear Purpose: The code properly implements the submitpackage RPC call for atomically broadcasting parent+child transaction packages, which is essential for CPFP scenarios.

  2. Good Error Handling: Proper input validation and error wrapping with context using %w for error chains.

  3. Proper Dependency Updates: The go.mod updates look correct, moving btcd to v0.25.0 and promoting btcwallet from indirect to direct dependency.

🔍 Issues & Recommendations

CRITICAL: Missing Test Coverage

According to the repository development guidelines, the project strives for near 90% test coverage. This PR adds 135 lines of new code in chain/bitcoind_client.go with zero test coverage.

Required Actions:

  • Add chain/bitcoind_client_test.go with comprehensive unit tests
  • Test cases should include valid parent+child package submission, empty parents slice error, nil child transaction error, serialization failures, maxFeeRateBTCPerVByte conversion (nil and valid values), and mock RPC responses for both success and failure scenarios

Code Style Issues

  1. Typo in comment (chain/bitcoind_client.go:71): "transactions to that we'll add the request" should be "transactions that we'll add to the request"

  2. Variable naming (chain/bitcoind_client.go:83): The variable name 'ch' for parent transactions is misleading. Should use 'parent' or 'tx' for clarity.

  3. Unused constants (chain/bitcoind_client.go:17-23): defaultSubmitPackageMaxTries and defaultSubmitPackageRetryWait are defined but never used. Either remove them, implement retry logic, or add a comment explaining they're reserved for future use.

  4. Unused struct field (chain/bitcoind_client.go:32): The chainClient field is never initialized or used. Consider removing it or document why it's present.

  5. Comment typo (chain/bitcoind_client.go:128): "Unmarshall" should be "Unmarshal" (one 'l').

Documentation Issues

The SubmitPackage comment mentions "The returned slice holds the txids" but the function returns *btcjson.SubmitPackageResult, not a slice. Update documentation to clarify what fields the result contains.

Potential Issues

  1. Error handling: Consider defining package-level sentinel errors instead of using errors.New, to allow callers to use errors.Is() for better error handling.

  2. Fee rate validation: No validation that maxFeeRateBTCPerVByte is positive when non-nil. Negative or zero values could cause issues.

📋 Testing Checklist

Before merging, ensure:

  • make unit pkg=chain timeout=5m passes with new tests
  • make lint passes
  • Test coverage for chain/bitcoind_client.go is ≥80%
  • No ERR log lines in test output (unless testing error paths)

🎯 Summary

This is a solid foundation, but tests are mandatory per project guidelines. The code quality is good overall with minor style issues. Once tests are added and the issues above are addressed, this will be ready to merge.

Recommendation: Request changes for test coverage before approval.

@claude

claude Bot commented Nov 19, 2025

Copy link
Copy Markdown

Code Review: SubmitPackage Implementation

Thank you for porting over the SubmitPackage functionality from btcwallet! This is a solid implementation with clear purpose. Below are my findings:

Strengths

  1. Good documentation: The function comments follow the project convention of starting with the function name and explain the parameters clearly
  2. Proper error wrapping: Uses fmt.Errorf with %w for error wrapping throughout (chain/bitcoind_client.go:74-75, :82-83, :91-92, :104-105)
  3. Clean abstraction: The wrapper pattern around rpcclient.Client is appropriate for adding functionality not yet upstream
  4. Reasonable validation: Input sanity checks for nil/empty values (chain/bitcoind_client.go:50-57)
  5. Dependencies updated correctly: The go.mod changes look appropriate, upgrading to btcd v0.25.0 and related dependencies

Issues and Suggestions

1. Missing Test Coverage (HIGH PRIORITY)

Per CLAUDE.md, you must strive for near 90% test coverage where practical. This PR adds 123 lines of new code but no tests.

Required tests:

  • Unit test for input validation (nil child, empty parents)
  • Unit test for transaction serialization logic
  • Unit test for fee rate conversion (BTC/vByte to BTC/kvB)
  • Mock test for RPC interaction (consider using a test RPC client)
  • Integration test demonstrating the package submission flow

Action: Add chain/bitcoind_client_test.go before merging.

2. Typo in Comment (line 59)

Current: "Prepare the hex encoded transactions to that we'll add the request."

Should be: "Prepare the hex encoded transactions that we'll add to the request."

3. Variable Naming Inconsistency (line 71)

The variable "ch" is confusing—it suggests "channel" but represents a transaction. Use "parent" or "tx" for clarity:

for i, parent := range parents {
    h, err := toHex(parent)
    // ...
}

4. Error Message Consistency

Lines 51-52 and 56 use errors.New with inline error messages that bypass the nolint directive's intent. Consider defining sentinel errors at package level:

var (
    ErrNoParents = errors.New("submitpackage: need at least one parent txn")
    ErrNoChild = errors.New("submitpackage: child txn not defined")
)

This would remove the need for //nolint:err113 and improve testability.

5. Missing Context Parameter

Many functions in the codebase accept context.Context as the first parameter (per development_guidelines.md). While the underlying RawRequest doesn't accept context, consider future-proofing:

func (c *BitcoindRPCClient) SubmitPackage(ctx context.Context,
    parents []*wire.MsgTx, child *wire.MsgTx,
    maxFeeRateBTCPerVByte *float64) (*btcjson.SubmitPackageResult, error)

This would allow for cancellation/timeout support if rpcclient adds context support later.

6. Code Organization - Spacing

Per development_guidelines.md, code should be organized into logical stanzas with spacing. Consider adding blank lines between logical sections:

  • After input validation
  • Before defining the toHex helper
  • Before the parent serialization loop
  • Before child serialization
  • Before parameter marshaling

Security Considerations

No obvious security issues. The function properly validates inputs and wraps errors without exposing sensitive data.

Performance Considerations

Good preallocated slice capacity: make([]string, 0, len(parents)+1)

Minor note: The toHex closure is fine, but you could hoist it outside the function if it's reused elsewhere in the package.

Documentation Completeness

The function comment on line 41 mentions "If the active backend cannot relay packages, ErrUnimplemented is returned" but this error is never created or returned in the function body. Either:

  1. Remove this line from the docs, or
  2. Add detection logic for backends that don't support submitpackage

Before Merging:

  1. MUST: Add comprehensive unit tests (make unit pkg=chain)
  2. MUST: Run make lint and ensure it passes
  3. SHOULD: Fix the typo on line 59
  4. SHOULD: Rename variable ch to parent on line 71
  5. CONSIDER: Add context parameter for future-proofing
  6. CONSIDER: Define sentinel errors instead of inline error strings

Overall Assessment

This is a clean, well-structured implementation. The main blocker is missing test coverage—please add tests before merging per project requirements.

Commit Message Format Check: Properly formatted as "chain: port over SubmitPackage from btcwallet"

@claude

claude Bot commented Nov 19, 2025

Copy link
Copy Markdown

Code Review: SubmitPackage Implementation

Thank you for porting the SubmitPackage functionality! This PR adds important package relay capabilities. I've conducted a thorough review and found several issues that need addressing. While some concerns overlap with previous reviews, I'm highlighting additional aspects specific to this codebase's standards.


Critical Issues

1. Missing Test Coverage

Per CLAUDE.md: "Strive for near 90% test coverage where practical."

This PR adds 123 lines of production code with zero test coverage. Before merging, you MUST add:

  • chain/bitcoind_client_test.go with unit tests covering:
    • Input validation (empty parents, nil child)
    • Transaction serialization edge cases
    • Fee rate conversion (nil and various values, including edge cases like very small/large rates)
    • RPC response handling (success and various error scenarios)
    • The toHex helper function behavior with malformed transactions

Action Required: Run make unit pkg=chain timeout=5m after adding tests and verify coverage ≥80%.


Code Quality Issues

2. Comment Typo (line 59)

-	// Prepare the hex encoded transactions to that we'll add the request.
+	// Prepare the hex encoded transactions that we'll add to the request.

3. Variable Naming (line 71)

The variable name ch is misleading—suggests "channel" not "transaction":

-	for i, ch := range parents {
-		h, err := toHex(ch)
+	for i, parent := range parents {
+		h, err := toHex(parent)

4. Comment Typo (line 116)

-	// Unmarshall the response.
+	// Unmarshal the response.

5. Code Spacing (multiple locations)

Per docs/development_guidelines.md, code should be organized into logical stanzas with blank lines and comments explaining each section. The current implementation lacks proper spacing. Add blank lines:

  • After the input validation block (after line 57)
  • Before the toHex closure definition (before line 60)
  • Between major logical sections (serialization, parameter building, RPC call)

Example improvement for lines 59-69:

// Prepare the hex encoded transactions that we'll add to the request.
toHex := func(tx *wire.MsgTx) (string, error) {
	var buf bytes.Buffer
	if err := tx.Serialize(&buf); err != nil {
		return "", err
	}

	return hex.EncodeToString(buf.Bytes()), nil
}

// Serialize all parent transactions first, then the child.
rawTxs := make([]string, 0, len(parents)+1)

Design and Documentation Issues

6. Incomplete Documentation (line 41-42)

The function comment states: "If the active backend cannot relay packages, ErrUnimplemented is returned."

However, this error is never returned in the implementation. Either:

  • Remove this line from the documentation, OR
  • Implement error detection for unsupported backends

7. Error Handling Pattern (lines 50-56)

Using errors.New with inline strings requires //nolint:err113. Better practice: define package-level sentinel errors:

var (
	ErrNoParents = errors.New("submitpackage: need at least one parent txn")
	ErrNoChild   = errors.New("submitpackage: child txn not defined")
)

This enables callers to use errors.Is() and removes the need for the linter directive.

8. Missing Fee Rate Validation

The function accepts maxFeeRateBTCPerVByte *float64 but doesn't validate it's positive. Negative or zero values could cause unexpected behavior. Add validation:

if maxFeeRateBTCPerVByte != nil && *maxFeeRateBTCPerVByte <= 0 {
	return nil, fmt.Errorf("maxFeeRateBTCPerVByte must be positive: %f",
		*maxFeeRateBTCPerVByte)
}

9. Context Parameter Missing

Most functions in Lightning Labs codebases accept context.Context as the first parameter for cancellation/timeout support. While the underlying RawRequest doesn't support it yet, consider future-proofing:

func (c *BitcoindRPCClient) SubmitPackage(ctx context.Context,
	parents []*wire.MsgTx, child *wire.MsgTx,
	maxFeeRateBTCPerVByte *float64) (*btcjson.SubmitPackageResult, error)

You can add a TODO comment explaining why it's not used yet, but having the parameter enables future context propagation without breaking API changes.


Commit Organization Observation

Per CLAUDE.md: "Prefer small, atomic commits that build independently."

Consider whether dependency updates (go.mod/go.sum) should be in a separate commit from the feature implementation. This makes it easier to:

  • Review dependency changes independently
  • Revert or cherry-pick changes if needed
  • Understand the history

While not strictly required for this PR, it's a best practice for future contributions.


Pre-Merge Checklist

Before this PR can be merged:

  • Add chain/bitcoind_client_test.go with comprehensive unit tests
  • Run make lint and ensure it passes
  • Run make unit pkg=chain timeout=5m and ensure ≥80% coverage
  • Fix typos (lines 59, 116)
  • Rename ch to parent (line 71)
  • Add proper code spacing between logical stanzas
  • Fix or remove documentation about ErrUnimplemented
  • Consider adding fee rate validation
  • Consider defining sentinel errors instead of inline strings

Strongly Recommended:

  • Add context parameter for future-proofing

Positive Aspects

  • ✅ Proper error wrapping with %w throughout
  • ✅ Good capacity pre-allocation: make([]string, 0, len(parents)+1)
  • ✅ Clear wrapper abstraction around rpcclient.Client
  • ✅ Dependency updates look correct and necessary
  • ✅ Function comments follow convention (start with function name)
  • ✅ Integration with harness is clean and minimal

Summary

This is a functional implementation that adds valuable package relay capabilities, but it needs tests and code style improvements before merging. The biggest blocker is the complete absence of test coverage—this is non-negotiable per project standards.

Recommendation: Request changes for missing tests, style issues, and documentation clarification.

@ellemouton ellemouton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📦

@bhandras
bhandras merged commit dc8d82a into main Nov 19, 2025
15 checks passed
@bhandras
bhandras deleted the submitpackage branch November 19, 2025 08:23
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