Skip to content

tapgarden: hardening phase one (extraction)#2190

Merged
jtobin merged 5 commits into
lightninglabs:mainfrom
jtobin:tapgarden-extraction
Jul 10, 2026
Merged

tapgarden: hardening phase one (extraction)#2190
jtobin merged 5 commits into
lightninglabs:mainfrom
jtobin:tapgarden-extraction

Conversation

@jtobin

@jtobin jtobin commented Jul 2, 2026

Copy link
Copy Markdown
Member

This is an initial chunk of the large-scale tapgarden hardening work originally contained in #2153. It handles the following bullet from the original PR description:

Purity in output-key derivation. Previously it was possible for MintingOutputKey to return a cached value that didn't reflect the sibling argument the caller actually passed; now, because the function holds no state, its output is determined entirely by its inputs.

It contains the following changes (summary ctsy Opus):

Surface reduction. tapgarden had accumulated three concerns that didn't belong to it: node-side interfaces (chain bridge, key ring, wallet anchor, group fetcher), the re-org watcher, and the custodian. They move to new packages tapnode (with tapnodemock for tests), tapreorg, and tapcustody. Pure moves with no behavior change; what remains in tapgarden is more legibly about minting.

MintingOutputKey purity. MintingOutputKey read like a function of (batch, sibling) but was secretly stateful — it cached its first answer and returned that on subsequent calls regardless of the sibling argument. Only latent because in practice the call sites happened to agree; any restart or refactor that changed their order would have made the batch anchor to an address the tapscript witness couldn't prove against. The cache is dropped and the function is now actually pure.

@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 initiates a large-scale architectural hardening of the tapgarden package. By decoupling node-side interfaces and specific logic components into their own packages, the codebase is now more modular and easier to maintain. Furthermore, the PR resolves a latent state-related issue in the minting process by enforcing purity in key derivation, preventing potential commitment errors.

Highlights

  • Package Refactoring: Extracted node-side interfaces and logic from the monolithic tapgarden package into dedicated packages: tapnode, tapreorg, and tapcustody, improving modularity and maintainability.
  • Minting Logic Purity: Refactored MintingOutputKey to remove stateful caching, ensuring the function is pure and its output is determined solely by its inputs.
  • Documentation: Added release notes for version 0.9.0, documenting the architectural changes and bug fixes.
New Features

🧠 You can now enable Memory (public preview) 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 the 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 counterproductive. 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.

@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 refactors the codebase by splitting several components out of the monolithic tapgarden package into more focused packages: tapnode (for node-side abstractions and mocks), tapreorg (for the re-org watcher), and tapcustody (for the asset custodian). Additionally, it makes MintingOutputKey a pure function by removing its internal cache to ensure it correctly respects different sibling arguments. Feedback on the changes suggests renaming tapcustody/mock.go to mock_test.go to prevent test-only mock code from being compiled into production binaries, and adding missing documentation comments to its exported functions to comply with the repository style guide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread tapcustody/mock_test.go
Comment thread tapcustody/mock_test.go
@jtobin jtobin force-pushed the tapgarden-extraction branch 2 times, most recently from 4c687b7 to a59d6ec Compare July 8, 2026 18:40
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 28966962901

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage decreased (-0.2%) to 36.065%

Details

  • Coverage decreased (-0.2%) from the base build.
  • Patch coverage: 453 uncovered changes across 15 files (62 of 515 lines covered, 12.04%).
  • 75 coverage regressions across 13 files.

Uncovered Changes

Top 10 Files by Coverage Impact Changed Covered %
tapnode/tapnodemock/wallet_anchor.go 152 0 0.0%
tapnode/tapnodemock/key_ring.go 124 0 0.0%
tapnode/tapnodemock/chain_bridge.go 145 25 17.24%
tapreorg/watcher.go 19 5 26.32%
rpcserver/rpcserver.go 9 0 0.0%
log.go 6 0 0.0%
tapcustody/log.go 6 0 0.0%
tapreorg/log.go 6 0 0.0%
tapnode/chain_bridge.go 5 0 0.0%
tapcfg/server.go 3 0 0.0%
Total (21 files) 515 62 12.04%

Coverage Regressions

75 previously-covered lines in 13 files lost coverage.

Top 10 Files by Coverage Loss Lines Losing Coverage Coverage
tappsbt/create.go 30 43.0%
tapgarden/caretaker.go 7 68.39%
address/address.go 6 67.54%
asset/mock.go 5 72.91%
tapgarden/mock.go 5 76.78%
address/mock.go 4 95.11%
asset/asset.go 4 65.88%
tapfreighter/interface.go 4 57.32%
tapchannel/aux_leaf_signer.go 3 43.23%
commitment/tap.go 2 82.23%

Coverage Stats

Coverage Status
Relevant Lines: 129694
Covered Lines: 46774
Line Coverage: 36.06%
Coverage Strength: 2.91 hits per line

💛 - Coveralls

@GeorgeTsagk GeorgeTsagk 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.

lgtm, some optional nits

Comment thread tapgarden/batch.go Outdated
Comment thread rpcserver/rpcserver.go
@github-project-automation github-project-automation Bot moved this from 🆕 New to 👀 In review in Taproot-Assets Project Board Jul 10, 2026
jtobin added 5 commits July 10, 2026 11:22
ChainBridge, WalletAnchor, KeyRing, and GroupFetcher describe tapd's
view of its node-side dependencies (chain backend, wallet, key ring,
group lookups), but they lived in tapgarden/interface.go. They were
consumed by tapfreighter, tapchannel, tapconfig, lndservices,
universe/supplycommit, universe/supplyverifier, and backup -- which
made the tapgarden home a documented accident of authorship rather
than a property of what the package is.

Introduce a tapnode package that houses the four interfaces alone.
Concrete implementations remain in lndservices; the rest of the tree
imports tapnode for the interface only. tapgarden retains the
minting-specific symbols (MintingStore, MintSupplyCommitter, Planter,
BatchState, FundBatchResp, etc.). No behavior change.
The re-org watcher guards proof integrity in the face of chain
re-orgs, which is unrelated to growing seedlings into assets. It
lived in tapgarden only because that was the package that first
happened to need it.

Move tapgarden/re-org_watcher.go to tapreorg/watcher.go, renaming
ReOrgWatcher -> Watcher, ReOrgWatcherConfig -> Config, and
NewReOrgWatcher -> NewWatcher to drop the package-name stutter. The
new package owns its own DefaultTimeout and logger (subsystem
"RORG"). Drop a dead pre-overwrite assignment in
DefaultUpdateCallback while we're here. tapconfig, tapcfg/server.go,
and the root-level log.go are updated for the new symbols.
The Custodian receives assets transferred to this node; the Planter
mints new ones. Keeping them in the same package forced every
consumer that only cared about receipt to import the minting code,
and conflated the two responsibilities at the package boundary.

Hoist the Custodian, its config (renamed Config, dropping the type
stutter), its event surface (AssetReceiveEvent,
AddrImportErrEvent, AddrImportCompleteEvent), its helpers
(AddrMatchesAsset, EventMatchesProof, WaitForAddrImport,
AddrImportStatus), and MockAssetSyncer into a new tapcustody
package. Subsystem CSTD. GenHeaderVerifier, needed by caretaker,
planter, and custodian plus tapfreighter, supplyverifier, rpcserver,
and tapcfg, moves to tapnode alongside the ChainBridge interface it
wraps -- a node-level concern, not a tapgarden one.
MintingOutputKey memoized its result on first call; subsequent calls
silently ignored the sibling argument. The caretaker's
BatchStateCommitted branch was the only caller that exploited this,
passing nil and relying on the Frozen branch having cached the real
sibling. Any path that reached Committed without going through Frozen
first -- a future RBF retry, a partial restart, a refactor -- would
have silently computed and cached the wrong output key.

Drop the cache. MintingBatch loses its memoized mintingPubKey and
taprootAssetScriptRoot fields; MintingOutputKey recomputes from
(BatchKey, RootAssetCommitment, sibling) on every call. The caretaker's
Committed branch now loads the sibling preimage before calling
MintingOutputKey and passes it explicitly; the same preimage is already
used a few lines below for siblingBytes, so this is a reorder rather
than a new I/O cost. The work is a single tapscript hash plus an ECC
tweak -- not expensive enough to justify a memoizing getter that
introduces correctness footguns.
@jtobin jtobin force-pushed the tapgarden-extraction branch from a59d6ec to 3768622 Compare July 10, 2026 13:56
@jtobin jtobin enabled auto-merge July 10, 2026 13:56
@jtobin jtobin added this pull request to the merge queue Jul 10, 2026
Merged via the queue into lightninglabs:main with commit 343c0d9 Jul 10, 2026
86 of 87 checks passed
@github-project-automation github-project-automation Bot moved this from 👀 In review to ✅ Done in Taproot-Assets Project Board Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants