Skip to content

Validate txid length when parsing#1115

Draft
starius wants to merge 6 commits intolightninglabs:masterfrom
starius:max-hash-string-size
Draft

Validate txid length when parsing#1115
starius wants to merge 6 commits intolightninglabs:masterfrom
starius:max-hash-string-size

Conversation

@starius
Copy link
Copy Markdown
Collaborator

@starius starius commented Apr 7, 2026

chainhash.NewHashFromStr and chainhash.Decode accept partial txid, under 64 characters (even ""), padding its result with zeros. We should not use it directly to parse txid, otherwise we can accept truncated data accidentally. This PR replaces it with other functions (e.g. wire.NewOutPointFromString which is strict) or with the newly added strict wrapper NewHashFromStrExact.

SQL related code is fragile, so I decided to treat an empty string the same as NULL in some critical parts just in case such records exist in the DB. I'm not 100% certain about SQL commits, suggestions are welcome!

Also I found an issue in sweepbatcher: convertBatchRow swallowed errors and there is an obvious mistake when calling it. Fixed this as well.

Pull Request Checklist

  • Update release_notes.md if your PR contains major features, breaking changes or bugfixes

starius added 3 commits April 7, 2026 00:25
Add a dedicated helper that rejects any chainhash string unless it is
exactly 64 hex characters long, instead of relying on btcd's
lenient parser semantics.

Cover the helper with focused tests for valid, short, odd-length,
empty, and non-hex inputs so later call sites can use it as a
full-txid validation primitive.
Reject short skipped transaction IDs before passing them into the batcher.
Replace the local outpoint parser with wire.NewOutPointFromString.

This switches outpoint validation to btcd's canonical parser, which
rejects truncated txids and invalid output indexes.
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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 improves the robustness of transaction ID parsing and database interaction across the application. By replacing permissive parsing functions with strict validation, it ensures data integrity when handling transaction hashes. Additionally, it enhances error handling in batch processing and clarifies the API behavior regarding pending withdrawals, ensuring a more predictable and stable system state.

Highlights

  • Strict Transaction ID Parsing: Introduced a new utility function NewHashFromStrExact to enforce strict 64-character length validation for transaction IDs, preventing accidental acceptance of truncated data.
  • Database Robustness: Updated SQL storage logic to treat empty strings as NULL for critical fields, improving resilience against malformed database records.
  • Bug Fixes: Resolved an issue in sweepbatcher where errors were being swallowed during batch row conversion, and updated API documentation to clarify the state of pending withdrawals.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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.

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.

Copy link
Copy Markdown

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

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 introduces strict transaction ID parsing across the codebase using a new utility, chainhashutil.NewHashFromStrExact, which ensures that hex strings are exactly 64 characters long to prevent truncated hashes from being accepted. Additionally, the PR updates the static address withdrawal system to support pending states, allowing the transaction ID to be null or nil and documenting that associated fields will remain zero until confirmation. Database retrieval logic in several stores was refactored to handle these nullable fields and improve recovery robustness. Feedback was provided to ensure consistency in the withdrawal store by explicitly checking for empty strings when reading transaction IDs from the database.

if err != nil {
return nil, err
var txID *chainhash.Hash
if w.WithdrawalTxID.Valid {
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

For consistency and robustness, this check should also include a validation that the string is not empty, similar to the changes made in staticaddr/loopin/sql_store.go and sweepbatcher/store.go. The PR description mentions that SQL code is fragile and empty strings should be treated as NULL in critical parts. If an empty string exists in the database, chainhashutil.NewHashFromStrExact will return an error due to incorrect length, potentially breaking the recovery or listing of withdrawals.

Suggested change
if w.WithdrawalTxID.Valid {
if w.WithdrawalTxID.Valid && w.WithdrawalTxID.String != "" {

starius added 3 commits April 7, 2026 01:47
Use strict txid parsing when reading swap updates and static address
loop-ins from SQL rows. Empty swap update txids still mean "absent",
but any non-empty truncated value now fails loudly.

Add store-level tests that inject truncated txids through the query
layer and assert that the fetch paths reject them.
Return errors from batch row conversion instead of silently
accepting malformed batch txids while appending nil batches.
Represent withdrawal txids as optional in the domain model and keep
pending withdrawals visible through GetAllWithdrawals.

Pending rows now surface nil and zero values in Go and empty and zero
defaults over RPC, while malformed non-NULL txids still fail loudly.

Also sync godoc's with how it actually behaves: returns pending withdraws
in addition to finalized ones.
@starius starius force-pushed the max-hash-string-size branch from bfa83b9 to 8ac8e38 Compare April 7, 2026 06:48
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